diff --git a/.forgejo/workflows/deps.yml b/.forgejo/workflows/deps.yml new file mode 100644 index 0000000..ffaca53 --- /dev/null +++ b/.forgejo/workflows/deps.yml @@ -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://code.forgejo.org/actions/checkout@v3 + with: + fetch-depth: 0 + - uses: https://code.forgejo.org/actions/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://github.com/YosysHQ/sby.git 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://github.com/Z3Prover/z3.git 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://github.com/YosysHQ/yosys.git deps/yosys + make -C deps/yosys -j"$(nproc)" + - uses: https://code.forgejo.org/actions/cache/save@v3 + if: steps.restore-deps.outputs.cache-hit != 'true' + with: + path: deps + key: ${{ steps.restore-deps.outputs.cache-primary-key }} diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml index 001168f..e83c668 100644 --- a/.forgejo/workflows/test.yml +++ b/.forgejo/workflows/test.yml @@ -3,23 +3,59 @@ on: [push, pull_request] jobs: + deps: + uses: ./.forgejo/workflows/deps.yml test: runs-on: debian-12 - container: - image: git.libre-chip.org/libre-chip/fayalite-deps:latest + needs: deps steps: - - uses: actions/checkout@v3 + - uses: https://code.forgejo.org/actions/checkout@v3 with: fetch-depth: 0 - run: | scripts/check-copyright.sh - - uses: https://git.libre-chip.org/mirrors/rust-cache@v2 + - 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://code.forgejo.org/actions/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://github.com/Swatinem/rust-cache@v2 with: save-if: ${{ github.ref == 'refs/heads/master' }} - run: cargo test - run: cargo build --tests --features=unstable-doc - run: cargo test --doc --features=unstable-doc - run: cargo doc --features=unstable-doc - - run: FAYALITE_TEST_HASHER=always_zero cargo test --test=module --features=unstable-doc,unstable-test-hasher - - run: cargo run --example blinky yosys-nextpnr-xray --platform=arty-a7-100t --nextpnr-xilinx-chipdb-dir /opt/fayalite-deps/nextpnr-xilinx/xilinx --prjxray-db-dir /opt/fayalite-deps/prjxray-db -o target/blinky-out - - run: cargo run --example tx_only_uart yosys-nextpnr-xray --platform=arty-a7-100t --nextpnr-xilinx-chipdb-dir /opt/fayalite-deps/nextpnr-xilinx/xilinx --prjxray-db-dir /opt/fayalite-deps/prjxray-db -o target/tx_only_uart-out diff --git a/Cargo.lock b/Cargo.lock index be5f3bc..23cdc34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,18 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 4 +version = 3 + +[[package]] +name = "ahash" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] [[package]] name = "allocator-api2" @@ -25,9 +37,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" @@ -81,12 +93,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - [[package]] name = "basic-toml" version = "0.1.8" @@ -155,9 +161,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.48" +version = "4.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" dependencies = [ "clap_builder", "clap_derive", @@ -165,9 +171,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.48" +version = "4.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" dependencies = [ "anstream", "anstyle", @@ -175,20 +181,11 @@ dependencies = [ "strsim", ] -[[package]] -name = "clap_complete" -version = "4.5.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75bf0b32ad2e152de789bb635ea4d3078f6b838ad7974143e99b99f45a04af4a" -dependencies = [ - "clap", -] - [[package]] name = "clap_derive" -version = "4.5.47" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" dependencies = [ "heck", "proc-macro2", @@ -198,9 +195,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.5" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "colorchoice" @@ -306,11 +303,9 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" name = "fayalite" version = "0.3.0" dependencies = [ - "base64", "bitvec", "blake3", "clap", - "clap_complete", "ctor", "eyre", "fayalite-proc-macros", @@ -319,7 +314,7 @@ dependencies = [ "jobslot", "num-bigint", "num-traits", - "ordered-float", + "os_pipe", "petgraph", "serde", "serde_json", @@ -370,12 +365,6 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "funty" version = "2.0.0" @@ -394,13 +383,12 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.3" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", - "r-efi", "wasi", ] @@ -412,13 +400,12 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ + "ahash", "allocator-api2", - "equivalent", - "foldhash", ] [[package]] @@ -444,9 +431,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.9.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", @@ -467,23 +454,23 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jobslot" -version = "0.2.23" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58715c67c327da7f1558708348d68c207fd54900c4ae0529e29305d04d795b8c" +checksum = "fe10868679d7a24c2c67d862d0e64a342ce9aef7cdde9ce8019bd35d353d458d" dependencies = [ "cfg-if", "derive_destructure2", "getrandom", "libc", "scopeguard", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] name = "libc" -version = "0.2.176" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "linux-raw-sys" @@ -526,26 +513,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] -name = "ordered-float" -version = "5.1.0" +name = "os_pipe" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" dependencies = [ - "num-traits", - "rand", - "serde", + "libc", + "windows-sys 0.59.0", ] [[package]] name = "petgraph" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a98c6720655620a521dcc722d0ad66cd8afd5d86e34a89ef691c50b7b24de06" +version = "0.6.5" +source = "git+https://github.com/programmerjake/petgraph.git?rev=258ea8071209a924b73fe96f9f87a3b7b45cbc9f#258ea8071209a924b73fe96f9f87a3b7b45cbc9f" dependencies = [ "fixedbitset", - "hashbrown", "indexmap", - "serde", ] [[package]] @@ -576,37 +559,12 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - [[package]] name = "radium" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "rand_core", - "serde", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "serde", -] - [[package]] name = "rustix" version = "0.38.31" @@ -792,21 +750,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" -version = "0.14.7+wasi-0.2.4" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - -[[package]] -name = "wasip2" -version = "1.0.1+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" -dependencies = [ - "wit-bindgen", -] +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "which" @@ -851,12 +797,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - [[package]] name = "windows-sys" version = "0.52.0" @@ -868,11 +808,11 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.61.2" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-link", + "windows-targets", ] [[package]] @@ -945,12 +885,6 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" -[[package]] -name = "wit-bindgen" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" - [[package]] name = "wyz" version = "0.5.1" @@ -959,3 +893,23 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 2380ea7..54de3a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,31 +7,30 @@ members = ["crates/*"] [workspace.package] version = "0.3.0" license = "LGPL-3.0-or-later" -edition = "2024" +edition = "2021" repository = "https://git.libre-chip.org/libre-chip/fayalite" keywords = ["hdl", "hardware", "semiconductors", "firrtl", "fpga"] categories = ["simulation", "development-tools", "compilers"] -rust-version = "1.89.0" +rust-version = "1.82.0" [workspace.dependencies] fayalite-proc-macros = { version = "=0.3.0", path = "crates/fayalite-proc-macros" } fayalite-proc-macros-impl = { version = "=0.3.0", path = "crates/fayalite-proc-macros-impl" } fayalite-visit-gen = { version = "=0.3.0", path = "crates/fayalite-visit-gen" } base16ct = "0.2.0" -base64 = "0.22.1" bitvec = { version = "1.0.1", features = ["serde"] } blake3 = { version = "1.5.4", features = ["serde"] } clap = { version = "4.5.9", features = ["derive", "env", "string"] } -clap_complete = "4.5.58" ctor = "0.2.8" eyre = "0.6.12" -hashbrown = "0.15.2" +hashbrown = "0.14.3" indexmap = { version = "2.5.0", features = ["serde"] } -jobslot = "0.2.23" +jobslot = "0.2.19" num-bigint = "0.4.6" num-traits = "0.2.16" -ordered-float = { version = "5.1.0", features = ["serde"] } -petgraph = "0.8.1" +os_pipe = "1.2.1" +# TODO: switch back to crates.io once petgraph accepts PR #684 and releases a new version +petgraph = { git = "https://github.com/programmerjake/petgraph.git", rev = "258ea8071209a924b73fe96f9f87a3b7b45cbc9f" } prettyplease = "0.2.20" proc-macro2 = "1.0.83" quote = "1.0.36" diff --git a/README.md b/README.md index 18cd78c..438550e 100644 --- a/README.md +++ b/README.md @@ -7,78 +7,3 @@ See Notices.txt for copyright information Fayalite is a library for designing digital hardware -- a hardware description language (HDL) embedded in the Rust programming language. Fayalite's semantics are based on [FIRRTL] as interpreted by [LLVM CIRCT](https://circt.llvm.org/docs/Dialects/FIRRTL/FIRRTLAnnotations/). [FIRRTL]: https://github.com/chipsalliance/firrtl-spec - -# Building the [Blinky example] for the Arty A7 100T on Linux - -[Blinky example]: crates/fayalite/examples/blinky.rs - -This uses the container image containing all the external programs and files that Fayalite needs to build for FPGAs, the sources for the container image are in - -Steps: - -Install podman (or docker). - -Run: -```bash -podman run --rm --security-opt label=disable --volume="$(pwd):$(pwd)" -w="$(pwd)" -it git.libre-chip.org/libre-chip/fayalite-deps:latest cargo run --example blinky yosys-nextpnr-xray --nextpnr-xilinx-chipdb-dir /opt/fayalite-deps/nextpnr-xilinx/xilinx --prjxray-db-dir /opt/fayalite-deps/prjxray-db --platform arty-a7-100t -o target/blinky-out -``` - -To actually program the FPGA, you'll need to install [openFPGALoader] on your host OS: - -[openFPGALoader]: https://github.com/trabucayre/openFPGALoader - -On Debian 12: -```bash -sudo apt update && sudo apt install openfpgaloader -``` - -Then program the FPGA: -```bash -sudo openFPGALoader --board arty_a7_100t target/blinky-out/blinky.bit -``` - -This will program the FPGA but leave the Flash chip unmodified, so the FPGA will revert when the board is power-cycled. - -To program the Flash also, so it stays programmed when power-cycling the board: - -```bash -sudo openFPGALoader --board arty_a7_100t -f target/blinky-out/blinky.bit -``` - -# Building the [Transmit-only UART example] for the Arty A7 100T on Linux - -[Transmit-only UART example]: crates/fayalite/examples/tx_only_uart.rs - -Follow the steps above of building the Blinky example, but replace `blinky` with `tx_only_uart`. - -View the output using [tio](https://github.com/tio/tio) which you can install in Debian using `apt`. - -Find the correct USB device: -```bash -sudo tio --list -``` - -You want the device with a name like (note the `if01`, `if00` is presumably the JTAG port): -`/dev/serial/by-id/usb-Digilent_Digilent_USB_Device_210319B4A51E-if01-port0` - -Connect to the serial port: -```bash -sudo tio -b115200 /dev/serial/by-id/put-your-device-id-here -``` - -You'll see (repeating endlessly): -```text -Hello World from Fayalite!!! -Hello World from Fayalite!!! -Hello World from Fayalite!!! -``` - -Press Ctrl+T then `q` to exit tio. - -# 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). diff --git a/crates/fayalite-proc-macros-impl/src/fold.rs b/crates/fayalite-proc-macros-impl/src/fold.rs index 22e7b82..49cc8c1 100644 --- a/crates/fayalite-proc-macros-impl/src/fold.rs +++ b/crates/fayalite-proc-macros-impl/src/fold.rs @@ -220,7 +220,6 @@ forward_fold!(syn::ExprArray => fold_expr_array); forward_fold!(syn::ExprCall => fold_expr_call); forward_fold!(syn::ExprIf => fold_expr_if); forward_fold!(syn::ExprMatch => fold_expr_match); -forward_fold!(syn::ExprMethodCall => fold_expr_method_call); forward_fold!(syn::ExprPath => fold_expr_path); forward_fold!(syn::ExprRepeat => fold_expr_repeat); forward_fold!(syn::ExprStruct => fold_expr_struct); diff --git a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs index e8dc51b..79326e2 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_bundle.rs @@ -1,22 +1,21 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ - Errors, HdlAttr, PairsIterExt, hdl_type_common::{ - ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedField, ParsedFieldsNamed, ParsedGenerics, - SplitForImpl, TypesParser, WrappedInConst, common_derives, get_target, + common_derives, get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedField, + ParsedFieldsNamed, ParsedGenerics, SplitForImpl, TypesParser, WrappedInConst, }, - kw, + kw, Errors, HdlAttr, PairsIterExt, }; use proc_macro2::TokenStream; -use quote::{ToTokens, format_ident, quote_spanned}; +use quote::{format_ident, quote_spanned, ToTokens}; use syn::{ - AngleBracketedGenericArguments, Attribute, Field, FieldMutability, Fields, FieldsNamed, - GenericParam, Generics, Ident, ItemStruct, Path, Token, Type, Visibility, parse_quote, - parse_quote_spanned, + parse_quote, parse_quote_spanned, punctuated::{Pair, Punctuated}, spanned::Spanned, token::Brace, + AngleBracketedGenericArguments, Attribute, Field, FieldMutability, Fields, FieldsNamed, + GenericParam, Generics, Ident, ItemStruct, Path, Token, Type, Visibility, }; #[derive(Clone, Debug)] @@ -31,9 +30,7 @@ pub(crate) struct ParsedBundle { pub(crate) field_flips: Vec>>, pub(crate) mask_type_ident: Ident, pub(crate) mask_type_match_variant_ident: Ident, - pub(crate) mask_type_sim_value_ident: Ident, pub(crate) match_variant_ident: Ident, - pub(crate) sim_value_ident: Ident, pub(crate) builder_ident: Ident, pub(crate) mask_type_builder_ident: Ident, } @@ -86,12 +83,7 @@ impl ParsedBundle { custom_bounds, no_static: _, no_runtime_generics: _, - cmp_eq: _, - ref get, } = options.body; - if let Some((get, ..)) = get { - errors.error(get, "#[hdl(get(...))] is not allowed on structs"); - } let mut fields = match fields { syn::Fields::Named(fields) => fields, syn::Fields::Unnamed(fields) => { @@ -132,9 +124,7 @@ impl ParsedBundle { field_flips, mask_type_ident: format_ident!("__{}__MaskType", ident), mask_type_match_variant_ident: format_ident!("__{}__MaskType__MatchVariant", ident), - mask_type_sim_value_ident: format_ident!("__{}__MaskType__SimValue", ident), match_variant_ident: format_ident!("__{}__MatchVariant", ident), - sim_value_ident: format_ident!("__{}__SimValue", ident), mask_type_builder_ident: format_ident!("__{}__MaskType__Builder", ident), builder_ident: format_ident!("__{}__Builder", ident), ident, @@ -349,6 +339,7 @@ impl ToTokens for Builder { } })); quote_spanned! {self.ident.span()=> + #[automatically_derived] #[allow(non_camel_case_types, non_snake_case, dead_code)] impl #impl_generics #unfilled_ty #where_clause @@ -435,9 +426,7 @@ impl ToTokens for ParsedBundle { field_flips, mask_type_ident, mask_type_match_variant_ident, - mask_type_sim_value_ident, match_variant_ident, - sim_value_ident, builder_ident, mask_type_builder_ident, } = self; @@ -448,8 +437,6 @@ impl ToTokens for ParsedBundle { custom_bounds: _, no_static, no_runtime_generics, - cmp_eq, - get: _, } = &options.body; let target = get_target(target, ident); let mut item_attrs = attrs.clone(); @@ -534,7 +521,7 @@ impl ToTokens for ParsedBundle { semi_token: None, } .to_tokens(tokens); - let mut mask_type_match_variant_fields = mask_type_fields.clone(); + let mut mask_type_match_variant_fields = mask_type_fields; for Field { ty, .. } in &mut mask_type_match_variant_fields.named { *ty = parse_quote_spanned! {span=> ::fayalite::expr::Expr<#ty> @@ -576,58 +563,6 @@ impl ToTokens for ParsedBundle { semi_token: None, } .to_tokens(tokens); - let mut mask_type_sim_value_fields = mask_type_fields; - for Field { ty, .. } in &mut mask_type_sim_value_fields.named { - *ty = parse_quote_spanned! {span=> - ::fayalite::sim::value::SimValue<#ty> - }; - } - ItemStruct { - attrs: vec![ - parse_quote_spanned! {span=> - #[::fayalite::__std::prelude::v1::derive( - ::fayalite::__std::fmt::Debug, - ::fayalite::__std::clone::Clone, - )] - }, - parse_quote_spanned! {span=> - #[allow(non_camel_case_types, dead_code)] - }, - ], - vis: vis.clone(), - struct_token: *struct_token, - ident: mask_type_sim_value_ident.clone(), - generics: generics.into(), - fields: Fields::Named(mask_type_sim_value_fields), - semi_token: None, - } - .to_tokens(tokens); - let mut sim_value_fields = FieldsNamed::from(fields.clone()); - for Field { ty, .. } in &mut sim_value_fields.named { - *ty = parse_quote_spanned! {span=> - ::fayalite::sim::value::SimValue<#ty> - }; - } - ItemStruct { - attrs: vec![ - parse_quote_spanned! {span=> - #[::fayalite::__std::prelude::v1::derive( - ::fayalite::__std::fmt::Debug, - ::fayalite::__std::clone::Clone, - )] - }, - parse_quote_spanned! {span=> - #[allow(non_camel_case_types, dead_code)] - }, - ], - vis: vis.clone(), - struct_token: *struct_token, - ident: sim_value_ident.clone(), - generics: generics.into(), - fields: Fields::Named(sim_value_fields), - semi_token: None, - } - .to_tokens(tokens); let this_token = Ident::new("__this", span); let fields_token = Ident::new("__fields", span); let self_token = Token![self](span); @@ -678,32 +613,6 @@ impl ToTokens for ParsedBundle { } }, )); - let sim_value_from_opaque_fields = - Vec::from_iter(fields.named().into_iter().map(|field| { - let ident: &Ident = field.ident().as_ref().unwrap(); - quote_spanned! {span=> - #ident: v.field_from_opaque(), - } - })); - let sim_value_clone_from_opaque_fields = - Vec::from_iter(fields.named().into_iter().map(|field| { - let ident: &Ident = field.ident().as_ref().unwrap(); - quote_spanned! {span=> - v.field_clone_from_opaque(&mut value.#ident); - } - })); - let sim_value_to_opaque_fields = Vec::from_iter(fields.named().into_iter().map(|field| { - let ident: &Ident = field.ident().as_ref().unwrap(); - quote_spanned! {span=> - v.field(&value.#ident); - } - })); - let to_sim_value_fields = Vec::from_iter(fields.named().into_iter().map(|field| { - let ident: &Ident = field.ident().as_ref().unwrap(); - quote_spanned! {span=> - #ident: ::fayalite::sim::value::SimValue::ty(&self.#ident), - } - })); let fields_len = fields.named().into_iter().len(); quote_spanned! {span=> #[automatically_derived] @@ -712,7 +621,6 @@ impl ToTokens for ParsedBundle { { type BaseType = ::fayalite::bundle::Bundle; type MaskType = #mask_type_ident #type_generics; - type SimValue = #mask_type_sim_value_ident #type_generics; type MatchVariant = #mask_type_match_variant_ident #type_generics; type MatchActiveScope = (); type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope< @@ -750,35 +658,6 @@ impl ToTokens for ParsedBundle { fn source_location() -> ::fayalite::source_location::SourceLocation { ::fayalite::source_location::SourceLocation::caller() } - fn sim_value_from_opaque( - &self, - opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, - ) -> ::SimValue { - #![allow(unused_mut, unused_variables)] - let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque); - #mask_type_sim_value_ident { - #(#sim_value_from_opaque_fields)* - } - } - fn sim_value_clone_from_opaque( - &self, - value: &mut ::SimValue, - opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, - ) { - #![allow(unused_mut, unused_variables)] - let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque); - #(#sim_value_clone_from_opaque_fields)* - } - fn sim_value_to_opaque<'__w>( - &self, - value: &::SimValue, - writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>, - ) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> { - #![allow(unused_mut, unused_variables)] - let mut v = ::fayalite::bundle::BundleSimValueToOpaque::new(*self, writer); - #(#sim_value_to_opaque_fields)* - v.finish() - } } #[automatically_derived] impl #impl_generics ::fayalite::bundle::BundleType for #mask_type_ident #type_generics @@ -810,57 +689,11 @@ impl ToTokens for ParsedBundle { } } #[automatically_derived] - impl #impl_generics ::fayalite::sim::value::ToSimValue for #mask_type_sim_value_ident #type_generics - #where_clause - { - type Type = #mask_type_ident #type_generics; - - fn to_sim_value( - &self, - ) -> ::fayalite::sim::value::SimValue< - ::Type, - > { - let ty = #mask_type_ident { - #(#to_sim_value_fields)* - }; - ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) - } - fn into_sim_value( - self, - ) -> ::fayalite::sim::value::SimValue< - ::Type, - > { - let ty = #mask_type_ident { - #(#to_sim_value_fields)* - }; - ::fayalite::sim::value::SimValue::from_value(ty, self) - } - } - #[automatically_derived] - impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#mask_type_ident #type_generics> - for #mask_type_sim_value_ident #type_generics - #where_clause - { - fn to_sim_value_with_type( - &self, - ty: #mask_type_ident #type_generics, - ) -> ::fayalite::sim::value::SimValue<#mask_type_ident #type_generics> { - ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) - } - fn into_sim_value_with_type( - self, - ty: #mask_type_ident #type_generics, - ) -> ::fayalite::sim::value::SimValue<#mask_type_ident #type_generics> { - ::fayalite::sim::value::SimValue::from_value(ty, self) - } - } - #[automatically_derived] impl #impl_generics ::fayalite::ty::Type for #target #type_generics #where_clause { type BaseType = ::fayalite::bundle::Bundle; type MaskType = #mask_type_ident #type_generics; - type SimValue = #sim_value_ident #type_generics; type MatchVariant = #match_variant_ident #type_generics; type MatchActiveScope = (); type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope< @@ -900,35 +733,6 @@ impl ToTokens for ParsedBundle { fn source_location() -> ::fayalite::source_location::SourceLocation { ::fayalite::source_location::SourceLocation::caller() } - fn sim_value_from_opaque( - &self, - opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, - ) -> ::SimValue { - #![allow(unused_mut, unused_variables)] - let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque); - #sim_value_ident { - #(#sim_value_from_opaque_fields)* - } - } - fn sim_value_clone_from_opaque( - &self, - value: &mut ::SimValue, - opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, - ) { - #![allow(unused_mut, unused_variables)] - let mut v = ::fayalite::bundle::BundleSimValueFromOpaque::new(*self, opaque); - #(#sim_value_clone_from_opaque_fields)* - } - fn sim_value_to_opaque<'__w>( - &self, - value: &::SimValue, - writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>, - ) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> { - #![allow(unused_mut, unused_variables)] - let mut v = ::fayalite::bundle::BundleSimValueToOpaque::new(*self, writer); - #(#sim_value_to_opaque_fields)* - v.finish() - } } #[automatically_derived] impl #impl_generics ::fayalite::bundle::BundleType for #target #type_generics @@ -959,144 +763,8 @@ impl ToTokens for ParsedBundle { ::fayalite::intern::Interned::into_inner(::fayalite::intern::Intern::intern_sized(__retval)) } } - #[automatically_derived] - impl #impl_generics ::fayalite::sim::value::ToSimValue for #sim_value_ident #type_generics - #where_clause - { - type Type = #target #type_generics; - - fn to_sim_value( - &self, - ) -> ::fayalite::sim::value::SimValue< - ::Type, - > { - let ty = #target { - #(#to_sim_value_fields)* - }; - ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) - } - fn into_sim_value( - self, - ) -> ::fayalite::sim::value::SimValue< - ::Type, - > { - let ty = #target { - #(#to_sim_value_fields)* - }; - ::fayalite::sim::value::SimValue::from_value(ty, self) - } - } - #[automatically_derived] - impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#target #type_generics> - for #sim_value_ident #type_generics - #where_clause - { - fn to_sim_value_with_type( - &self, - ty: #target #type_generics, - ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { - ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) - } - fn into_sim_value_with_type( - self, - ty: #target #type_generics, - ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { - ::fayalite::sim::value::SimValue::from_value(ty, self) - } - } } .to_tokens(tokens); - if let Some((cmp_eq,)) = cmp_eq { - let mut expr_where_clause = - Generics::from(generics) - .where_clause - .unwrap_or_else(|| syn::WhereClause { - where_token: Token![where](span), - predicates: Punctuated::new(), - }); - let mut sim_value_where_clause = expr_where_clause.clone(); - let mut fields_sim_value_eq = vec![]; - let mut fields_cmp_eq = vec![]; - let mut fields_cmp_ne = vec![]; - for field in fields.named() { - let field_ident = field.ident(); - let field_ty = field.ty(); - expr_where_clause - .predicates - .push(parse_quote_spanned! {cmp_eq.span=> - #field_ty: ::fayalite::expr::ops::ExprPartialEq<#field_ty> - }); - sim_value_where_clause - .predicates - .push(parse_quote_spanned! {cmp_eq.span=> - #field_ty: ::fayalite::sim::value::SimValuePartialEq<#field_ty> - }); - fields_sim_value_eq.push(quote_spanned! {span=> - ::fayalite::sim::value::SimValuePartialEq::sim_value_eq(&__lhs.#field_ident, &__rhs.#field_ident) - }); - fields_cmp_eq.push(quote_spanned! {span=> - ::fayalite::expr::ops::ExprPartialEq::cmp_eq(__lhs.#field_ident, __rhs.#field_ident) - }); - fields_cmp_ne.push(quote_spanned! {span=> - ::fayalite::expr::ops::ExprPartialEq::cmp_ne(__lhs.#field_ident, __rhs.#field_ident) - }); - } - let sim_value_eq_body; - let cmp_eq_body; - let cmp_ne_body; - if fields_len == 0 { - sim_value_eq_body = quote_spanned! {span=> - true - }; - cmp_eq_body = quote_spanned! {span=> - ::fayalite::expr::ToExpr::to_expr(&true) - }; - cmp_ne_body = quote_spanned! {span=> - ::fayalite::expr::ToExpr::to_expr(&false) - }; - } else { - sim_value_eq_body = quote_spanned! {span=> - #(#fields_sim_value_eq)&&* - }; - cmp_eq_body = quote_spanned! {span=> - #(#fields_cmp_eq)&* - }; - cmp_ne_body = quote_spanned! {span=> - #(#fields_cmp_ne)|* - }; - }; - quote_spanned! {span=> - #[automatically_derived] - impl #impl_generics ::fayalite::expr::ops::ExprPartialEq for #target #type_generics - #expr_where_clause - { - fn cmp_eq( - __lhs: ::fayalite::expr::Expr, - __rhs: ::fayalite::expr::Expr, - ) -> ::fayalite::expr::Expr<::fayalite::int::Bool> { - #cmp_eq_body - } - fn cmp_ne( - __lhs: ::fayalite::expr::Expr, - __rhs: ::fayalite::expr::Expr, - ) -> ::fayalite::expr::Expr<::fayalite::int::Bool> { - #cmp_ne_body - } - } - #[automatically_derived] - impl #impl_generics ::fayalite::sim::value::SimValuePartialEq for #target #type_generics - #sim_value_where_clause - { - fn sim_value_eq( - __lhs: &::fayalite::sim::value::SimValue, - __rhs: &::fayalite::sim::value::SimValue, - ) -> bool { - #sim_value_eq_body - } - } - } - .to_tokens(tokens); - } if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) { let static_generics = generics.clone().for_static_type(); let (static_impl_generics, static_type_generics, static_where_clause) = @@ -1132,14 +800,6 @@ impl ToTokens for ParsedBundle { } })); quote_spanned! {span=> - #[automatically_derived] - impl #static_impl_generics ::fayalite::__std::default::Default for #mask_type_ident #static_type_generics - #static_where_clause - { - fn default() -> Self { - ::TYPE - } - } #[automatically_derived] impl #static_impl_generics ::fayalite::ty::StaticType for #mask_type_ident #static_type_generics #static_where_clause @@ -1162,15 +822,6 @@ impl ToTokens for ParsedBundle { }; } #[automatically_derived] - impl #static_impl_generics ::fayalite::__std::default::Default - for #target #static_type_generics - #static_where_clause - { - fn default() -> Self { - ::TYPE - } - } - #[automatically_derived] impl #static_impl_generics ::fayalite::ty::StaticType for #target #static_type_generics #static_where_clause { diff --git a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs index 885cf87..1d16177 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_enum.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_enum.rs @@ -1,20 +1,20 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ - Errors, HdlAttr, PairsIterExt, hdl_type_common::{ - ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType, SplitForImpl, - TypesParser, WrappedInConst, common_derives, get_target, + common_derives, get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, + ParsedType, SplitForImpl, TypesParser, WrappedInConst, }, - kw, + kw, Errors, HdlAttr, PairsIterExt, }; use proc_macro2::TokenStream; -use quote::{ToTokens, format_ident, quote_spanned}; +use quote::{format_ident, quote_spanned, ToTokens}; use syn::{ - Attribute, Field, FieldMutability, Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, - ItemEnum, ItemStruct, Token, Type, Variant, Visibility, parse_quote_spanned, + parse_quote_spanned, punctuated::{Pair, Punctuated}, token::{Brace, Paren}, + Attribute, Field, FieldMutability, Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, + ItemEnum, ItemStruct, Token, Type, Variant, Visibility, }; crate::options! { @@ -129,9 +129,6 @@ pub(crate) struct ParsedEnum { pub(crate) brace_token: Brace, pub(crate) variants: Punctuated, pub(crate) match_variant_ident: Ident, - pub(crate) sim_value_ident: Ident, - pub(crate) sim_builder_ident: Ident, - pub(crate) sim_builder_ty_field_ident: Ident, } impl ParsedEnum { @@ -158,15 +155,7 @@ impl ParsedEnum { custom_bounds, no_static: _, no_runtime_generics: _, - cmp_eq, - ref get, } = options.body; - if let Some((cmp_eq,)) = cmp_eq { - errors.error(cmp_eq, "#[hdl(cmp_eq)] is not yet implemented for enums"); - } - if let Some((get, ..)) = get { - errors.error(get, "#[hdl(get(...))] is not allowed on enums"); - } attrs.retain(|attr| { if attr.path().is_ident("repr") { errors.error(attr, "#[repr] is not supported on #[hdl] enums"); @@ -197,9 +186,6 @@ impl ParsedEnum { brace_token, variants, match_variant_ident: format_ident!("__{}__MatchVariant", ident), - sim_value_ident: format_ident!("__{}__SimValue", ident), - sim_builder_ident: format_ident!("__{}__SimBuilder", ident), - sim_builder_ty_field_ident: format_ident!("__ty", span = ident.span()), ident, }) } @@ -217,9 +203,6 @@ impl ToTokens for ParsedEnum { brace_token, variants, match_variant_ident, - sim_value_ident, - sim_builder_ident, - sim_builder_ty_field_ident, } = self; let span = ident.span(); let ItemOptions { @@ -228,8 +211,6 @@ impl ToTokens for ParsedEnum { custom_bounds: _, no_static, no_runtime_generics, - cmp_eq: _, // TODO: implement cmp_eq for enums - get: _, } = &options.body; let target = get_target(target, ident); let mut struct_attrs = attrs.clone(); @@ -423,137 +404,11 @@ impl ToTokens for ParsedEnum { )), } .to_tokens(tokens); - let mut struct_attrs = attrs.clone(); - struct_attrs.push(parse_quote_spanned! {span=> - #[allow(dead_code, non_camel_case_types)] - }); - ItemStruct { - attrs: struct_attrs, - vis: vis.clone(), - struct_token: Token![struct](enum_token.span), - ident: sim_builder_ident.clone(), - generics: generics.into(), - fields: FieldsNamed { - brace_token: *brace_token, - named: Punctuated::from_iter([Field { - attrs: vec![], - vis: Visibility::Inherited, - mutability: FieldMutability::None, - ident: Some(sim_builder_ty_field_ident.clone()), - colon_token: Some(Token![:](span)), - ty: parse_quote_spanned! {span=> - #target #type_generics - }, - }]), - } - .into(), - semi_token: None, - } - .to_tokens(tokens); - let mut enum_attrs = attrs.clone(); - enum_attrs.push(parse_quote_spanned! {span=> - #[::fayalite::__std::prelude::v1::derive( - ::fayalite::__std::fmt::Debug, - ::fayalite::__std::clone::Clone, - )] - }); - enum_attrs.push(parse_quote_spanned! {span=> - #[allow(dead_code, non_camel_case_types)] - }); - let sim_value_has_unknown_variant = !variants.len().is_power_of_two(); - let sim_value_unknown_variant_name = sim_value_has_unknown_variant.then(|| { - let mut name = String::new(); - let unknown = "Unknown"; - loop { - let orig_len = name.len(); - name.push_str(unknown); - if variants.iter().all(|v| v.ident != name) { - break Ident::new(&name, span); - } - name.truncate(orig_len); - name.push('_'); - } - }); - let sim_value_unknown_variant = - sim_value_unknown_variant_name - .as_ref() - .map(|unknown_variant_name| { - Pair::End(parse_quote_spanned! {span=> - #unknown_variant_name(::fayalite::enum_::UnknownVariantSimValue) - }) - }); - ItemEnum { - attrs: enum_attrs, - vis: vis.clone(), - enum_token: *enum_token, - ident: sim_value_ident.clone(), - generics: generics.into(), - brace_token: *brace_token, - variants: Punctuated::from_iter( - variants - .pairs() - .map_pair_value_ref( - |ParsedVariant { - attrs, - options: _, - ident, - field, - }| Variant { - attrs: attrs.clone(), - ident: ident.clone(), - fields: match field { - Some(ParsedVariantField { - paren_token, - attrs, - options: _, - ty, - comma_token, - }) => Fields::Unnamed(FieldsUnnamed { - paren_token: *paren_token, - unnamed: Punctuated::from_iter([ - Pair::new( - Field { - attrs: attrs.clone(), - vis: Visibility::Inherited, - mutability: FieldMutability::None, - ident: None, - colon_token: None, - ty: parse_quote_spanned! {span=> - ::fayalite::sim::value::SimValue<#ty> - }, - }, - Some(comma_token.unwrap_or(Token![,](ident.span()))), - ), - Pair::new( - Field { - attrs: vec![], - vis: Visibility::Inherited, - mutability: FieldMutability::None, - ident: None, - colon_token: None, - ty: parse_quote_spanned! {span=> - ::fayalite::enum_::EnumPaddingSimValue - }, - }, - None, - ), - ]), - }), - None => Fields::Unnamed(parse_quote_spanned! {span=> - (::fayalite::enum_::EnumPaddingSimValue) - }), - }, - discriminant: None, - }, - ) - .chain(sim_value_unknown_variant), - ), - } - .to_tokens(tokens); let self_token = Token![self](span); for (index, ParsedVariant { ident, field, .. }) in variants.iter().enumerate() { if let Some(ParsedVariantField { ty, .. }) = field { quote_spanned! {span=> + #[automatically_derived] impl #impl_generics #target #type_generics #where_clause { @@ -575,27 +430,10 @@ impl ToTokens for ParsedEnum { ) } } - impl #impl_generics #sim_builder_ident #type_generics - #where_clause - { - #[allow(non_snake_case, dead_code)] - #vis fn #ident<__V: ::fayalite::sim::value::ToSimValueWithType<#ty>>( - #self_token, - v: __V, - ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { - let v = ::fayalite::sim::value::ToSimValueWithType::into_sim_value_with_type( - v, - #self_token.#sim_builder_ty_field_ident.#ident, - ); - ::fayalite::sim::value::SimValue::from_value( - #self_token.#sim_builder_ty_field_ident, - #sim_value_ident::#ident(v, ::fayalite::enum_::EnumPaddingSimValue::new()), - ) - } - } } } else { quote_spanned! {span=> + #[automatically_derived] impl #impl_generics #target #type_generics #where_clause { @@ -610,17 +448,6 @@ impl ToTokens for ParsedEnum { ) } } - impl #impl_generics #sim_builder_ident #type_generics - #where_clause - { - #[allow(non_snake_case, dead_code)] - #vis fn #ident(#self_token) -> ::fayalite::sim::value::SimValue<#target #type_generics> { - ::fayalite::sim::value::SimValue::from_value( - #self_token.#sim_builder_ty_field_ident, - #sim_value_ident::#ident(::fayalite::enum_::EnumPaddingSimValue::new()), - ) - } - } } } .to_tokens(tokens); @@ -702,142 +529,6 @@ impl ToTokens for ParsedEnum { } }, )); - let sim_value_from_opaque_unknown_match_arm = if let Some(sim_value_unknown_variant_name) = - &sim_value_unknown_variant_name - { - quote_spanned! {span=> - _ => #sim_value_ident::#sim_value_unknown_variant_name(v.unknown_variant_from_opaque()), - } - } else { - quote_spanned! {span=> - _ => ::fayalite::__std::unreachable!(), - } - }; - let sim_value_from_opaque_match_arms = Vec::from_iter( - variants - .iter() - .enumerate() - .map( - |( - index, - ParsedVariant { - attrs: _, - options: _, - ident, - field, - }, - )| { - if let Some(_) = field { - quote_spanned! {span=> - #index => { - let (field, padding) = v.variant_with_field_from_opaque(); - #sim_value_ident::#ident(field, padding) - } - } - } else { - quote_spanned! {span=> - #index => #sim_value_ident::#ident( - v.variant_no_field_from_opaque(), - ), - } - } - }, - ) - .chain([sim_value_from_opaque_unknown_match_arm]), - ); - let sim_value_clone_from_opaque_unknown_match_arm = - if let Some(sim_value_unknown_variant_name) = &sim_value_unknown_variant_name { - quote_spanned! {span=> - _ => if let #sim_value_ident::#sim_value_unknown_variant_name(value) = value { - v.unknown_variant_clone_from_opaque(value); - } else { - *value = #sim_value_ident::#sim_value_unknown_variant_name( - v.unknown_variant_from_opaque(), - ); - }, - } - } else { - quote_spanned! {span=> - _ => ::fayalite::__std::unreachable!(), - } - }; - let sim_value_clone_from_opaque_match_arms = Vec::from_iter( - variants - .iter() - .enumerate() - .map( - |( - index, - ParsedVariant { - attrs: _, - options: _, - ident, - field, - }, - )| { - if let Some(_) = field { - quote_spanned! {span=> - #index => if let #sim_value_ident::#ident(field, padding) = value { - v.variant_with_field_clone_from_opaque(field, padding); - } else { - let (field, padding) = v.variant_with_field_from_opaque(); - *value = #sim_value_ident::#ident(field, padding); - }, - } - } else { - quote_spanned! {span=> - #index => if let #sim_value_ident::#ident(padding) = value { - v.variant_no_field_clone_from_opaque(padding); - } else { - *value = #sim_value_ident::#ident( - v.variant_no_field_from_opaque(), - ); - }, - } - } - }, - ) - .chain([sim_value_clone_from_opaque_unknown_match_arm]), - ); - let sim_value_to_opaque_match_arms = Vec::from_iter( - variants - .iter() - .enumerate() - .map( - |( - index, - ParsedVariant { - attrs: _, - options: _, - ident, - field, - }, - )| { - if let Some(_) = field { - quote_spanned! {span=> - #sim_value_ident::#ident(field, padding) => { - v.variant_with_field_to_opaque(#index, field, padding) - } - } - } else { - quote_spanned! {span=> - #sim_value_ident::#ident(padding) => { - v.variant_no_field_to_opaque(#index, padding) - } - } - } - }, - ) - .chain(sim_value_unknown_variant_name.as_ref().map( - |sim_value_unknown_variant_name| { - quote_spanned! {span=> - #sim_value_ident::#sim_value_unknown_variant_name(value) => { - v.unknown_variant_to_opaque(value) - } - } - }, - )), - ); let variants_len = variants.len(); quote_spanned! {span=> #[automatically_derived] @@ -846,7 +537,6 @@ impl ToTokens for ParsedEnum { { type BaseType = ::fayalite::enum_::Enum; type MaskType = ::fayalite::int::Bool; - type SimValue = #sim_value_ident #type_generics; type MatchVariant = #match_variant_ident #type_generics; type MatchActiveScope = ::fayalite::module::Scope; type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope; @@ -879,41 +569,11 @@ impl ToTokens for ParsedEnum { fn source_location() -> ::fayalite::source_location::SourceLocation { ::fayalite::source_location::SourceLocation::caller() } - fn sim_value_from_opaque( - &self, - opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, - ) -> ::SimValue { - let v = ::fayalite::enum_::EnumSimValueFromOpaque::new(*self, opaque); - match v.discriminant() { - #(#sim_value_from_opaque_match_arms)* - } - } - fn sim_value_clone_from_opaque( - &self, - value: &mut ::SimValue, - opaque: ::fayalite::ty::OpaqueSimValueSlice<'_>, - ) { - let v = ::fayalite::enum_::EnumSimValueFromOpaque::new(*self, opaque); - match v.discriminant() { - #(#sim_value_clone_from_opaque_match_arms)* - } - } - fn sim_value_to_opaque<'__w>( - &self, - value: &::SimValue, - writer: ::fayalite::ty::OpaqueSimValueWriter<'__w>, - ) -> ::fayalite::ty::OpaqueSimValueWritten<'__w> { - let v = ::fayalite::enum_::EnumSimValueToOpaque::new(*self, writer); - match value { - #(#sim_value_to_opaque_match_arms)* - } - } } #[automatically_derived] impl #impl_generics ::fayalite::enum_::EnumType for #target #type_generics #where_clause { - type SimBuilder = #sim_builder_ident #type_generics; fn match_activate_scope( v: ::MatchVariantAndInactiveScope, ) -> (::MatchVariant, ::MatchActiveScope) { @@ -932,33 +592,6 @@ impl ToTokens for ParsedEnum { ][..]) } } - #[automatically_derived] - impl #impl_generics ::fayalite::sim::value::ToSimValueWithType<#target #type_generics> - for #sim_value_ident #type_generics - #where_clause - { - fn to_sim_value_with_type( - &self, - ty: #target #type_generics, - ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { - ::fayalite::sim::value::SimValue::from_value(ty, ::fayalite::__std::clone::Clone::clone(self)) - } - fn into_sim_value_with_type( - self, - ty: #target #type_generics, - ) -> ::fayalite::sim::value::SimValue<#target #type_generics> { - ::fayalite::sim::value::SimValue::from_value(ty, self) - } - } - #[automatically_derived] - impl #impl_generics ::fayalite::__std::convert::From<#target #type_generics> - for #sim_builder_ident #type_generics - #where_clause - { - fn from(#sim_builder_ty_field_ident: #target #type_generics) -> Self { - Self { #sim_builder_ty_field_ident } - } - } } .to_tokens(tokens); if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) { @@ -996,15 +629,6 @@ impl ToTokens for ParsedEnum { } })); quote_spanned! {span=> - #[automatically_derived] - impl #static_impl_generics ::fayalite::__std::default::Default - for #target #static_type_generics - #static_where_clause - { - fn default() -> Self { - ::TYPE - } - } #[automatically_derived] impl #static_impl_generics ::fayalite::ty::StaticType for #target #static_type_generics @@ -1023,34 +647,6 @@ impl ToTokens for ParsedEnum { const MASK_TYPE_PROPERTIES: ::fayalite::ty::TypeProperties = <::fayalite::int::Bool as ::fayalite::ty::StaticType>::TYPE_PROPERTIES; } - #[automatically_derived] - impl #static_impl_generics ::fayalite::sim::value::ToSimValue - for #sim_value_ident #static_type_generics - #static_where_clause - { - type Type = #target #static_type_generics; - - fn to_sim_value( - &self, - ) -> ::fayalite::sim::value::SimValue< - ::Type, - > { - ::fayalite::sim::value::SimValue::from_value( - ::fayalite::ty::StaticType::TYPE, - ::fayalite::__std::clone::Clone::clone(self), - ) - } - fn into_sim_value( - self, - ) -> ::fayalite::sim::value::SimValue< - ::Type, - > { - ::fayalite::sim::value::SimValue::from_value( - ::fayalite::ty::StaticType::TYPE, - self, - ) - } - } } .to_tokens(tokens); } diff --git a/crates/fayalite-proc-macros-impl/src/hdl_type_alias.rs b/crates/fayalite-proc-macros-impl/src/hdl_type_alias.rs index 0fa2222..e5d5f7b 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_type_alias.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_type_alias.rs @@ -1,266 +1,30 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ - Errors, HdlAttr, hdl_type_common::{ - ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType, - PhantomConstGetBound, TypesParser, WrappedInConst, common_derives, get_target, known_items, + get_target, ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType, + TypesParser, }, - kw, + kw, Errors, HdlAttr, }; use proc_macro2::TokenStream; -use quote::{ToTokens, format_ident, quote_spanned}; -use syn::{ - Attribute, Expr, Fields, GenericParam, Generics, Ident, ItemStruct, ItemType, Token, Type, - TypeGroup, TypeParam, TypeParen, Visibility, parse_quote_spanned, punctuated::Pair, - token::Paren, -}; +use quote::ToTokens; +use syn::{parse_quote_spanned, Attribute, Generics, Ident, ItemType, Token, Type, Visibility}; #[derive(Clone, Debug)] -pub(crate) struct PhantomConstAccessorTypeParam { - attrs: Vec, - ident: Ident, - colon_token: Token![:], - phantom_const_get_bound: PhantomConstGetBound, - plus_token: Option, -} - -impl From for TypeParam { - fn from(value: PhantomConstAccessorTypeParam) -> Self { - let PhantomConstAccessorTypeParam { - attrs, - ident, - colon_token, - phantom_const_get_bound, - plus_token, - } = value; - TypeParam { - attrs, - ident, - colon_token: Some(colon_token), - bounds: FromIterator::from_iter([Pair::new( - phantom_const_get_bound.into(), - plus_token, - )]), - eq_token: None, - default: None, - } - } -} - -impl From for GenericParam { - fn from(value: PhantomConstAccessorTypeParam) -> Self { - TypeParam::from(value).into() - } -} - -impl PhantomConstAccessorTypeParam { - fn parse_opt(generic_param: GenericParam) -> Option { - let GenericParam::Type(TypeParam { - attrs, - ident, - colon_token, - bounds, - eq_token: None, - default: None, - }) = generic_param - else { - return None; - }; - let colon_token = colon_token.unwrap_or(Token![:](ident.span())); - let mut bounds = bounds.into_pairs(); - let (bound, plus_token) = bounds.next()?.into_tuple(); - let phantom_const_get_bound = PhantomConstGetBound::parse_type_param_bound(bound) - .ok()? - .ok()?; - let None = bounds.next() else { - return None; - }; - Some(Self { - attrs, - ident, - colon_token, - phantom_const_get_bound, - plus_token, - }) - } -} - -#[derive(Clone, Debug)] -pub(crate) struct PhantomConstAccessorGenerics { - lt_token: Token![<], - type_param: PhantomConstAccessorTypeParam, - comma_token: Option, - gt_token: Token![>], -} - -impl From for Generics { - fn from(value: PhantomConstAccessorGenerics) -> Self { - let PhantomConstAccessorGenerics { - lt_token, - type_param, - comma_token, - gt_token, - } = value; - Generics { - lt_token: Some(lt_token), - params: FromIterator::from_iter([Pair::new(type_param.into(), comma_token)]), - gt_token: Some(gt_token), - where_clause: None, - } - } -} - -impl<'a> From<&'a PhantomConstAccessorGenerics> for Generics { - fn from(value: &'a PhantomConstAccessorGenerics) -> Self { - value.clone().into() - } -} - -impl PhantomConstAccessorGenerics { - fn parse_opt(generics: Generics) -> Option { - let Generics { - lt_token, - params, - gt_token, - where_clause: None, - } = generics - else { - return None; - }; - let mut params = params.into_pairs(); - let (generic_param, comma_token) = params.next()?.into_tuple(); - let type_param = PhantomConstAccessorTypeParam::parse_opt(generic_param)?; - let span = type_param.ident.span(); - let lt_token = lt_token.unwrap_or(Token![<](span)); - let gt_token = gt_token.unwrap_or(Token![>](span)); - let None = params.next() else { - return None; - }; - Some(Self { - lt_token, - type_param, - comma_token, - gt_token, - }) - } -} - -#[derive(Clone, Debug)] -pub(crate) enum ParsedTypeAlias { - TypeAlias { - attrs: Vec, - options: HdlAttr, - vis: Visibility, - type_token: Token![type], - ident: Ident, - generics: MaybeParsed, - eq_token: Token![=], - ty: MaybeParsed, - semi_token: Token![;], - }, - PhantomConstAccessor { - attrs: Vec, - options: HdlAttr, - get: (kw::get, Paren, Expr), - vis: Visibility, - type_token: Token![type], - ident: Ident, - generics: PhantomConstAccessorGenerics, - eq_token: Token![=], - ty: Type, - ty_is_dyn_size: Option, - semi_token: Token![;], - }, +pub(crate) struct ParsedTypeAlias { + pub(crate) attrs: Vec, + pub(crate) options: HdlAttr, + pub(crate) vis: Visibility, + pub(crate) type_token: Token![type], + pub(crate) ident: Ident, + pub(crate) generics: MaybeParsed, + pub(crate) eq_token: Token![=], + pub(crate) ty: MaybeParsed, + pub(crate) semi_token: Token![;], } impl ParsedTypeAlias { - fn ty_is_dyn_size(ty: &Type) -> Option { - match ty { - Type::Group(TypeGroup { - group_token: _, - elem, - }) => Self::ty_is_dyn_size(elem), - Type::Paren(TypeParen { - paren_token: _, - elem, - }) => Self::ty_is_dyn_size(elem), - Type::Path(syn::TypePath { qself: None, path }) => { - known_items::DynSize::parse_path(path.clone()).ok() - } - _ => None, - } - } - fn parse_phantom_const_accessor( - item: ItemType, - mut errors: Errors, - options: HdlAttr, - get: (kw::get, Paren, Expr), - ) -> syn::Result { - let ItemType { - attrs, - vis, - type_token, - ident, - generics, - eq_token, - ty, - semi_token, - } = item; - let ItemOptions { - outline_generated: _, - ref target, - custom_bounds, - no_static, - no_runtime_generics, - cmp_eq, - get: _, - } = options.body; - if let Some((no_static,)) = no_static { - errors.error(no_static, "no_static is not valid on type aliases"); - } - if let Some((target, ..)) = target { - errors.error( - target, - "target is not implemented on PhantomConstGet type aliases", - ); - } - if let Some((no_runtime_generics,)) = no_runtime_generics { - errors.error( - no_runtime_generics, - "no_runtime_generics is not implemented on PhantomConstGet type aliases", - ); - } - if let Some((cmp_eq,)) = cmp_eq { - errors.error(cmp_eq, "cmp_eq is not valid on type aliases"); - } - if let Some((custom_bounds,)) = custom_bounds { - errors.error( - custom_bounds, - "custom_bounds is not implemented on PhantomConstGet type aliases", - ); - } - let Some(generics) = PhantomConstAccessorGenerics::parse_opt(generics) else { - errors.error(ident, "#[hdl(get(...))] type alias must be of the form:\ntype MyTypeGetter> = RetType;"); - errors.finish()?; - unreachable!(); - }; - errors.finish()?; - let ty_is_dyn_size = Self::ty_is_dyn_size(&ty); - Ok(Self::PhantomConstAccessor { - attrs, - options, - get, - vis, - type_token, - ident, - generics, - eq_token, - ty: *ty, - ty_is_dyn_size, - semi_token, - }) - } fn parse(item: ItemType) -> syn::Result { let ItemType { mut attrs, @@ -285,32 +49,10 @@ impl ParsedTypeAlias { custom_bounds, no_static, no_runtime_generics: _, - cmp_eq, - ref mut get, } = options.body; - if let Some(get) = get.take() { - return Self::parse_phantom_const_accessor( - ItemType { - attrs, - vis, - type_token, - ident, - generics, - eq_token, - ty, - semi_token, - }, - errors, - options, - get, - ); - } if let Some((no_static,)) = no_static { errors.error(no_static, "no_static is not valid on type aliases"); } - if let Some((cmp_eq,)) = cmp_eq { - errors.error(cmp_eq, "cmp_eq is not valid on type aliases"); - } let generics = if custom_bounds.is_some() { MaybeParsed::Unrecognized(generics) } else if let Some(generics) = errors.ok(ParsedGenerics::parse(&mut generics)) { @@ -320,7 +62,7 @@ impl ParsedTypeAlias { }; let ty = TypesParser::maybe_run(generics.as_ref(), *ty, &mut errors); errors.finish()?; - Ok(Self::TypeAlias { + Ok(Self { attrs, options, vis, @@ -336,155 +78,53 @@ impl ParsedTypeAlias { impl ToTokens for ParsedTypeAlias { fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - Self::TypeAlias { - attrs, - options, - vis, - type_token, - ident, - generics, - eq_token, - ty, - semi_token, - } => { - let ItemOptions { - outline_generated: _, - target, - custom_bounds: _, - no_static: _, - no_runtime_generics, - cmp_eq: _, - get: _, - } = &options.body; - let target = get_target(target, ident); - let mut type_attrs = attrs.clone(); - type_attrs.push(parse_quote_spanned! {ident.span()=> - #[allow(type_alias_bounds)] - }); - ItemType { - attrs: type_attrs, - vis: vis.clone(), - type_token: *type_token, - ident: ident.clone(), - generics: generics.into(), - eq_token: *eq_token, - ty: Box::new(ty.clone().into()), - semi_token: *semi_token, - } - .to_tokens(tokens); - if let (MaybeParsed::Parsed(generics), MaybeParsed::Parsed(ty), None) = - (generics, ty, no_runtime_generics) - { - generics.make_runtime_generics(tokens, vis, ident, &target, |context| { - ty.make_hdl_type_expr(context) - }) - } - } - Self::PhantomConstAccessor { - attrs, - options, - get: (_get_kw, _get_paren, get_expr), - vis, - type_token, - ident, - generics, - eq_token, - ty, - ty_is_dyn_size, - semi_token, - } => { - let ItemOptions { - outline_generated: _, - target: _, - custom_bounds: _, - no_static: _, - no_runtime_generics: _, - cmp_eq: _, - get: _, - } = &options.body; - let span = ident.span(); - let mut type_attrs = attrs.clone(); - type_attrs.push(parse_quote_spanned! {span=> - #[allow(type_alias_bounds)] - }); - let type_param_ident = &generics.type_param.ident; - let syn_generics = Generics::from(generics); - ItemType { - attrs: type_attrs, - vis: vis.clone(), - type_token: *type_token, - ident: ident.clone(), - generics: syn_generics.clone(), - eq_token: *eq_token, - ty: parse_quote_spanned! {span=> - <#ty as ::fayalite::phantom_const::ReturnSelfUnchanged<#type_param_ident>>::Type - }, - semi_token: *semi_token, - } - .to_tokens(tokens); - let generics_accumulation_ident = - format_ident!("__{}__GenericsAccumulation", ident); - ItemStruct { - attrs: vec![ - common_derives(span), - parse_quote_spanned! {span=> - #[allow(non_camel_case_types)] - }, - ], - vis: vis.clone(), - struct_token: Token![struct](span), - ident: generics_accumulation_ident.clone(), - generics: Generics::default(), - fields: Fields::Unnamed(parse_quote_spanned! {span=> - (()) - }), - semi_token: Some(Token![;](span)), - } - .to_tokens(tokens); - quote_spanned! {span=> - #[allow(non_upper_case_globals, dead_code)] - #vis const #ident: #generics_accumulation_ident = #generics_accumulation_ident(()); - } - .to_tokens(tokens); - let mut wrapped_in_const = WrappedInConst::new(tokens, span); - let tokens = wrapped_in_const.inner(); - let (impl_generics, _type_generics, where_clause) = syn_generics.split_for_impl(); - let phantom_const_get_ty = &generics.type_param.phantom_const_get_bound.ty; - let index_output = if let Some(ty_is_dyn_size) = ty_is_dyn_size { - known_items::usize(ty_is_dyn_size.span).to_token_stream() - } else { - ty.to_token_stream() - }; - quote_spanned! {span=> - #[allow(non_upper_case_globals)] - #[automatically_derived] - impl #impl_generics ::fayalite::__std::ops::Index<#type_param_ident> - for #generics_accumulation_ident - #where_clause - { - type Output = #index_output; - - fn index(&self, __param: #type_param_ident) -> &Self::Output { - ::fayalite::phantom_const::type_alias_phantom_const_get_helper::<#phantom_const_get_ty, #index_output>( - __param, - #get_expr, - ) - } - } - } - .to_tokens(tokens); - } + let Self { + attrs, + options, + vis, + type_token, + ident, + generics, + eq_token, + ty, + semi_token, + } = self; + let ItemOptions { + outline_generated: _, + target, + custom_bounds: _, + no_static: _, + no_runtime_generics, + } = &options.body; + let target = get_target(target, ident); + let mut type_attrs = attrs.clone(); + type_attrs.push(parse_quote_spanned! {ident.span()=> + #[allow(type_alias_bounds)] + }); + ItemType { + attrs: type_attrs, + vis: vis.clone(), + type_token: *type_token, + ident: ident.clone(), + generics: generics.into(), + eq_token: *eq_token, + ty: Box::new(ty.clone().into()), + semi_token: *semi_token, + } + .to_tokens(tokens); + if let (MaybeParsed::Parsed(generics), MaybeParsed::Parsed(ty), None) = + (generics, ty, no_runtime_generics) + { + generics.make_runtime_generics(tokens, vis, ident, &target, |context| { + ty.make_hdl_type_expr(context) + }) } } } pub(crate) fn hdl_type_alias_impl(item: ItemType) -> syn::Result { let item = ParsedTypeAlias::parse(item)?; - let outline_generated = match &item { - ParsedTypeAlias::TypeAlias { options, .. } - | ParsedTypeAlias::PhantomConstAccessor { options, .. } => options.body.outline_generated, - }; + let outline_generated = item.options.body.outline_generated; let mut contents = item.to_token_stream(); if outline_generated.is_some() { contents = crate::outline_generated(contents, "hdl-type-alias-"); diff --git a/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs b/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs index f5b353e..6193dc3 100644 --- a/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs +++ b/crates/fayalite-proc-macros-impl/src/hdl_type_common.rs @@ -1,21 +1,21 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -use crate::{Errors, HdlAttr, PairsIterExt, fold::impl_fold, kw}; +use crate::{fold::impl_fold, kw, Errors, HdlAttr, PairsIterExt}; use proc_macro2::{Span, TokenStream}; -use quote::{ToTokens, format_ident, quote_spanned}; +use quote::{format_ident, quote_spanned, ToTokens}; use std::{collections::HashMap, fmt, mem}; use syn::{ - AngleBracketedGenericArguments, Attribute, Block, ConstParam, Expr, ExprBlock, ExprGroup, - ExprIndex, ExprParen, ExprPath, ExprTuple, Field, FieldMutability, Fields, FieldsNamed, - FieldsUnnamed, GenericArgument, GenericParam, Generics, Ident, ImplGenerics, Index, ItemStruct, - Path, PathArguments, PathSegment, PredicateType, QSelf, Stmt, Token, TraitBound, Turbofish, - Type, TypeGenerics, TypeGroup, TypeParam, TypeParamBound, TypeParen, TypePath, TypeTuple, - Visibility, WhereClause, WherePredicate, parse::{Parse, ParseStream}, parse_quote, parse_quote_spanned, punctuated::{Pair, Punctuated}, spanned::Spanned, token::{Brace, Bracket, Paren}, + AngleBracketedGenericArguments, Attribute, Block, ConstParam, Expr, ExprBlock, ExprGroup, + ExprIndex, ExprParen, ExprPath, ExprTuple, Field, FieldMutability, Fields, FieldsNamed, + FieldsUnnamed, GenericArgument, GenericParam, Generics, Ident, ImplGenerics, Index, ItemStruct, + Path, PathArguments, PathSegment, PredicateType, QSelf, Stmt, Token, Turbofish, Type, + TypeGenerics, TypeGroup, TypeParam, TypeParen, TypePath, TypeTuple, Visibility, WhereClause, + WherePredicate, }; crate::options! { @@ -26,8 +26,6 @@ crate::options! { CustomBounds(custom_bounds), NoStatic(no_static), NoRuntimeGenerics(no_runtime_generics), - CmpEq(cmp_eq), - Get(get, Expr), } } @@ -300,7 +298,7 @@ impl ParseTypes for ParsedExpr { return Ok(ParsedExpr::Delimited(ParsedExprDelimited { delim: ExprDelimiter::Group(*group_token), expr: parser.parse(expr)?, - })); + })) } Expr::Paren(ExprParen { attrs, @@ -310,7 +308,7 @@ impl ParseTypes for ParsedExpr { return Ok(ParsedExpr::Delimited(ParsedExprDelimited { delim: ExprDelimiter::Paren(*paren_token), expr: parser.parse(expr)?, - })); + })) } Expr::Path(ExprPath { attrs, @@ -1903,8 +1901,8 @@ pub(crate) mod known_items { use proc_macro2::{Ident, Span, TokenStream}; use quote::ToTokens; use syn::{ - Path, PathArguments, PathSegment, Token, parse::{Parse, ParseStream}, + Path, PathArguments, PathSegment, Token, }; macro_rules! impl_known_item_body { @@ -2046,7 +2044,6 @@ pub(crate) mod known_items { impl_known_item!(::fayalite::int::Size); impl_known_item!(::fayalite::int::UInt); impl_known_item!(::fayalite::int::UIntType); - impl_known_item!(::fayalite::phantom_const::PhantomConstGet); impl_known_item!(::fayalite::reset::ResetType); impl_known_item!(::fayalite::ty::CanonicalType); impl_known_item!(::fayalite::ty::StaticType); @@ -2065,174 +2062,6 @@ pub(crate) mod known_items { ); } -#[derive(Clone, Debug)] -pub(crate) struct PhantomConstGetBound { - pub(crate) phantom_const_get: known_items::PhantomConstGet, - pub(crate) colon2_token: Option, - pub(crate) lt_token: Token![<], - pub(crate) ty: Type, - pub(crate) comma_token: Option, - pub(crate) gt_token: Token![>], -} - -impl PhantomConstGetBound { - pub(crate) fn parse_path_with_arguments(path: Path) -> syn::Result> { - match known_items::PhantomConstGet::parse_path_with_arguments(path) { - Ok((phantom_const_get, arguments)) => { - Self::parse_path_and_arguments(phantom_const_get, arguments).map(Ok) - } - Err(path) => Ok(Err(path)), - } - } - pub(crate) fn parse_path_and_arguments( - phantom_const_get: known_items::PhantomConstGet, - arguments: PathArguments, - ) -> syn::Result { - let error = |arguments: PathArguments, message: &str| { - let mut path = phantom_const_get.path.clone(); - path.segments.last_mut().expect("known to exist").arguments = arguments; - syn::Error::new_spanned(path, message) - }; - match arguments { - PathArguments::None => Err(error(arguments, "missing generics for PhantomConstGet")), - PathArguments::AngleBracketed(AngleBracketedGenericArguments { - colon2_token, - lt_token, - args, - gt_token, - }) => { - let error = |args: Punctuated, message| { - error( - PathArguments::AngleBracketed(AngleBracketedGenericArguments { - colon2_token, - lt_token, - args, - gt_token, - }), - message, - ) - }; - let mut args = args.into_pairs().peekable(); - let Some((generic_argument, comma_token)) = args.next().map(Pair::into_tuple) - else { - return Err(error( - Default::default(), - "PhantomConstGet takes a type argument but no generic arguments were supplied", - )); - }; - if args.peek().is_some() { - return Err(error( - [Pair::new(generic_argument, comma_token)] - .into_iter() - .chain(args) - .collect(), - "PhantomConstGet takes a single type argument but too many generic arguments were supplied", - )); - }; - let GenericArgument::Type(ty) = generic_argument else { - return Err(error( - Punctuated::from_iter([Pair::new(generic_argument, comma_token)]), - "PhantomConstGet requires a type argument", - )); - }; - Ok(Self { - phantom_const_get, - colon2_token, - lt_token, - ty, - comma_token, - gt_token, - }) - } - PathArguments::Parenthesized(_) => Err(error( - arguments, - "parenthetical generics are not valid for PhantomConstGet", - )), - } - } - pub(crate) fn parse_type_param_bound( - bound: TypeParamBound, - ) -> syn::Result> { - let TypeParamBound::Trait(TraitBound { - paren_token: None, - modifier: syn::TraitBoundModifier::None, - lifetimes: None, - path, - }) = bound - else { - return Ok(Err(bound)); - }; - Ok(match Self::parse_path_with_arguments(path)? { - Ok(v) => Ok(v), - Err(path) => Err(TypeParamBound::Trait(TraitBound { - paren_token: None, - modifier: syn::TraitBoundModifier::None, - lifetimes: None, - path, - })), - }) - } -} - -impl ToTokens for PhantomConstGetBound { - fn to_tokens(&self, tokens: &mut TokenStream) { - let Self { - phantom_const_get, - colon2_token, - lt_token, - ty, - comma_token, - gt_token, - } = self; - phantom_const_get.to_tokens(tokens); - colon2_token.to_tokens(tokens); - lt_token.to_tokens(tokens); - ty.to_tokens(tokens); - comma_token.to_tokens(tokens); - gt_token.to_tokens(tokens); - } -} - -impl From for Path { - fn from(value: PhantomConstGetBound) -> Self { - let PhantomConstGetBound { - phantom_const_get, - colon2_token, - lt_token, - ty, - comma_token, - gt_token, - } = value; - let mut path = phantom_const_get.path; - path.segments.last_mut().expect("known to exist").arguments = - PathArguments::AngleBracketed(AngleBracketedGenericArguments { - colon2_token, - lt_token, - args: FromIterator::from_iter([Pair::new(GenericArgument::Type(ty), comma_token)]), - gt_token, - }); - path - } -} - -impl From for TraitBound { - fn from(value: PhantomConstGetBound) -> Self { - let path = Path::from(value); - TraitBound { - paren_token: None, - modifier: syn::TraitBoundModifier::None, - lifetimes: None, - path, - } - } -} - -impl From for TypeParamBound { - fn from(value: PhantomConstGetBound) -> Self { - TraitBound::from(value).into() - } -} - macro_rules! impl_bounds { ( #[struct = $struct_type:ident] @@ -2240,21 +2069,11 @@ macro_rules! impl_bounds { $( $Variant:ident, )* - $( - #[has_body] - $VariantHasBody:ident($variant_has_body_ty:ty), - )* - $( - #[unknown] - $Unknown:ident, - )? } ) => { #[derive(Clone, Debug)] $vis enum $enum_type { $($Variant(known_items::$Variant),)* - $($VariantHasBody($variant_has_body_ty),)* - $($Unknown(syn::TypeParamBound),)? } $(impl From for $enum_type { @@ -2263,69 +2082,32 @@ macro_rules! impl_bounds { } })* - $(impl From<$variant_has_body_ty> for $enum_type { - fn from(v: $variant_has_body_ty) -> Self { - Self::$VariantHasBody(v) - } - })* - impl ToTokens for $enum_type { fn to_tokens(&self, tokens: &mut TokenStream) { match self { $(Self::$Variant(v) => v.to_tokens(tokens),)* - $(Self::$VariantHasBody(v) => v.to_tokens(tokens),)* - $(Self::$Unknown(v) => v.to_tokens(tokens),)? } } } impl $enum_type { - $vis fn parse_path_with_arguments(path: Path) -> syn::Result> { - #![allow(unreachable_code)] + $vis fn parse_path(path: Path) -> Result { $(let path = match known_items::$Variant::parse_path(path) { - Ok(v) => return Ok(Ok(Self::$Variant(v))), + Ok(v) => return Ok(Self::$Variant(v)), Err(path) => path, };)* - $(let path = match <$variant_has_body_ty>::parse_path_with_arguments(path)? { - Ok(v) => return Ok(Ok(Self::$VariantHasBody(v))), - Err(path) => path, - };)* - $(return Ok(Ok(Self::$Unknown(syn::TraitBound { - paren_token: None, - modifier: syn::TraitBoundModifier::None, - lifetimes: None, - path, - }.into())));)? - Ok(Err(path)) - } - $vis fn parse_type_param_bound(mut type_param_bound: syn::TypeParamBound) -> syn::Result> { - #![allow(unreachable_code)] - if let syn::TypeParamBound::Trait(mut trait_bound) = type_param_bound { - if let syn::TraitBound { - paren_token: _, - modifier: syn::TraitBoundModifier::None, - lifetimes: None, - path: _, - } = trait_bound { - match Self::parse_path_with_arguments(trait_bound.path)? { - Ok(retval) => return Ok(Ok(retval)), - Err(path) => trait_bound.path = path, - } - } - type_param_bound = trait_bound.into(); - } - $(return Ok(Ok(Self::$Unknown(type_param_bound)));)? - Ok(Err(type_param_bound)) + Err(path) } } impl Parse for $enum_type { fn parse(input: ParseStream) -> syn::Result { - Self::parse_type_param_bound(input.parse()?)? - .map_err(|type_param_bound| syn::Error::new_spanned( - type_param_bound, - format_args!("expected one of: {}", [$(stringify!($Variant),)* $(stringify!($VariantHasBody)),*].join(", ")), - )) + Self::parse_path(Path::parse_mod_style(input)?).map_err(|path| { + syn::Error::new_spanned( + path, + format_args!("expected one of: {}", [$(stringify!($Variant)),*].join(", ")), + ) + }) } } @@ -2333,8 +2115,6 @@ macro_rules! impl_bounds { #[allow(non_snake_case)] $vis struct $struct_type { $($vis $Variant: Option,)* - $($vis $VariantHasBody: Option<$variant_has_body_ty>,)* - $($vis $Unknown: Vec,)? } impl ToTokens for $struct_type { @@ -2346,80 +2126,42 @@ macro_rules! impl_bounds { separator = Some(::default()); v.to_tokens(tokens); })* - $(if let Some(v) = &self.$VariantHasBody { - separator.to_tokens(tokens); - separator = Some(::default()); - v.to_tokens(tokens); - })* - $(for v in &self.$Unknown { - separator.to_tokens(tokens); - separator = Some(::default()); - v.to_tokens(tokens); - })* } } const _: () = { #[derive(Clone, Debug)] - #[allow(non_snake_case)] - $vis struct Iter { - $($Variant: Option,)* - $($VariantHasBody: Option<$variant_has_body_ty>,)* - $($Unknown: std::vec::IntoIter,)? - } + $vis struct Iter($vis $struct_type); impl IntoIterator for $struct_type { type Item = $enum_type; type IntoIter = Iter; fn into_iter(self) -> Self::IntoIter { - Iter { - $($Variant: self.$Variant,)* - $($VariantHasBody: self.$VariantHasBody,)* - $($Unknown: self.$Unknown.into_iter(),)? - } + Iter(self) } } impl Iterator for Iter { type Item = $enum_type; + fn next(&mut self) -> Option { $( - if let Some(value) = self.$Variant.take() { + if let Some(value) = self.0.$Variant.take() { return Some($enum_type::$Variant(value)); } )* - $( - if let Some(value) = self.$VariantHasBody.take() { - return Some($enum_type::$VariantHasBody(value)); - } - )* - $( - if let Some(value) = self.$Unknown.next() { - return Some($enum_type::$Unknown(value)); - } - )? None } #[allow(unused_mut, unused_variables)] fn fold B>(mut self, mut init: B, mut f: F) -> B { $( - if let Some(value) = self.$Variant.take() { + if let Some(value) = self.0.$Variant.take() { init = f(init, $enum_type::$Variant(value)); } )* - $( - if let Some(value) = self.$VariantHasBody.take() { - init = f(init, $enum_type::$VariantHasBody(value)); - } - )* - $( - if let Some(value) = self.$Unknown.next() { - init = f(init, $enum_type::$Unknown(value)); - } - )? init } } @@ -2431,12 +2173,6 @@ macro_rules! impl_bounds { $($enum_type::$Variant(v) => { self.$Variant = Some(v); })* - $($enum_type::$VariantHasBody(v) => { - self.$VariantHasBody = Some(v); - })* - $($enum_type::$Unknown(v) => { - self.$Unknown.push(v); - })? }); } } @@ -2455,10 +2191,6 @@ macro_rules! impl_bounds { $(if let Some(v) = v.$Variant { self.$Variant = Some(v); })* - $(if let Some(v) = v.$VariantHasBody { - self.$VariantHasBody = Some(v); - })* - $(self.$Unknown.extend(v.$Unknown);)* }); } } @@ -2512,10 +2244,6 @@ impl_bounds! { Size, StaticType, Type, - #[has_body] - PhantomConstGet(PhantomConstGetBound), - #[unknown] - Unknown, } } @@ -2529,10 +2257,6 @@ impl_bounds! { ResetType, StaticType, Type, - #[has_body] - PhantomConstGet(PhantomConstGetBound), - #[unknown] - Unknown, } } @@ -2546,8 +2270,6 @@ impl From for ParsedBound { ParsedTypeBound::ResetType(v) => ParsedBound::ResetType(v), ParsedTypeBound::StaticType(v) => ParsedBound::StaticType(v), ParsedTypeBound::Type(v) => ParsedBound::Type(v), - ParsedTypeBound::PhantomConstGet(v) => ParsedBound::PhantomConstGet(v), - ParsedTypeBound::Unknown(v) => ParsedBound::Unknown(v), } } } @@ -2562,8 +2284,6 @@ impl From for ParsedBounds { ResetType, StaticType, Type, - PhantomConstGet, - Unknown, } = value; Self { BoolOrIntType, @@ -2575,8 +2295,6 @@ impl From for ParsedBounds { Size: None, StaticType, Type, - PhantomConstGet, - Unknown, } } } @@ -2612,11 +2330,6 @@ impl ParsedTypeBound { ParsedTypeBound::Type(known_items::Type(span)), ]), Self::Type(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::from(v)]), - Self::PhantomConstGet(v) => ParsedTypeBounds::from_iter([ - ParsedTypeBound::from(v), - ParsedTypeBound::Type(known_items::Type(span)), - ]), - Self::Unknown(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::Unknown(v)]), } } } @@ -2651,8 +2364,6 @@ impl From for ParsedBounds { Size, StaticType: None, Type: None, - PhantomConstGet: None, - Unknown: vec![], } } } @@ -2680,7 +2391,6 @@ impl ParsedBounds { fn categorize(self, errors: &mut Errors, span: Span) -> ParsedBoundsCategory { let mut type_bounds = None; let mut size_type_bounds = None; - let mut unknown_bounds = vec![]; self.into_iter().for_each(|bound| match bound.categorize() { ParsedBoundCategory::Type(bound) => { type_bounds @@ -2692,37 +2402,15 @@ impl ParsedBounds { .get_or_insert_with(ParsedSizeTypeBounds::default) .extend([bound]); } - ParsedBoundCategory::Unknown(bound) => unknown_bounds.push(bound), }); - match (type_bounds, size_type_bounds, unknown_bounds.is_empty()) { - (None, None, true) => ParsedBoundsCategory::Type(ParsedTypeBounds { + match (type_bounds, size_type_bounds) { + (None, None) => ParsedBoundsCategory::Type(ParsedTypeBounds { Type: Some(known_items::Type(span)), ..Default::default() }), - (None, None, false) => { - errors.error( - unknown_bounds.remove(0), - "unknown bounds: must use at least one known bound (such as `Type`) with any unknown bounds", - ); - ParsedBoundsCategory::Type(ParsedTypeBounds { - Unknown: unknown_bounds, - ..Default::default() - }) - } - (None, Some(bounds), true) => ParsedBoundsCategory::SizeType(bounds), - (None, Some(bounds), false) => { - // TODO: implement - errors.error( - unknown_bounds.remove(0), - "unknown bounds with `Size` bounds are not implemented", - ); - ParsedBoundsCategory::SizeType(bounds) - } - (Some(bounds), None, _) => ParsedBoundsCategory::Type(ParsedTypeBounds { - Unknown: unknown_bounds, - ..bounds - }), - (Some(type_bounds), Some(size_type_bounds), _) => { + (None, Some(bounds)) => ParsedBoundsCategory::SizeType(bounds), + (Some(bounds), None) => ParsedBoundsCategory::Type(bounds), + (Some(type_bounds), Some(size_type_bounds)) => { errors.error( size_type_bounds .Size @@ -2739,7 +2427,6 @@ impl ParsedBounds { pub(crate) enum ParsedBoundCategory { Type(ParsedTypeBound), SizeType(ParsedSizeTypeBound), - Unknown(syn::TypeParamBound), } impl ParsedBound { @@ -2754,17 +2441,12 @@ impl ParsedBound { Self::Size(v) => ParsedBoundCategory::SizeType(ParsedSizeTypeBound::Size(v)), Self::StaticType(v) => ParsedBoundCategory::Type(ParsedTypeBound::StaticType(v)), Self::Type(v) => ParsedBoundCategory::Type(ParsedTypeBound::Type(v)), - Self::PhantomConstGet(v) => { - ParsedBoundCategory::Type(ParsedTypeBound::PhantomConstGet(v)) - } - Self::Unknown(v) => ParsedBoundCategory::Unknown(v), } } fn implied_bounds(self) -> ParsedBounds { match self.categorize() { ParsedBoundCategory::Type(v) => v.implied_bounds().into(), ParsedBoundCategory::SizeType(v) => v.implied_bounds().into(), - ParsedBoundCategory::Unknown(v) => ParsedBounds::from_iter([ParsedBound::Unknown(v)]), } } } @@ -3642,9 +3324,8 @@ impl ParsedGenerics { | ParsedTypeBound::BundleType(_) | ParsedTypeBound::EnumType(_) | ParsedTypeBound::IntType(_) - | ParsedTypeBound::ResetType(_) - | ParsedTypeBound::PhantomConstGet(_) => { - errors.error(bound, "bounds on mask types are not implemented"); + | ParsedTypeBound::ResetType(_) => { + errors.error(bound, "bound on mask type not implemented"); } ParsedTypeBound::StaticType(bound) => { if bounds.StaticType.is_none() { @@ -3656,12 +3337,6 @@ impl ParsedGenerics { } } ParsedTypeBound::Type(_) => {} - ParsedTypeBound::Unknown(_) => { - errors.error( - bound, - "unknown bounds on mask types are not implemented", - ); - } } } bounds.add_implied_bounds(); @@ -3987,10 +3662,7 @@ pub(crate) trait AsTurbofish { } impl AsTurbofish for TypeGenerics<'_> { - type Turbofish<'a> - = Turbofish<'a> - where - Self: 'a; + type Turbofish<'a> = Turbofish<'a> where Self: 'a; fn as_turbofish(&self) -> Self::Turbofish<'_> { TypeGenerics::as_turbofish(self) @@ -3998,8 +3670,7 @@ impl AsTurbofish for TypeGenerics<'_> { } impl AsTurbofish for ParsedGenericsTypeGenerics<'_> { - type Turbofish<'a> - = ParsedGenericsTurbofish<'a> + type Turbofish<'a> = ParsedGenericsTurbofish<'a> where Self: 'a; @@ -4050,18 +3721,15 @@ impl SplitForImpl for Generics { } impl SplitForImpl for ParsedGenerics { - type ImplGenerics<'a> - = ParsedGenericsImplGenerics<'a> + type ImplGenerics<'a> = ParsedGenericsImplGenerics<'a> where Self: 'a; - type TypeGenerics<'a> - = ParsedGenericsTypeGenerics<'a> + type TypeGenerics<'a> = ParsedGenericsTypeGenerics<'a> where Self: 'a; - type WhereClause<'a> - = ParsedGenericsWhereClause<'a> + type WhereClause<'a> = ParsedGenericsWhereClause<'a> where Self: 'a; @@ -4278,8 +3946,7 @@ impl ToTokens for MaybeParsed { } impl AsTurbofish for MaybeParsed { - type Turbofish<'a> - = MaybeParsed, U::Turbofish<'a>> + type Turbofish<'a> = MaybeParsed, U::Turbofish<'a>> where Self: 'a; @@ -4292,16 +3959,13 @@ impl AsTurbofish for MaybeParsed { } impl SplitForImpl for MaybeParsed { - type ImplGenerics<'a> - = MaybeParsed, U::ImplGenerics<'a>> + type ImplGenerics<'a> = MaybeParsed, U::ImplGenerics<'a>> where Self: 'a; - type TypeGenerics<'a> - = MaybeParsed, U::TypeGenerics<'a>> + type TypeGenerics<'a> = MaybeParsed, U::TypeGenerics<'a>> where Self: 'a; - type WhereClause<'a> - = MaybeParsed, U::WhereClause<'a>> + type WhereClause<'a> = MaybeParsed, U::WhereClause<'a>> where Self: 'a; diff --git a/crates/fayalite-proc-macros-impl/src/lib.rs b/crates/fayalite-proc-macros-impl/src/lib.rs index 13ec7a2..6ba177b 100644 --- a/crates/fayalite-proc-macros-impl/src/lib.rs +++ b/crates/fayalite-proc-macros-impl/src/lib.rs @@ -2,13 +2,13 @@ // See Notices.txt for copyright information #![cfg_attr(test, recursion_limit = "512")] use proc_macro2::{Span, TokenStream}; -use quote::{ToTokens, quote}; +use quote::{quote, ToTokens}; use std::{ - collections::{HashMap, hash_map::Entry}, + collections::{hash_map::Entry, HashMap}, io::{ErrorKind, Write}, }; use syn::{ - AttrStyle, Attribute, Error, Ident, Item, ItemFn, LitBool, LitStr, Meta, Token, bracketed, + bracketed, ext::IdentExt, parenthesized, parse::{Parse, ParseStream, Parser}, @@ -16,6 +16,7 @@ use syn::{ punctuated::{Pair, Punctuated}, spanned::Spanned, token::{Bracket, Paren}, + AttrStyle, Attribute, Error, Ident, Item, ItemFn, LitBool, LitStr, Meta, Token, }; mod fold; @@ -66,21 +67,18 @@ mod kw { } custom_keyword!(__evaluated_cfgs); - custom_keyword!(add_platform_io); custom_keyword!(all); custom_keyword!(any); custom_keyword!(cfg); custom_keyword!(cfg_attr); custom_keyword!(clock_domain); - custom_keyword!(cmp_eq); custom_keyword!(connect_inexact); custom_keyword!(custom_bounds); custom_keyword!(flip); - custom_keyword!(get); custom_keyword!(hdl); custom_keyword!(hdl_module); - custom_keyword!(incomplete_wire); custom_keyword!(input); + custom_keyword!(incomplete_wire); custom_keyword!(instance); custom_keyword!(m); custom_keyword!(memory); @@ -94,7 +92,6 @@ mod kw { custom_keyword!(output); custom_keyword!(reg_builder); custom_keyword!(reset); - custom_keyword!(sim); custom_keyword!(skip); custom_keyword!(target); custom_keyword!(wire); diff --git a/crates/fayalite-proc-macros-impl/src/module.rs b/crates/fayalite-proc-macros-impl/src/module.rs index 5628ff9..0852f58 100644 --- a/crates/fayalite-proc-macros-impl/src/module.rs +++ b/crates/fayalite-proc-macros-impl/src/module.rs @@ -1,20 +1,19 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ - Errors, HdlAttr, PairsIterExt, hdl_type_common::{ParsedGenerics, SplitForImpl}, kw, - module::transform_body::{HdlLet, HdlLetKindIO, ModuleIOOrAddPlatformIO}, - options, + module::transform_body::{HdlLet, HdlLetKindIO}, + options, Errors, HdlAttr, PairsIterExt, }; use proc_macro2::TokenStream; -use quote::{ToTokens, format_ident, quote, quote_spanned}; +use quote::{format_ident, quote, quote_spanned, ToTokens}; use std::collections::HashSet; use syn::{ + parse_quote, + visit::{visit_pat, Visit}, Attribute, Block, ConstParam, Error, FnArg, GenericParam, Generics, Ident, ItemFn, ItemStruct, LifetimeParam, ReturnType, Signature, TypeParam, Visibility, WhereClause, WherePredicate, - parse_quote, - visit::{Visit, visit_pat}, }; mod transform_body; @@ -39,7 +38,7 @@ pub(crate) fn check_name_conflicts_with_module_builder(name: &Ident) -> syn::Res if name == "m" { Err(Error::new_spanned( name, - "name conflicts with implicit `m: &ModuleBuilder`", + "name conflicts with implicit `m: &mut ModuleBuilder<_>`", )) } else { Ok(()) @@ -67,7 +66,7 @@ struct ModuleFnModule { vis: Visibility, sig: Signature, block: Box, - struct_generics: Option, + struct_generics: ParsedGenerics, the_struct: TokenStream, } @@ -290,7 +289,7 @@ impl ModuleFn { paren_token, body, } => { - debug_assert!(matches!(io, ModuleIOOrAddPlatformIO::ModuleIO(v) if v.is_empty())); + debug_assert!(io.is_empty()); return Ok(Self(ModuleFnImpl::Fn { attrs, config_options: HdlAttr { @@ -322,21 +321,6 @@ impl ModuleFn { body, }, }; - let io = match io { - ModuleIOOrAddPlatformIO::ModuleIO(io) => io, - ModuleIOOrAddPlatformIO::AddPlatformIO => { - return Ok(Self(ModuleFnImpl::Module(ModuleFnModule { - attrs, - config_options, - module_kind: module_kind.unwrap(), - vis, - sig, - block, - struct_generics: None, - the_struct: TokenStream::new(), - }))); - } - }; let (_struct_impl_generics, _struct_type_generics, struct_where_clause) = struct_generics.split_for_impl(); let struct_where_clause: Option = parse_quote! { #struct_where_clause }; @@ -379,7 +363,7 @@ impl ModuleFn { vis, sig, block, - struct_generics: Some(struct_generics), + struct_generics, the_struct, }))) } @@ -393,7 +377,7 @@ impl ModuleFn { module_kind, vis, sig, - mut block, + block, struct_generics, the_struct, } = match self.0 { @@ -448,24 +432,13 @@ impl ModuleFn { ModuleKind::Normal => quote! { ::fayalite::module::ModuleKind::Normal }, }; let fn_name = &outer_sig.ident; - let struct_ty = match struct_generics { - Some(struct_generics) => { - let (_struct_impl_generics, struct_type_generics, _struct_where_clause) = - struct_generics.split_for_impl(); - quote! {#fn_name #struct_type_generics} - } - None => quote! {::fayalite::bundle::Bundle}, - }; + let (_struct_impl_generics, struct_type_generics, _struct_where_clause) = + struct_generics.split_for_impl(); + let struct_ty = quote! {#fn_name #struct_type_generics}; body_sig.ident = parse_quote! {__body}; body_sig .inputs .insert(0, parse_quote! { m: &::fayalite::module::ModuleBuilder }); - block.stmts.insert( - 0, - parse_quote! { - let _ = m; - }, - ); let body_fn = ItemFn { attrs: vec![], vis: Visibility::Inherited, diff --git a/crates/fayalite-proc-macros-impl/src/module/transform_body.rs b/crates/fayalite-proc-macros-impl/src/module/transform_body.rs index 7b41f5e..6e99e87 100644 --- a/crates/fayalite-proc-macros-impl/src/module/transform_body.rs +++ b/crates/fayalite-proc-macros-impl/src/module/transform_body.rs @@ -1,45 +1,36 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ - Errors, HdlAttr, - fold::{DoFold, impl_fold}, + fold::{impl_fold, DoFold}, hdl_type_common::{ - ParseFailed, ParseTypes, ParsedGenerics, ParsedType, TypesParser, known_items, + known_items, ParseFailed, ParseTypes, ParsedGenerics, ParsedType, TypesParser, }, is_hdl_attr, kw, - module::{ModuleIO, ModuleIOKind, ModuleKind, check_name_conflicts_with_module_builder}, - options, + module::{check_name_conflicts_with_module_builder, ModuleIO, ModuleIOKind, ModuleKind}, + options, Errors, HdlAttr, }; use num_bigint::BigInt; use proc_macro2::{Span, TokenStream}; -use quote::{ToTokens, quote, quote_spanned}; +use quote::{quote, quote_spanned, ToTokens}; use std::{borrow::Borrow, convert::Infallible}; use syn::{ - Attribute, Block, Error, Expr, ExprIf, ExprLet, ExprLit, ExprRepeat, ExprUnary, - GenericArgument, Ident, Item, Lit, LitStr, Local, LocalInit, Pat, Token, Type, UnOp, - fold::{Fold, fold_expr, fold_expr_lit, fold_expr_unary, fold_local, fold_stmt}, + fold::{fold_expr, fold_expr_lit, fold_expr_unary, fold_local, fold_stmt, Fold}, parenthesized, - parse::{Parse, ParseStream}, + parse::{Nothing, Parse, ParseStream}, parse_quote, parse_quote_spanned, spanned::Spanned, token::Paren, + Attribute, Block, Error, Expr, ExprIf, ExprLet, ExprLit, ExprRepeat, ExprUnary, + GenericArgument, Ident, Item, Lit, LitStr, Local, LocalInit, Pat, Token, Type, UnOp, }; mod expand_aggregate_literals; mod expand_match; -options! { - #[options = ExprOptions] - pub(crate) enum ExprOption { - Sim(sim), - } -} - options! { pub(crate) enum LetFnKind { Input(input), Output(output), - AddPlatformIO(add_platform_io), Instance(instance), RegBuilder(reg_builder), Wire(wire), @@ -217,49 +208,6 @@ impl HdlLetKindToTokens for HdlLetKindInstance { } } -#[derive(Clone, Debug)] -pub(crate) struct HdlLetKindAddPlatformIO { - pub(crate) m: kw::m, - pub(crate) dot_token: Token![.], - pub(crate) add_platform_io: kw::add_platform_io, - pub(crate) paren: Paren, - pub(crate) platform_io_builder: Box, -} - -impl ParseTypes for HdlLetKindAddPlatformIO { - fn parse_types(input: &mut Self, _parser: &mut TypesParser<'_>) -> Result { - Ok(input.clone()) - } -} - -impl_fold! { - struct HdlLetKindAddPlatformIO<> { - m: kw::m, - dot_token: Token![.], - add_platform_io: kw::add_platform_io, - paren: Paren, - platform_io_builder: Box, - } -} - -impl HdlLetKindToTokens for HdlLetKindAddPlatformIO { - fn ty_to_tokens(&self, _tokens: &mut TokenStream) {} - - fn expr_to_tokens(&self, tokens: &mut TokenStream) { - let Self { - m, - dot_token, - add_platform_io, - paren, - platform_io_builder, - } = self; - m.to_tokens(tokens); - dot_token.to_tokens(tokens); - add_platform_io.to_tokens(tokens); - paren.surround(tokens, |tokens| platform_io_builder.to_tokens(tokens)); - } -} - #[derive(Clone, Debug)] pub(crate) struct RegBuilderClockDomain { pub(crate) dot_token: Token![.], @@ -755,7 +703,6 @@ impl HdlLetKindMemory { #[derive(Clone, Debug)] pub(crate) enum HdlLetKind { IO(HdlLetKindIO), - AddPlatformIO(HdlLetKindAddPlatformIO), Incomplete(HdlLetKindIncomplete), Instance(HdlLetKindInstance), RegBuilder(HdlLetKindRegBuilder), @@ -766,7 +713,6 @@ pub(crate) enum HdlLetKind { impl_fold! { enum HdlLetKind { IO(HdlLetKindIO), - AddPlatformIO(HdlLetKindAddPlatformIO), Incomplete(HdlLetKindIncomplete), Instance(HdlLetKindInstance), RegBuilder(HdlLetKindRegBuilder), @@ -782,9 +728,6 @@ impl, I> ParseTypes> for HdlLetKind { ) -> Result { match input { HdlLetKind::IO(input) => ParseTypes::parse_types(input, parser).map(HdlLetKind::IO), - HdlLetKind::AddPlatformIO(input) => { - ParseTypes::parse_types(input, parser).map(HdlLetKind::AddPlatformIO) - } HdlLetKind::Incomplete(input) => { ParseTypes::parse_types(input, parser).map(HdlLetKind::Incomplete) } @@ -910,23 +853,6 @@ impl HdlLetKindParse for HdlLetKind { ModuleIOKind::Output(output), ) .map(Self::IO), - LetFnKind::AddPlatformIO((add_platform_io,)) => { - if let Some(parsed_ty) = parsed_ty { - return Err(Error::new_spanned( - parsed_ty.1, - "type annotation not allowed for instance", - )); - } - let (m, dot_token) = unwrap_m_dot(m_dot, kind)?; - let paren_contents; - Ok(Self::AddPlatformIO(HdlLetKindAddPlatformIO { - m, - dot_token, - add_platform_io, - paren: parenthesized!(paren_contents in input), - platform_io_builder: paren_contents.call(parse_single_fn_arg)?, - })) - } LetFnKind::Instance((instance,)) => { if let Some(parsed_ty) = parsed_ty { return Err(Error::new_spanned( @@ -1002,7 +928,6 @@ impl HdlLetKindToTokens for HdlLetKind { fn ty_to_tokens(&self, tokens: &mut TokenStream) { match self { HdlLetKind::IO(v) => v.ty_to_tokens(tokens), - HdlLetKind::AddPlatformIO(v) => v.ty_to_tokens(tokens), HdlLetKind::Incomplete(v) => v.ty_to_tokens(tokens), HdlLetKind::Instance(v) => v.ty_to_tokens(tokens), HdlLetKind::RegBuilder(v) => v.ty_to_tokens(tokens), @@ -1014,7 +939,6 @@ impl HdlLetKindToTokens for HdlLetKind { fn expr_to_tokens(&self, tokens: &mut TokenStream) { match self { HdlLetKind::IO(v) => v.expr_to_tokens(tokens), - HdlLetKind::AddPlatformIO(v) => v.expr_to_tokens(tokens), HdlLetKind::Incomplete(v) => v.expr_to_tokens(tokens), HdlLetKind::Instance(v) => v.expr_to_tokens(tokens), HdlLetKind::RegBuilder(v) => v.expr_to_tokens(tokens), @@ -1028,7 +952,7 @@ with_debug_clone_and_fold! { #[allow(dead_code)] pub(crate) struct HdlLet { pub(crate) attrs: Vec, - pub(crate) hdl_attr: HdlAttr, + pub(crate) hdl_attr: HdlAttr, pub(crate) let_token: Token![let], pub(crate) mut_token: Option, pub(crate) name: Ident, @@ -1185,7 +1109,7 @@ fn parse_quote_let_pat>( } } -pub(crate) fn wrap_ty_with_expr(ty: impl ToTokens) -> Type { +fn wrap_ty_with_expr(ty: impl ToTokens) -> Type { parse_quote_spanned! {ty.span()=> ::fayalite::expr::Expr<#ty> } @@ -1217,7 +1141,7 @@ impl ToTokens for ImplicitName { struct Visitor<'a> { module_kind: Option, errors: Errors, - io: ModuleIOOrAddPlatformIO, + io: Vec, block_depth: usize, parsed_generics: &'a ParsedGenerics, } @@ -1249,7 +1173,7 @@ impl Visitor<'_> { Some(_) => {} } } - fn process_hdl_if(&mut self, hdl_attr: HdlAttr, expr_if: ExprIf) -> Expr { + fn process_hdl_if(&mut self, hdl_attr: HdlAttr, expr_if: ExprIf) -> Expr { let ExprIf { attrs, if_token, @@ -1257,10 +1181,10 @@ impl Visitor<'_> { then_branch, else_branch, } = expr_if; - let (else_token, else_expr) = else_branch.unzip(); - let else_expr = else_expr.map(|else_expr| match *else_expr { - Expr::If(expr_if) => Box::new(self.process_hdl_if(hdl_attr.clone(), expr_if)), - _ => else_expr, + self.require_normal_module_or_fn(if_token); + let else_expr = else_branch.unzip().1.map(|else_expr| match *else_expr { + Expr::If(expr_if) => self.process_hdl_if(hdl_attr.clone(), expr_if), + expr => expr, }); if let Expr::Let(ExprLet { attrs: let_attrs, @@ -1282,19 +1206,7 @@ impl Visitor<'_> { }, ); } - let ExprOptions { sim } = hdl_attr.body; - if sim.is_some() { - ExprIf { - attrs, - if_token, - cond: parse_quote_spanned! {if_token.span=> - *::fayalite::sim::value::SimValue::<::fayalite::int::Bool>::value(&::fayalite::sim::value::ToSimValue::into_sim_value(#cond)) - }, - then_branch, - else_branch: else_token.zip(else_expr), - } - .into() - } else if let Some(else_expr) = else_expr { + if let Some(else_expr) = else_expr { parse_quote_spanned! {if_token.span=> #(#attrs)* { @@ -1357,81 +1269,7 @@ impl Visitor<'_> { }), semi_token: hdl_let.semi_token, }; - match &mut self.io { - ModuleIOOrAddPlatformIO::ModuleIO(io) => io.push(hdl_let), - ModuleIOOrAddPlatformIO::AddPlatformIO => { - self.errors.error( - kind, - "can't have other inputs/outputs in a module using m.add_platform_io()", - ); - } - } - let_stmt - } - fn process_hdl_let_add_platform_io( - &mut self, - hdl_let: HdlLet, - ) -> Local { - let HdlLet { - mut attrs, - hdl_attr: _, - let_token, - mut_token, - ref name, - eq_token, - kind: - HdlLetKindAddPlatformIO { - m, - dot_token, - add_platform_io, - paren, - platform_io_builder, - }, - semi_token, - } = hdl_let; - let mut expr = quote! {#m #dot_token #add_platform_io}; - paren.surround(&mut expr, |expr| { - let name_str = ImplicitName { - name, - span: name.span(), - }; - quote_spanned! {name.span()=> - #name_str, #platform_io_builder - } - .to_tokens(expr); - }); - self.require_module(add_platform_io); - attrs.push(parse_quote_spanned! {let_token.span=> - #[allow(unused_variables)] - }); - let let_stmt = Local { - attrs, - let_token, - pat: parse_quote! { #mut_token #name }, - init: Some(LocalInit { - eq_token, - expr: parse_quote! { #expr }, - diverge: None, - }), - semi_token, - }; - match &mut self.io { - ModuleIOOrAddPlatformIO::ModuleIO(io) => { - for io in io { - self.errors.error( - io.kind.kind, - "can't have other inputs/outputs in a module using m.add_platform_io()", - ); - } - } - ModuleIOOrAddPlatformIO::AddPlatformIO => { - self.errors.error( - add_platform_io, - "can't use m.add_platform_io() more than once in a single module", - ); - } - } - self.io = ModuleIOOrAddPlatformIO::AddPlatformIO; + self.io.push(hdl_let); let_stmt } fn process_hdl_let_instance(&mut self, hdl_let: HdlLet) -> Local { @@ -1652,7 +1490,6 @@ impl Visitor<'_> { } the_match! { IO => process_hdl_let_io, - AddPlatformIO => process_hdl_let_add_platform_io, Incomplete => process_hdl_let_incomplete, Instance => process_hdl_let_instance, RegBuilder => process_hdl_let_reg_builder, @@ -1749,7 +1586,7 @@ impl Visitor<'_> { } } -pub(crate) fn empty_let() -> Local { +fn empty_let() -> Local { Local { attrs: vec![], let_token: Default::default(), @@ -1831,42 +1668,20 @@ impl Fold for Visitor<'_> { Repeat => process_hdl_repeat, Struct => process_hdl_struct, Tuple => process_hdl_tuple, - MethodCall => process_hdl_method_call, - Call => process_hdl_call, } } } - fn fold_local(&mut self, mut let_stmt: Local) -> Local { + fn fold_local(&mut self, let_stmt: Local) -> Local { match self .errors - .ok(HdlAttr::::parse_and_leave_attr( + .ok(HdlAttr::::parse_and_leave_attr( &let_stmt.attrs, )) { None => return empty_let(), Some(None) => return fold_local(self, let_stmt), Some(Some(HdlAttr { .. })) => {} }; - let mut pat = &let_stmt.pat; - if let Pat::Type(pat_type) = pat { - pat = &pat_type.pat; - } - let Pat::Ident(syn::PatIdent { - attrs: _, - by_ref: None, - mutability: _, - ident: _, - subpat: None, - }) = pat - else { - let hdl_attr = - HdlAttr::::parse_and_take_attr(&mut let_stmt.attrs) - .ok() - .flatten() - .expect("already checked above"); - let let_stmt = fold_local(self, let_stmt); - return self.process_hdl_let_pat(hdl_attr, let_stmt); - }; let hdl_let = syn::parse2::>>(let_stmt.into_token_stream()); let Some(hdl_let) = self.errors.ok(hdl_let) else { return empty_let(); @@ -1896,20 +1711,15 @@ impl Fold for Visitor<'_> { } } -pub(crate) enum ModuleIOOrAddPlatformIO { - ModuleIO(Vec), - AddPlatformIO, -} - pub(crate) fn transform_body( module_kind: Option, mut body: Box, parsed_generics: &ParsedGenerics, -) -> syn::Result<(Box, ModuleIOOrAddPlatformIO)> { +) -> syn::Result<(Box, Vec)> { let mut visitor = Visitor { module_kind, errors: Errors::new(), - io: ModuleIOOrAddPlatformIO::ModuleIO(vec![]), + io: vec![], block_depth: 0, parsed_generics, }; diff --git a/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_aggregate_literals.rs b/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_aggregate_literals.rs index 1aabb19..b5a0ad3 100644 --- a/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_aggregate_literals.rs +++ b/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_aggregate_literals.rs @@ -1,102 +1,45 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information - -use crate::{ - HdlAttr, kw, - module::transform_body::{ - ExprOptions, Visitor, - expand_match::{EnumPath, parse_enum_path}, - }, -}; +use crate::{kw, module::transform_body::Visitor, HdlAttr}; use quote::{format_ident, quote_spanned}; -use std::mem; use syn::{ - Expr, ExprArray, ExprCall, ExprGroup, ExprMethodCall, ExprParen, ExprPath, ExprRepeat, - ExprStruct, ExprTuple, FieldValue, Token, TypePath, parse_quote_spanned, - punctuated::Punctuated, spanned::Spanned, token::Paren, + parse::Nothing, parse_quote, parse_quote_spanned, spanned::Spanned, Expr, ExprArray, ExprPath, + ExprRepeat, ExprStruct, ExprTuple, FieldValue, TypePath, }; impl Visitor<'_> { pub(crate) fn process_hdl_array( &mut self, - hdl_attr: HdlAttr, + hdl_attr: HdlAttr, mut expr_array: ExprArray, ) -> Expr { - let ExprOptions { sim } = hdl_attr.body; - let span = hdl_attr.kw.span; - if sim.is_some() { - for elem in &mut expr_array.elems { - *elem = parse_quote_spanned! {elem.span()=> - ::fayalite::sim::value::ToSimValue::to_sim_value(&(#elem)) - }; - } - parse_quote_spanned! {span=> - ::fayalite::sim::value::ToSimValue::into_sim_value(#expr_array) - } - } else { - for elem in &mut expr_array.elems { - *elem = parse_quote_spanned! {elem.span()=> - ::fayalite::expr::ToExpr::to_expr(&(#elem)) - }; - } - parse_quote_spanned! {span=> - ::fayalite::expr::ToExpr::to_expr(&#expr_array) - } + self.require_normal_module_or_fn(hdl_attr); + for elem in &mut expr_array.elems { + *elem = parse_quote_spanned! {elem.span()=> + ::fayalite::expr::ToExpr::to_expr(&(#elem)) + }; } + parse_quote! {::fayalite::expr::ToExpr::to_expr(&#expr_array)} } pub(crate) fn process_hdl_repeat( &mut self, - hdl_attr: HdlAttr, + hdl_attr: HdlAttr, mut expr_repeat: ExprRepeat, ) -> Expr { + self.require_normal_module_or_fn(hdl_attr); let repeated_value = &expr_repeat.expr; - let ExprOptions { sim } = hdl_attr.body; - let span = hdl_attr.kw.span; - if sim.is_some() { - *expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=> - ::fayalite::sim::value::ToSimValue::to_sim_value(&(#repeated_value)) - }; - parse_quote_spanned! {span=> - ::fayalite::sim::value::ToSimValue::into_sim_value(#expr_repeat) - } - } else { - *expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=> - ::fayalite::expr::ToExpr::to_expr(&(#repeated_value)) - }; - parse_quote_spanned! {span=> - ::fayalite::expr::ToExpr::to_expr(&#expr_repeat) - } - } + *expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=> + ::fayalite::expr::ToExpr::to_expr(&(#repeated_value)) + }; + parse_quote! {::fayalite::expr::ToExpr::to_expr(&#expr_repeat)} } pub(crate) fn process_hdl_struct( &mut self, - hdl_attr: HdlAttr, - mut expr_struct: ExprStruct, + hdl_attr: HdlAttr, + expr_struct: ExprStruct, ) -> Expr { + self.require_normal_module_or_fn(&hdl_attr); let name_span = expr_struct.path.segments.last().unwrap().ident.span(); - let ExprOptions { sim } = hdl_attr.body; - if sim.is_some() { - let ty_path = TypePath { - qself: expr_struct.qself.take(), - path: expr_struct.path, - }; - expr_struct.path = parse_quote_spanned! {name_span=> - __SimValue::<#ty_path> - }; - for field in &mut expr_struct.fields { - let expr = &field.expr; - field.expr = parse_quote_spanned! {field.member.span()=> - ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr)) - }; - } - return parse_quote_spanned! {name_span=> - { - type __SimValue = ::SimValue; - let value: ::fayalite::sim::value::SimValue<#ty_path> = ::fayalite::sim::value::ToSimValue::into_sim_value(#expr_struct); - value - } - }; - } let builder_ident = format_ident!("__builder", span = name_span); let empty_builder = if expr_struct.qself.is_some() || expr_struct @@ -148,126 +91,12 @@ impl Visitor<'_> { } pub(crate) fn process_hdl_tuple( &mut self, - hdl_attr: HdlAttr, - mut expr_tuple: ExprTuple, + hdl_attr: HdlAttr, + expr_tuple: ExprTuple, ) -> Expr { - let ExprOptions { sim } = hdl_attr.body; - if sim.is_some() { - for element in &mut expr_tuple.elems { - *element = parse_quote_spanned! {element.span()=> - &(#element) - }; - } - parse_quote_spanned! {expr_tuple.span()=> - ::fayalite::sim::value::ToSimValue::into_sim_value(#expr_tuple) - } - } else { - parse_quote_spanned! {expr_tuple.span()=> - ::fayalite::expr::ToExpr::to_expr(&#expr_tuple) - } + self.require_normal_module_or_fn(hdl_attr); + parse_quote_spanned! {expr_tuple.span()=> + ::fayalite::expr::ToExpr::to_expr(&#expr_tuple) } } - pub(crate) fn process_hdl_call( - &mut self, - hdl_attr: HdlAttr, - mut expr_call: ExprCall, - ) -> Expr { - let span = hdl_attr.kw.span; - let mut func = &mut *expr_call.func; - let EnumPath { - variant_path: _, - enum_path, - variant_name, - } = loop { - match func { - Expr::Group(ExprGroup { expr, .. }) | Expr::Paren(ExprParen { expr, .. }) => { - func = &mut **expr; - } - Expr::Path(_) => { - let Expr::Path(ExprPath { attrs, qself, path }) = - mem::replace(func, Expr::PLACEHOLDER) - else { - unreachable!(); - }; - match parse_enum_path(TypePath { qself, path }) { - Ok(path) => break path, - Err(path) => { - self.errors.error(&path, "unsupported enum variant path"); - let TypePath { qself, path } = path; - *func = ExprPath { attrs, qself, path }.into(); - return expr_call.into(); - } - } - } - _ => { - self.errors.error( - &expr_call.func, - "#[hdl] function call -- function must be a possibly-parenthesized path", - ); - return expr_call.into(); - } - } - }; - self.process_hdl_method_call( - hdl_attr, - ExprMethodCall { - attrs: expr_call.attrs, - receiver: parse_quote_spanned! {span=> - <#enum_path as ::fayalite::ty::StaticType>::TYPE - }, - dot_token: Token![.](span), - method: variant_name, - turbofish: None, - paren_token: expr_call.paren_token, - args: expr_call.args, - }, - ) - } - pub(crate) fn process_hdl_method_call( - &mut self, - hdl_attr: HdlAttr, - mut expr_method_call: ExprMethodCall, - ) -> Expr { - let ExprOptions { sim } = hdl_attr.body; - let span = hdl_attr.kw.span; - // remove any number of groups and up to one paren - let mut receiver = &mut *expr_method_call.receiver; - let mut has_group = false; - let receiver = loop { - match receiver { - Expr::Group(ExprGroup { expr, .. }) => { - has_group = true; - receiver = expr; - } - Expr::Paren(ExprParen { expr, .. }) => break &mut **expr, - receiver @ Expr::Path(_) => break receiver, - _ => { - if !has_group { - self.errors.error( - &expr_method_call.receiver, - "#[hdl] on a method call needs parenthesized receiver", - ); - } - break &mut *expr_method_call.receiver; - } - } - }; - let func = if sim.is_some() { - parse_quote_spanned! {span=> - ::fayalite::enum_::enum_type_to_sim_builder - } - } else { - parse_quote_spanned! {span=> - ::fayalite::enum_::assert_is_enum_type - } - }; - *expr_method_call.receiver = ExprCall { - attrs: vec![], - func, - paren_token: Paren(span), - args: Punctuated::from_iter([mem::replace(receiver, Expr::PLACEHOLDER)]), - } - .into(); - expr_method_call.into() - } } diff --git a/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs b/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs index 069f00d..1d53104 100644 --- a/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs +++ b/crates/fayalite-proc-macros-impl/src/module/transform_body/expand_match.rs @@ -1,121 +1,24 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ - Errors, HdlAttr, PairsIterExt, - fold::{DoFold, impl_fold}, + fold::{impl_fold, DoFold}, kw, - module::transform_body::{ - ExprOptions, Visitor, empty_let, with_debug_clone_and_fold, wrap_ty_with_expr, - }, + module::transform_body::{with_debug_clone_and_fold, Visitor}, + Errors, HdlAttr, PairsIterExt, }; use proc_macro2::{Span, TokenStream}; -use quote::{ToTokens, TokenStreamExt, format_ident, quote_spanned}; -use std::collections::BTreeSet; +use quote::{format_ident, quote_spanned, ToTokens, TokenStreamExt}; use syn::{ - Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Local, Member, Pat, PatIdent, PatOr, - PatParen, PatPath, PatRest, PatStruct, PatTuple, PatTupleStruct, PatWild, Path, PathSegment, - Token, TypePath, - fold::{Fold, fold_arm, fold_expr_match, fold_local, fold_pat}, + fold::{fold_arm, fold_expr_match, fold_pat, Fold}, + parse::Nothing, parse_quote_spanned, punctuated::Punctuated, spanned::Spanned, token::{Brace, Paren}, + Arm, Attribute, Expr, ExprMatch, FieldPat, Ident, Member, Pat, PatIdent, PatOr, PatParen, + PatPath, PatRest, PatStruct, PatTupleStruct, PatWild, Path, PathSegment, Token, TypePath, }; -macro_rules! visit_trait { - ( - $($vis:vis fn $fn:ident($state:ident: _, $value:ident: &$Value:ty) $block:block)* - ) => { - trait VisitMatchPat<'a> { - $(fn $fn(&mut self, $value: &'a $Value) { - $fn(self, $value); - })* - } - - $($vis fn $fn<'a>($state: &mut (impl ?Sized + VisitMatchPat<'a>), $value: &'a $Value) $block)* - }; -} - -visit_trait! { - fn visit_match_pat_binding(_state: _, v: &MatchPatBinding) { - let MatchPatBinding { ident: _ } = v; - } - fn visit_match_pat_wild(_state: _, v: &MatchPatWild) { - let MatchPatWild { underscore_token: _ } = v; - } - fn visit_match_pat_rest(_state: _, v: &MatchPatRest) { - let MatchPatRest { dot2_token: _ } = v; - } - fn visit_match_pat_paren(state: _, v: &MatchPatParen) { - let MatchPatParen { paren_token: _, pat } = v; - state.visit_match_pat(pat); - } - fn visit_match_pat_paren_simple(state: _, v: &MatchPatParen) { - let MatchPatParen { paren_token: _, pat } = v; - state.visit_match_pat_simple(pat); - } - fn visit_match_pat_or(state: _, v: &MatchPatOr) { - let MatchPatOr { leading_vert: _, cases } = v; - for v in cases { - state.visit_match_pat(v); - } - } - fn visit_match_pat_or_simple(state: _, v: &MatchPatOr) { - let MatchPatOr { leading_vert: _, cases } = v; - for v in cases { - state.visit_match_pat_simple(v); - } - } - fn visit_match_pat_struct_field(state: _, v: &MatchPatStructField) { - let MatchPatStructField { field_name: _, colon_token: _, pat } = v; - state.visit_match_pat_simple(pat); - } - fn visit_match_pat_struct(state: _, v: &MatchPatStruct) { - let MatchPatStruct { match_span: _, path: _, brace_token: _, fields, rest: _ } = v; - for v in fields { - state.visit_match_pat_struct_field(v); - } - } - fn visit_match_pat_tuple(state: _, v: &MatchPatTuple) { - let MatchPatTuple { paren_token: _, fields } = v; - for v in fields { - state.visit_match_pat_simple(v); - } - } - fn visit_match_pat_enum_variant(state: _, v: &MatchPatEnumVariant) { - let MatchPatEnumVariant { - match_span:_, - sim:_, - variant_path: _, - enum_path: _, - variant_name: _, - field, - } = v; - if let Some((_, v)) = field { - state.visit_match_pat_simple(v); - } - } - fn visit_match_pat_simple(state: _, v: &MatchPatSimple) { - match v { - MatchPatSimple::Paren(v) => state.visit_match_pat_paren_simple(v), - MatchPatSimple::Or(v) => state.visit_match_pat_or_simple(v), - MatchPatSimple::Binding(v) => state.visit_match_pat_binding(v), - MatchPatSimple::Wild(v) => state.visit_match_pat_wild(v), - MatchPatSimple::Rest(v) => state.visit_match_pat_rest(v), - } - } - fn visit_match_pat(state: _, v: &MatchPat) { - match v { - MatchPat::Simple(v) => state.visit_match_pat_simple(v), - MatchPat::Or(v) => state.visit_match_pat_or(v), - MatchPat::Paren(v) => state.visit_match_pat_paren(v), - MatchPat::Struct(v) => state.visit_match_pat_struct(v), - MatchPat::Tuple(v) => state.visit_match_pat_tuple(v), - MatchPat::EnumVariant(v) => state.visit_match_pat_enum_variant(v), - } - } -} - with_debug_clone_and_fold! { struct MatchPatBinding<> { ident: Ident, @@ -150,15 +53,6 @@ with_debug_clone_and_fold! { } } -impl

MatchPatOr

{ - /// returns the first `|` between two patterns - fn first_inner_vert(&self) -> Option { - let mut pairs = self.cases.pairs(); - pairs.next_back(); - pairs.next().and_then(|v| v.into_tuple().1.copied()) - } -} - impl ToTokens for MatchPatOr

{ fn to_tokens(&self, tokens: &mut TokenStream) { let Self { @@ -183,19 +77,6 @@ impl ToTokens for MatchPatWild { } } -with_debug_clone_and_fold! { - struct MatchPatRest<> { - dot2_token: Token![..], - } -} - -impl ToTokens for MatchPatRest { - fn to_tokens(&self, tokens: &mut TokenStream) { - let Self { dot2_token } = self; - dot2_token.to_tokens(tokens); - } -} - with_debug_clone_and_fold! { struct MatchPatStructField<> { field_name: Ident, @@ -278,29 +159,9 @@ impl ToTokens for MatchPatStruct { } } -with_debug_clone_and_fold! { - struct MatchPatTuple<> { - paren_token: Paren, - fields: Punctuated, - } -} - -impl ToTokens for MatchPatTuple { - fn to_tokens(&self, tokens: &mut TokenStream) { - let Self { - paren_token, - fields, - } = self; - paren_token.surround(tokens, |tokens| { - fields.to_tokens(tokens); - }) - } -} - with_debug_clone_and_fold! { struct MatchPatEnumVariant<> { match_span: Span, - sim: Option<(kw::sim,)>, variant_path: Path, enum_path: Path, variant_name: Ident, @@ -312,7 +173,6 @@ impl ToTokens for MatchPatEnumVariant { fn to_tokens(&self, tokens: &mut TokenStream) { let Self { match_span, - sim, variant_path: _, enum_path, variant_name, @@ -322,28 +182,7 @@ impl ToTokens for MatchPatEnumVariant { __MatchTy::<#enum_path>::#variant_name } .to_tokens(tokens); - if sim.is_some() { - if let Some((paren_token, field)) = field { - paren_token.surround(tokens, |tokens| { - field.to_tokens(tokens); - match field { - MatchPatSimple::Paren(_) - | MatchPatSimple::Or(_) - | MatchPatSimple::Binding(_) - | MatchPatSimple::Wild(_) => quote_spanned! {*match_span=> - , _ - } - .to_tokens(tokens), - MatchPatSimple::Rest(_) => {} - } - }); - } else { - quote_spanned! {*match_span=> - (_) - } - .to_tokens(tokens); - } - } else if let Some((paren_token, field)) = field { + if let Some((paren_token, field)) = field { paren_token.surround(tokens, |tokens| field.to_tokens(tokens)); } } @@ -355,7 +194,6 @@ enum MatchPatSimple { Or(MatchPatOr), Binding(MatchPatBinding), Wild(MatchPatWild), - Rest(MatchPatRest), } impl_fold! { @@ -364,7 +202,6 @@ impl_fold! { Or(MatchPatOr), Binding(MatchPatBinding), Wild(MatchPatWild), - Rest(MatchPatRest), } } @@ -375,18 +212,17 @@ impl ToTokens for MatchPatSimple { Self::Paren(v) => v.to_tokens(tokens), Self::Binding(v) => v.to_tokens(tokens), Self::Wild(v) => v.to_tokens(tokens), - Self::Rest(v) => v.to_tokens(tokens), } } } -pub(crate) struct EnumPath { - pub(crate) variant_path: Path, - pub(crate) enum_path: Path, - pub(crate) variant_name: Ident, +struct EnumPath { + variant_path: Path, + enum_path: Path, + variant_name: Ident, } -pub(crate) fn parse_enum_path(variant_path: TypePath) -> Result { +fn parse_enum_path(variant_path: TypePath) -> Result { let TypePath { qself: None, path: variant_path, @@ -442,9 +278,8 @@ trait ParseMatchPat: Sized { fn or(v: MatchPatOr) -> Self; fn paren(v: MatchPatParen) -> Self; fn struct_(state: &mut HdlMatchParseState<'_>, v: MatchPatStruct) -> Result; - fn tuple(state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result; fn enum_variant(state: &mut HdlMatchParseState<'_>, v: MatchPatEnumVariant) - -> Result; + -> Result; fn parse(state: &mut HdlMatchParseState<'_>, pat: Pat) -> Result { match pat { Pat::Ident(PatIdent { @@ -478,7 +313,6 @@ trait ParseMatchPat: Sized { state, MatchPatEnumVariant { match_span: state.match_span, - sim: state.sim, variant_path, enum_path, variant_name, @@ -525,7 +359,6 @@ trait ParseMatchPat: Sized { state, MatchPatEnumVariant { match_span: state.match_span, - sim: state.sim, variant_path, enum_path, variant_name, @@ -610,7 +443,6 @@ trait ParseMatchPat: Sized { state, MatchPatEnumVariant { match_span: state.match_span, - sim: state.sim, variant_path, enum_path, variant_name, @@ -630,34 +462,7 @@ trait ParseMatchPat: Sized { }) => Ok(Self::simple(MatchPatSimple::Wild(MatchPatWild { underscore_token, }))), - Pat::Tuple(PatTuple { - attrs: _, - paren_token, - elems, - }) => { - let fields = elems - .into_pairs() - .filter_map_pair_value(|field_pat| { - if let Pat::Rest(PatRest { - attrs: _, - dot2_token, - }) = field_pat - { - Some(MatchPatSimple::Rest(MatchPatRest { dot2_token })) - } else { - MatchPatSimple::parse(state, field_pat).ok() - } - }) - .collect(); - Self::tuple( - state, - MatchPatTuple { - paren_token, - fields, - }, - ) - } - Pat::Slice(_) | Pat::Const(_) | Pat::Lit(_) | Pat::Range(_) => { + Pat::Tuple(_) | Pat::Slice(_) | Pat::Const(_) | Pat::Lit(_) | Pat::Range(_) => { state .errors .error(pat, "not yet implemented in #[hdl] patterns"); @@ -692,14 +497,6 @@ impl ParseMatchPat for MatchPatSimple { Err(()) } - fn tuple(state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result { - state.errors.push(syn::Error::new( - v.paren_token.span.open(), - "matching tuples is not yet implemented inside structs/enums in #[hdl] patterns", - )); - Err(()) - } - fn enum_variant( state: &mut HdlMatchParseState<'_>, v: MatchPatEnumVariant, @@ -718,7 +515,6 @@ enum MatchPat { Or(MatchPatOr), Paren(MatchPatParen), Struct(MatchPatStruct), - Tuple(MatchPatTuple), EnumVariant(MatchPatEnumVariant), } @@ -728,7 +524,6 @@ impl_fold! { Or(MatchPatOr), Paren(MatchPatParen), Struct(MatchPatStruct), - Tuple(MatchPatTuple), EnumVariant(MatchPatEnumVariant), } } @@ -750,10 +545,6 @@ impl ParseMatchPat for MatchPat { Ok(Self::Struct(v)) } - fn tuple(_state: &mut HdlMatchParseState<'_>, v: MatchPatTuple) -> Result { - Ok(Self::Tuple(v)) - } - fn enum_variant( _state: &mut HdlMatchParseState<'_>, v: MatchPatEnumVariant, @@ -769,7 +560,6 @@ impl ToTokens for MatchPat { Self::Or(v) => v.to_tokens(tokens), Self::Paren(v) => v.to_tokens(tokens), Self::Struct(v) => v.to_tokens(tokens), - Self::Tuple(v) => v.to_tokens(tokens), Self::EnumVariant(v) => v.to_tokens(tokens), } } @@ -832,6 +622,10 @@ struct RewriteAsCheckMatch { } impl Fold for RewriteAsCheckMatch { + fn fold_field_pat(&mut self, mut i: FieldPat) -> FieldPat { + i.colon_token = Some(Token![:](i.member.span())); + i + } fn fold_pat(&mut self, pat: Pat) -> Pat { match pat { Pat::Ident(mut pat_ident) => match parse_enum_ident(pat_ident.ident) { @@ -946,177 +740,17 @@ impl Fold for RewriteAsCheckMatch { // don't recurse into expressions i } - fn fold_local(&mut self, mut let_stmt: Local) -> Local { - if let Some(syn::LocalInit { - eq_token, - expr: _, - diverge, - }) = let_stmt.init.take() - { - let_stmt.init = Some(syn::LocalInit { - eq_token, - expr: parse_quote_spanned! {self.span=> - __match_value - }, - diverge: diverge.map(|(else_, _expr)| { - ( - else_, - parse_quote_spanned! {self.span=> - match __infallible {} - }, - ) - }), - }); - } - fold_local(self, let_stmt) - } } struct HdlMatchParseState<'a> { - sim: Option<(kw::sim,)>, match_span: Span, errors: &'a mut Errors, } -struct HdlLetPatVisitState<'a> { - errors: &'a mut Errors, - bindings: BTreeSet<&'a Ident>, -} - -impl<'a> VisitMatchPat<'a> for HdlLetPatVisitState<'a> { - fn visit_match_pat_binding(&mut self, v: &'a MatchPatBinding) { - self.bindings.insert(&v.ident); - } - - fn visit_match_pat_or(&mut self, v: &'a MatchPatOr) { - if let Some(first_inner_vert) = v.first_inner_vert() { - self.errors.error( - first_inner_vert, - "or-patterns are not supported in let statements", - ); - } - visit_match_pat_or(self, v); - } - - fn visit_match_pat_or_simple(&mut self, v: &'a MatchPatOr) { - if let Some(first_inner_vert) = v.first_inner_vert() { - self.errors.error( - first_inner_vert, - "or-patterns are not supported in let statements", - ); - } - visit_match_pat_or_simple(self, v); - } - - fn visit_match_pat_enum_variant(&mut self, v: &'a MatchPatEnumVariant) { - self.errors.error(v, "refutable pattern in let statement"); - } -} - impl Visitor<'_> { - pub(crate) fn process_hdl_let_pat( - &mut self, - hdl_attr: HdlAttr, - mut let_stmt: Local, - ) -> Local { - let span = let_stmt.let_token.span(); - let ExprOptions { sim } = hdl_attr.body; - if let Pat::Type(pat) = &mut let_stmt.pat { - *pat.ty = wrap_ty_with_expr((*pat.ty).clone()); - } - let check_let_stmt = RewriteAsCheckMatch { span }.fold_local(let_stmt.clone()); - let Local { - attrs: _, - let_token, - pat, - init, - semi_token, - } = let_stmt; - let Some(syn::LocalInit { - eq_token, - expr, - diverge, - }) = init - else { - self.errors - .error(let_token, "#[hdl] let must be assigned a value"); - return empty_let(); - }; - if let Some((else_, _)) = diverge { - // TODO: implement let-else - self.errors - .error(else_, "#[hdl] let ... else { ... } is not implemented"); - return empty_let(); - } - let Ok(pat) = MatchPat::parse( - &mut HdlMatchParseState { - sim, - match_span: span, - errors: &mut self.errors, - }, - pat, - ) else { - return empty_let(); - }; - let mut state = HdlLetPatVisitState { - errors: &mut self.errors, - bindings: BTreeSet::new(), - }; - state.visit_match_pat(&pat); - let HdlLetPatVisitState { - errors: _, - bindings, - } = state; - let retval = if sim.is_some() { - parse_quote_spanned! {span=> - let (#(#bindings,)*) = { - type __MatchTy = ::SimValue; - let __match_value = ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr)); - #let_token #pat #eq_token ::fayalite::sim::value::SimValue::into_value(__match_value) #semi_token - (#(#bindings,)*) - }; - } - } else { - parse_quote_spanned! {span=> - let (#(#bindings,)* __scope,) = { - type __MatchTy = ::MatchVariant; - let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr)); - ::fayalite::expr::check_match_expr( - __match_expr, - |__match_value, __infallible| { - #[allow(unused_variables)] - #check_let_stmt - match __infallible {} - }, - ); - let mut __match_iter = ::fayalite::module::match_(__match_expr); - let ::fayalite::__std::option::Option::Some(__match_variant) = - ::fayalite::__std::iter::Iterator::next(&mut __match_iter) - else { - ::fayalite::__std::unreachable!("#[hdl] let with uninhabited type"); - }; - let ::fayalite::__std::option::Option::None = - ::fayalite::__std::iter::Iterator::next(&mut __match_iter) - else { - ::fayalite::__std::unreachable!("#[hdl] let with refutable pattern"); - }; - let (__match_variant, __scope) = - ::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope( - __match_variant, - ); - #let_token #pat #eq_token __match_variant #semi_token - (#(#bindings,)* __scope,) - }; - } - }; - match retval { - syn::Stmt::Local(retval) => retval, - _ => unreachable!(), - } - } pub(crate) fn process_hdl_match( &mut self, - hdl_attr: HdlAttr, + _hdl_attr: HdlAttr, expr_match: ExprMatch, ) -> Expr { let span = expr_match.match_token.span(); @@ -1128,9 +762,8 @@ impl Visitor<'_> { brace_token: _, arms, } = expr_match; - let ExprOptions { sim } = hdl_attr.body; + self.require_normal_module_or_fn(match_token); let mut state = HdlMatchParseState { - sim, match_span: span, errors: &mut self.errors, }; @@ -1138,36 +771,24 @@ impl Visitor<'_> { arms.into_iter() .filter_map(|arm| MatchArm::parse(&mut state, arm).ok()), ); - let expr = if sim.is_some() { - quote_spanned! {span=> - { - type __MatchTy = ::SimValue; - let __match_expr = ::fayalite::sim::value::ToSimValue::to_sim_value(&(#expr)); - #match_token ::fayalite::sim::value::SimValue::into_value(__match_expr) { + let expr = quote_spanned! {span=> + { + type __MatchTy = ::MatchVariant; + let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr)); + ::fayalite::expr::check_match_expr(__match_expr, |__match_value, __infallible| { + #[allow(unused_variables)] + #check_match + }); + for __match_variant in ::fayalite::module::match_(__match_expr) { + let (__match_variant, __scope) = + ::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope( + __match_variant, + ); + #match_token __match_variant { #(#arms)* } } } - } else { - quote_spanned! {span=> - { - type __MatchTy = ::MatchVariant; - let __match_expr = ::fayalite::expr::ToExpr::to_expr(&(#expr)); - ::fayalite::expr::check_match_expr(__match_expr, |__match_value, __infallible| { - #[allow(unused_variables)] - #check_match - }); - for __match_variant in ::fayalite::module::match_(__match_expr) { - let (__match_variant, __scope) = - ::fayalite::ty::MatchVariantAndInactiveScope::match_activate_scope( - __match_variant, - ); - #match_token __match_variant { - #(#arms)* - } - } - } - } }; syn::parse2(expr).unwrap() } diff --git a/crates/fayalite-proc-macros-impl/src/process_cfg.rs b/crates/fayalite-proc-macros-impl/src/process_cfg.rs index bcf2fa1..5cff08f 100644 --- a/crates/fayalite-proc-macros-impl/src/process_cfg.rs +++ b/crates/fayalite-proc-macros-impl/src/process_cfg.rs @@ -5,8 +5,8 @@ use crate::{Cfg, CfgAttr, Cfgs, Errors}; use proc_macro2::Ident; use std::{collections::VecDeque, marker::PhantomData}; use syn::{ - Token, punctuated::{Pair, Punctuated}, + Token, }; struct State { @@ -131,9 +131,9 @@ trait PhaseDispatch { type Args; type Output; fn dispatch_collect(self, args: Self::Args) - -> Self::Output; + -> Self::Output; fn dispatch_process(self, args: Self::Args) - -> Self::Output; + -> Self::Output; } trait Phase: Sized + 'static { @@ -2510,7 +2510,7 @@ pub(crate) fn process_cfgs(item: syn::Item, cfgs: Cfgs) -> syn::Result) { - let clk_input = - platform_io_builder.peripherals_with_type::()[0].use_peripheral(); - let rst = platform_io_builder.peripherals_with_type::()[0].use_peripheral(); +fn blinky(clock_frequency: u64) { + #[hdl] + let clk: Clock = m.input(); + #[hdl] + let rst: SyncReset = m.input(); let cd = #[hdl] ClockDomain { - clk: clk_input.clk, - rst, + clk, + rst: rst.to_reset(), }; - let max_value = (Expr::ty(clk_input).frequency() / 2.0).round_ties_even() as u64 - 1; + let max_value = clock_frequency / 2 - 1; let int_ty = UInt::range_inclusive(0..=max_value); #[hdl] let counter_reg: UInt = reg_builder().clock_domain(cd).reset(0u8.cast_to(int_ty)); #[hdl] let output_reg: Bool = reg_builder().clock_domain(cd).reset(false); #[hdl] - let rgb_output_reg = reg_builder().clock_domain(cd).reset( - #[hdl] - peripherals::RgbLed { - r: false, - g: false, - b: false, - }, - ); - #[hdl] if counter_reg.cmp_eq(max_value) { connect_any(counter_reg, 0u8); connect(output_reg, !output_reg); - connect(rgb_output_reg.r, !rgb_output_reg.r); - #[hdl] - if rgb_output_reg.r { - connect(rgb_output_reg.g, !rgb_output_reg.g); - #[hdl] - if rgb_output_reg.g { - connect(rgb_output_reg.b, !rgb_output_reg.b); - } - } } else { connect_any(counter_reg, counter_reg + 1_hdl_u1); } - for led in platform_io_builder.peripherals_with_type::() { - if let Ok(led) = led.try_use_peripheral() { - connect(led.on, output_reg); - } - } - for rgb_led in platform_io_builder.peripherals_with_type::() { - if let Ok(rgb_led) = rgb_led.try_use_peripheral() { - connect(rgb_led, rgb_output_reg); - } - } #[hdl] - let io = m.add_platform_io(platform_io_builder); + let led: Bool = m.output(); + connect(led, output_reg); } -fn main() { - ::main("blinky", |_, platform, _| { - Ok(JobParams::new(platform.wrap_main_module(blinky))) - }); +#[derive(Parser)] +struct Cli { + /// clock frequency in hertz + #[arg(long, default_value = "1000000", value_parser = clap::value_parser!(u64).range(2..))] + clock_frequency: u64, + #[command(subcommand)] + cli: cli::Cli, +} + +fn main() -> cli::Result { + let cli = Cli::parse(); + cli.cli.run(blinky(cli.clock_frequency)) } diff --git a/crates/fayalite/examples/tx_only_uart.rs b/crates/fayalite/examples/tx_only_uart.rs deleted file mode 100644 index 5c20b39..0000000 --- a/crates/fayalite/examples/tx_only_uart.rs +++ /dev/null @@ -1,188 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information -use clap::builder::TypedValueParser; -use fayalite::{ - build::{ToArgs, WriteArgs}, - platform::PeripheralRef, - prelude::*, -}; -use ordered_float::NotNan; - -fn pick_clock<'a>( - platform_io_builder: &PlatformIOBuilder<'a>, -) -> PeripheralRef<'a, peripherals::ClockInput> { - let mut clks = platform_io_builder.peripherals_with_type::(); - clks.sort_by_key(|clk| { - // sort clocks by preference, smaller return values means higher preference - let mut frequency = clk.ty().frequency(); - let priority; - if frequency < 10e6 { - frequency = -frequency; // prefer bigger frequencies - priority = 1; - } else if frequency > 50e6 { - // prefer smaller frequencies - priority = 2; // least preferred - } else { - priority = 0; // most preferred - frequency = (frequency - 25e6).abs(); // prefer closer to 25MHz - } - (priority, NotNan::new(frequency).expect("should be valid")) - }); - clks[0] -} - -#[hdl_module] -fn tx_only_uart( - platform_io_builder: PlatformIOBuilder<'_>, - divisor: f64, - message: impl AsRef<[u8]>, -) { - let message = message.as_ref(); - let clk_input = pick_clock(&platform_io_builder).use_peripheral(); - let rst = platform_io_builder.peripherals_with_type::()[0].use_peripheral(); - let cd = #[hdl] - ClockDomain { - clk: clk_input.clk, - rst, - }; - let numerator = 1u128 << 16; - let denominator = (divisor * numerator as f64).round() as u128; - - #[hdl] - let remainder_reg: UInt<128> = reg_builder().clock_domain(cd).reset(0u128); - - #[hdl] - let sum: UInt<128> = wire(); - connect_any(sum, remainder_reg + numerator); - - #[hdl] - let tick_reg = reg_builder().clock_domain(cd).reset(false); - connect(tick_reg, false); - - #[hdl] - let next_remainder: UInt<128> = wire(); - connect(remainder_reg, next_remainder); - - #[hdl] - if sum.cmp_ge(denominator) { - connect_any(next_remainder, sum - denominator); - connect(tick_reg, true); - } else { - connect(next_remainder, sum); - } - - #[hdl] - let uart_state_reg = reg_builder().clock_domain(cd).reset(0_hdl_u4); - #[hdl] - let next_uart_state: UInt<4> = wire(); - - connect_any(next_uart_state, uart_state_reg + 1u8); - - #[hdl] - let message_mem: Array> = wire(Array[UInt::new_static()][message.len()]); - for (message, message_mem) in message.iter().zip(message_mem) { - connect(message_mem, *message); - } - #[hdl] - let addr_reg: UInt<32> = reg_builder().clock_domain(cd).reset(0u32); - #[hdl] - let next_addr: UInt<32> = wire(); - connect(next_addr, addr_reg); - - #[hdl] - let tx = reg_builder().clock_domain(cd).reset(true); - - #[hdl] - let tx_bits: Array = wire(); - - connect(tx_bits[0], false); // start bit - connect(tx_bits[9], true); // stop bit - - for i in 0..8 { - connect(tx_bits[i + 1], message_mem[addr_reg][i]); // data bits - } - - connect(tx, tx_bits[uart_state_reg]); - - #[hdl] - if uart_state_reg.cmp_eq(Expr::ty(tx_bits).len() - 1) { - connect(next_uart_state, 0_hdl_u4); - let next_addr_val = addr_reg + 1u8; - #[hdl] - if next_addr_val.cmp_lt(message.len()) { - connect_any(next_addr, next_addr_val); - } else { - connect(next_addr, 0u32); - } - } - - #[hdl] - if tick_reg { - connect(uart_state_reg, next_uart_state); - connect(addr_reg, next_addr); - } - - for uart in platform_io_builder.peripherals_with_type::() { - connect(uart.use_peripheral().tx, tx); - } - - #[hdl] - let io = m.add_platform_io(platform_io_builder); -} - -fn parse_baud_rate( - v: impl AsRef, -) -> Result, Box> { - let retval: NotNan = v - .as_ref() - .parse() - .map_err(|_| "invalid baud rate, must be a finite positive floating-point value")?; - if *retval > 0.0 && retval.is_finite() { - Ok(retval) - } else { - Err("baud rate must be finite and positive".into()) - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)] -pub struct ExtraArgs { - #[arg(long, value_parser = clap::builder::StringValueParser::new().try_map(parse_baud_rate), default_value = "115200")] - pub baud_rate: NotNan, - #[arg(long, default_value = "Hello World from Fayalite!!!\r\n", value_parser = clap::builder::NonEmptyStringValueParser::new())] - pub message: String, -} - -impl ToArgs for ExtraArgs { - fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) { - let Self { baud_rate, message } = self; - args.write_display_arg(format_args!("--baud-rate={baud_rate}")); - args.write_long_option_eq("message", message); - } -} - -fn main() { - type Cli = BuildCli; - Cli::main( - "tx_only_uart", - |_, platform, ExtraArgs { baud_rate, message }| { - Ok(JobParams::new(platform.try_wrap_main_module(|io| { - let clk = pick_clock(&io).ty(); - let divisor = clk.frequency() / *baud_rate; - let baud_rate_error = |msg| { - ::command() - .error(clap::error::ErrorKind::ValueValidation, msg) - }; - const HUGE_DIVISOR: f64 = u64::MAX as f64; - match divisor { - divisor if !divisor.is_finite() => { - return Err(baud_rate_error("bad baud rate")); - } - HUGE_DIVISOR.. => return Err(baud_rate_error("baud rate is too small")), - 4.0.. => {} - _ => return Err(baud_rate_error("baud rate is too large")), - } - Ok(tx_only_uart(io, divisor, message)) - })?)) - }, - ); -} diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements.rs index 229871b..61d29b5 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements.rs @@ -2,7 +2,6 @@ // See Notices.txt for copyright information //! ## `#[hdl] let` statements -pub mod destructuring; pub mod inputs_outputs; pub mod instances; pub mod memories; diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs deleted file mode 100644 index 1fc4705..0000000 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_let_statements/destructuring.rs +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information -//! ### Destructuring Let -//! -//! You can use `#[hdl] let` to destructure types, similarly to Rust `let` statements with non-trivial patterns. -//! -//! `#[hdl] let` statements can only match one level of struct/tuple pattern for now, -//! e.g. you can match with the pattern `MyStruct { a, b }`, but not `MyStruct { a, b: Struct2 { v } }`. -//! -//! ``` -//! # use fayalite::prelude::*; -//! #[hdl] -//! struct MyStruct { -//! a: UInt<8>, -//! b: Bool, -//! } -//! -//! #[hdl_module] -//! fn my_module() { -//! #[hdl] -//! let my_input: MyStruct = m.input(); -//! #[hdl] -//! let my_output: UInt<8> = m.input(); -//! #[hdl] -//! let MyStruct { a, b } = my_input; -//! #[hdl] -//! if b { -//! connect(my_output, a); -//! } else { -//! connect(my_output, 0_hdl_u8); -//! } -//! } -//! ``` diff --git a/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs b/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs index 6df70f1..9e6c511 100644 --- a/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs +++ b/crates/fayalite/src/_docs/modules/module_bodies/hdl_match_statements.rs @@ -7,5 +7,5 @@ //! //! `#[hdl] match` statements' bodies must evaluate to type `()` for now. //! -//! `#[hdl] match` statements can only match one level of struct/tuple/enum pattern for now, +//! `#[hdl] match` statements can only match one level of struct/enum pattern for now, //! e.g. you can match with the pattern `HdlSome(v)`, but not `HdlSome(HdlSome(_))`. diff --git a/crates/fayalite/src/annotations.rs b/crates/fayalite/src/annotations.rs index 4ca84dd..8eff4a0 100644 --- a/crates/fayalite/src/annotations.rs +++ b/crates/fayalite/src/annotations.rs @@ -12,7 +12,7 @@ use std::{ ops::Deref, }; -#[derive(Clone, Debug)] +#[derive(Clone)] struct CustomFirrtlAnnotationFieldsImpl { value: serde_json::Map, serialized: Interned, @@ -145,73 +145,52 @@ pub struct DocStringAnnotation { macro_rules! make_annotation_enum { ( - #[$non_exhaustive:ident] $(#[$meta:meta])* - $vis:vis enum $AnnotationEnum:ident { - $($Variant:ident($T:ty),)* + $vis:vis enum $Annotation:ident { + $($Variant:ident($T:ident),)* } ) => { - crate::annotations::make_annotation_enum!(@require_non_exhaustive $non_exhaustive); - - #[$non_exhaustive] $(#[$meta])* - #[derive(Clone, PartialEq, Eq, Hash)] - $vis enum $AnnotationEnum { + $vis enum $Annotation { $($Variant($T),)* } - impl std::fmt::Debug for $AnnotationEnum { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - $(Self::$Variant(v) => v.fmt(f),)* - } - } - } - - $(impl From<$T> for crate::annotations::Annotation { - fn from(v: $T) -> Self { - $AnnotationEnum::$Variant(v).into() - } - } - - impl crate::annotations::IntoAnnotations for $T { - type IntoAnnotations = [crate::annotations::Annotation; 1]; + $(impl IntoAnnotations for $T { + type IntoAnnotations = [$Annotation; 1]; fn into_annotations(self) -> Self::IntoAnnotations { - [self.into()] + [$Annotation::$Variant(self)] } } - impl crate::annotations::IntoAnnotations for &'_ $T { - type IntoAnnotations = [crate::annotations::Annotation; 1]; + impl IntoAnnotations for &'_ $T { + type IntoAnnotations = [$Annotation; 1]; fn into_annotations(self) -> Self::IntoAnnotations { - [crate::annotations::Annotation::from(self.clone())] + [$Annotation::$Variant(*self)] } } - impl crate::annotations::IntoAnnotations for &'_ mut $T { - type IntoAnnotations = [crate::annotations::Annotation; 1]; + impl IntoAnnotations for &'_ mut $T { + type IntoAnnotations = [$Annotation; 1]; fn into_annotations(self) -> Self::IntoAnnotations { - [crate::annotations::Annotation::from(self.clone())] + [$Annotation::$Variant(*self)] } } - impl crate::annotations::IntoAnnotations for Box<$T> { - type IntoAnnotations = [crate::annotations::Annotation; 1]; + impl IntoAnnotations for Box<$T> { + type IntoAnnotations = [$Annotation; 1]; fn into_annotations(self) -> Self::IntoAnnotations { - [crate::annotations::Annotation::from(*self)] + [$Annotation::$Variant(*self)] } })* }; - (@require_non_exhaustive non_exhaustive) => {}; } -pub(crate) use make_annotation_enum; - make_annotation_enum! { + #[derive(Clone, PartialEq, Eq, Hash, Debug)] #[non_exhaustive] pub enum Annotation { DontTouch(DontTouchAnnotation), @@ -220,7 +199,6 @@ make_annotation_enum! { BlackBoxPath(BlackBoxPathAnnotation), DocString(DocStringAnnotation), CustomFirrtl(CustomFirrtlAnnotation), - Xilinx(crate::vendor::xilinx::XilinxAnnotation), } } @@ -336,8 +314,10 @@ impl> Iterator for IterIntoAnnotations { } impl< - T: FusedIterator>>, -> FusedIterator for IterIntoAnnotations + T: FusedIterator< + Item: IntoAnnotations>, + >, + > FusedIterator for IterIntoAnnotations { } diff --git a/crates/fayalite/src/array.rs b/crates/fayalite/src/array.rs index 569f2e2..f617f91 100644 --- a/crates/fayalite/src/array.rs +++ b/crates/fayalite/src/array.rs @@ -2,24 +2,17 @@ // See Notices.txt for copyright information use crate::{ - expr::{ - CastToBits, Expr, HdlPartialEq, ReduceBits, ToExpr, - ops::{ArrayLiteral, ExprFromIterator, ExprIntoIterator, ExprPartialEq}, - }, - int::{Bool, DYN_SIZE, DynSize, KnownSize, Size, SizeType}, + expr::{ops::ArrayIndex, Expr, ToExpr}, + int::{DynSize, KnownSize, Size, SizeType, DYN_SIZE}, intern::{Intern, Interned, LazyInterned}, module::transform::visit::{Fold, Folder, Visit, Visitor}, - sim::value::{SimValue, SimValuePartialEq}, source_location::SourceLocation, ty::{ - CanonicalType, MatchVariantWithoutScope, OpaqueSimValueSlice, OpaqueSimValueWriter, - OpaqueSimValueWritten, StaticType, Type, TypeProperties, TypeWithDeref, - serde_impls::SerdeCanonicalType, + CanonicalType, MatchVariantWithoutScope, StaticType, Type, TypeProperties, TypeWithDeref, }, util::ConstUsize, }; -use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error}; -use std::{iter::FusedIterator, ops::Index}; +use std::ops::Index; #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct ArrayType { @@ -48,20 +41,15 @@ impl ArrayType { is_storable, is_castable_from_bits, bit_width, - sim_only_values_len, } = element; let Some(bit_width) = bit_width.checked_mul(len) else { panic!("array too big"); }; - let Some(sim_only_values_len) = sim_only_values_len.checked_mul(len) else { - panic!("array too big"); - }; TypeProperties { is_passive, is_storable, is_castable_from_bits, bit_width, - sim_only_values_len, } } pub fn new(element: T, len: Len::SizeType) -> Self { @@ -103,12 +91,6 @@ impl> ArrayType { } } -impl Default for ArrayType { - fn default() -> Self { - Self::TYPE - } -} - impl StaticType for ArrayType { const TYPE: Self = Self { element: LazyInterned::new_lazy(&|| T::TYPE.intern_sized()), @@ -157,7 +139,6 @@ impl, Len: Size, State: Visitor + ?Sized> Visit impl Type for ArrayType { type BaseType = Array; type MaskType = ArrayType; - type SimValue = Len::ArraySimValue; type MatchVariant = Len::ArrayMatch; type MatchActiveScope = (); type MatchVariantAndInactiveScope = MatchVariantWithoutScope>; @@ -167,8 +148,10 @@ impl Type for ArrayType { this: Expr, source_location: SourceLocation, ) -> Self::MatchVariantsIter { + let base = Expr::as_dyn_array(this); + let base_ty = Expr::ty(base); let _ = source_location; - let retval = Vec::from_iter(this); + let retval = Vec::from_iter((0..base_ty.len()).map(|i| ArrayIndex::new(base, i).to_expr())); std::iter::once(MatchVariantWithoutScope( Len::ArrayMatch::::try_from(retval) .ok() @@ -194,106 +177,16 @@ impl Type for ArrayType { Len::from_usize(array.len()), ) } - fn source_location() -> SourceLocation { SourceLocation::builtin() } - - fn sim_value_from_opaque(&self, mut opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - let element_ty = self.element(); - let element_size = element_ty.canonical().size(); - let mut value = Vec::with_capacity(self.len()); - for _ in 0..self.len() { - let (element_opaque, rest) = opaque.split_at(element_size); - value.push(SimValue::from_opaque(element_ty, element_opaque.to_owned())); - opaque = rest; - } - value.try_into().ok().expect("used correct length") - } - - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - mut opaque: OpaqueSimValueSlice<'_>, - ) { - let element_ty = self.element(); - let element_size = element_ty.canonical().size(); - let value = AsMut::<[SimValue]>::as_mut(value); - assert_eq!(self.len(), value.len()); - for element_value in value { - assert_eq!(SimValue::ty(element_value), element_ty); - let (element_opaque, rest) = opaque.split_at(element_size); - SimValue::opaque_mut(element_value).clone_from_slice(element_opaque); - opaque = rest; - } - } - - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - mut writer: OpaqueSimValueWriter<'w>, - ) -> OpaqueSimValueWritten<'w> { - let element_ty = self.element(); - let element_size = element_ty.canonical().size(); - let value = AsRef::<[SimValue]>::as_ref(value); - assert_eq!(self.len(), value.len()); - for element_value in value { - assert_eq!(SimValue::ty(element_value), element_ty); - writer.fill_prefix_with(element_size, |writer| { - writer.fill_cloned_from_slice(SimValue::opaque(element_value).as_slice()) - }); - } - writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty()) - } -} - -impl Serialize for ArrayType { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - SerdeCanonicalType::::Array { - element: self.element(), - len: self.len(), - } - .serialize(serializer) - } -} - -impl<'de, T: Type + Deserialize<'de>, Len: Size> Deserialize<'de> for ArrayType { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let name = |len| -> String { - if let Some(len) = len { - format!("an Array<_, {len}>") - } else { - "an Array<_>".to_string() - } - }; - match SerdeCanonicalType::::deserialize(deserializer)? { - SerdeCanonicalType::Array { element, len } => { - if let Some(len) = Len::try_from_usize(len) { - Ok(Self::new(element, len)) - } else { - Err(Error::invalid_value( - serde::de::Unexpected::Other(&name(Some(len))), - &&*name(Len::KNOWN_VALUE), - )) - } - } - ty => Err(Error::invalid_value( - serde::de::Unexpected::Other(ty.as_serde_unexpected_str()), - &&*name(Len::KNOWN_VALUE), - )), - } - } } impl TypeWithDeref for ArrayType { fn expr_deref(this: &Expr) -> &Self::MatchVariant { - let retval = Vec::from_iter(*this); + let base = Expr::as_dyn_array(*this); + let base_ty = Expr::ty(base); + let retval = Vec::from_iter((0..base_ty.len()).map(|i| ArrayIndex::new(base, i).to_expr())); Interned::into_inner(Intern::intern_sized( Len::ArrayMatch::::try_from(retval) .ok() @@ -325,143 +218,3 @@ impl Index for ArrayWithoutLen { Interned::into_inner(Intern::intern_sized(ArrayType::new(self.element, len))) } } - -impl ExprPartialEq> for ArrayType -where - Lhs: ExprPartialEq, -{ - fn cmp_eq(lhs: Expr, rhs: Expr>) -> Expr { - let lhs_ty = Expr::ty(lhs); - let rhs_ty = Expr::ty(rhs); - assert_eq!(lhs_ty.len(), rhs_ty.len()); - lhs.into_iter() - .zip(rhs) - .map(|(l, r)| l.cmp_eq(r)) - .collect::>>() - .cast_to_bits() - .all_one_bits() - } - - fn cmp_ne(lhs: Expr, rhs: Expr>) -> Expr { - let lhs_ty = Expr::ty(lhs); - let rhs_ty = Expr::ty(rhs); - assert_eq!(lhs_ty.len(), rhs_ty.len()); - lhs.into_iter() - .zip(rhs) - .map(|(l, r)| l.cmp_ne(r)) - .collect::>>() - .cast_to_bits() - .any_one_bits() - } -} - -impl SimValuePartialEq> for ArrayType -where - Lhs: SimValuePartialEq, -{ - fn sim_value_eq(this: &SimValue, other: &SimValue>) -> bool { - AsRef::<[_]>::as_ref(&**this) - .iter() - .zip(AsRef::<[_]>::as_ref(&**other)) - .all(|(l, r)| SimValuePartialEq::sim_value_eq(l, r)) - } -} - -impl ExprIntoIterator for ArrayType { - type Item = T; - type ExprIntoIter = ExprArrayIter; - - fn expr_into_iter(e: Expr) -> Self::ExprIntoIter { - ExprArrayIter { - base: e, - indexes: 0..Expr::ty(e).len(), - } - } -} - -#[derive(Clone, Debug)] -pub struct ExprArrayIter { - base: Expr>, - indexes: std::ops::Range, -} - -impl ExprArrayIter { - pub fn base(&self) -> Expr> { - self.base - } - pub fn indexes(&self) -> std::ops::Range { - self.indexes.clone() - } -} - -impl Iterator for ExprArrayIter { - type Item = Expr; - - fn next(&mut self) -> Option { - self.indexes.next().map(|i| self.base[i]) - } - - fn size_hint(&self) -> (usize, Option) { - self.indexes.size_hint() - } - - fn count(self) -> usize { - self.indexes.count() - } - - fn last(mut self) -> Option { - self.next_back() - } - - fn nth(&mut self, n: usize) -> Option { - self.indexes.nth(n).map(|i| self.base[i]) - } - - fn fold(self, init: B, mut f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.indexes.fold(init, |b, i| f(b, self.base[i])) - } -} - -impl DoubleEndedIterator for ExprArrayIter { - fn next_back(&mut self) -> Option { - self.indexes.next_back().map(|i| self.base[i]) - } - - fn nth_back(&mut self, n: usize) -> Option { - self.indexes.nth_back(n).map(|i| self.base[i]) - } - - fn rfold(self, init: B, mut f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.indexes.rfold(init, |b, i| f(b, self.base[i])) - } -} - -impl ExactSizeIterator for ExprArrayIter { - fn len(&self) -> usize { - self.indexes.len() - } -} - -impl FusedIterator for ExprArrayIter {} - -impl ExprFromIterator> for Array { - fn expr_from_iter>>(iter: T) -> Expr { - ArrayLiteral::new( - A::TYPE, - iter.into_iter().map(|v| Expr::canonical(v)).collect(), - ) - .to_expr() - } -} - -impl<'a, A: StaticType> ExprFromIterator<&'a Expr> for Array { - fn expr_from_iter>>(iter: T) -> Expr { - iter.into_iter().copied().collect() - } -} diff --git a/crates/fayalite/src/build.rs b/crates/fayalite/src/build.rs deleted file mode 100644 index a9e9635..0000000 --- a/crates/fayalite/src/build.rs +++ /dev/null @@ -1,2803 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - build::graph::JobGraph, - bundle::{Bundle, BundleType}, - intern::{Intern, InternSlice, Interned}, - module::Module, - platform::{DynPlatform, Platform}, - util::{job_server::AcquiredJob, os_str_strip_prefix}, - vendor, -}; -use clap::ArgAction; -use serde::{ - Deserialize, Deserializer, Serialize, Serializer, - de::{DeserializeOwned, Error as _}, - ser::Error as _, -}; -use std::{ - any::{Any, TypeId}, - borrow::Cow, - cmp::Ordering, - ffi::{OsStr, OsString}, - fmt, - hash::{Hash, Hasher}, - io::Write, - marker::PhantomData, - path::{Path, PathBuf}, - sync::{Arc, OnceLock}, -}; -use tempfile::TempDir; - -pub mod external; -pub mod firrtl; -pub mod formal; -pub mod graph; -pub mod registry; -pub mod verilog; - -pub(crate) fn built_in_job_kinds() -> impl IntoIterator { - [DynJobKind::new(BaseJobKind)] - .into_iter() - .chain(firrtl::built_in_job_kinds()) - .chain(formal::built_in_job_kinds()) - .chain(vendor::built_in_job_kinds()) - .chain(verilog::built_in_job_kinds()) -} - -#[derive(Clone, Hash, PartialEq, Eq, Debug)] -#[non_exhaustive] -pub enum JobItem { - Path { - path: Interned, - }, - DynamicPaths { - paths: Vec>, - source_job_name: Interned, - }, -} - -impl JobItem { - pub fn name(&self) -> JobItemName { - match self { - &JobItem::Path { path } => JobItemName::Path { path }, - &JobItem::DynamicPaths { - paths: _, - source_job_name, - } => JobItemName::DynamicPaths { source_job_name }, - } - } -} - -#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Serialize, Deserialize)] -#[non_exhaustive] -pub enum JobItemName { - Path { path: Interned }, - DynamicPaths { source_job_name: Interned }, -} - -impl JobItemName { - fn as_ref(&self) -> JobItemNameRef<'_> { - match self { - JobItemName::Path { path } => JobItemNameRef::Path { path }, - JobItemName::DynamicPaths { source_job_name } => { - JobItemNameRef::DynamicPaths { source_job_name } - } - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -enum JobItemNameRef<'a> { - Path { path: &'a Path }, - DynamicPaths { source_job_name: &'a str }, -} - -/// ordered by string contents, not by `Interned` -impl PartialOrd for JobItemName { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -/// ordered by string contents, not by `Interned` -impl Ord for JobItemName { - fn cmp(&self, other: &Self) -> Ordering { - if self == other { - Ordering::Equal - } else { - self.as_ref().cmp(&other.as_ref()) - } - } -} - -pub trait WriteArgs: - for<'a> Extend<&'a str> - + for<'a> Extend<&'a OsStr> - + for<'a> Extend<&'a Path> - + for<'a> Extend> - + for<'a> Extend> - + for<'a> Extend> - + Extend - + Extend - + Extend - + Extend> - + Extend> - + Extend> -{ - fn write_display_args(&mut self, args: impl IntoIterator) { - self.extend(args.into_iter().map(|v| v.to_string())); - } - fn write_owned_args(&mut self, args: impl IntoIterator>) { - self.extend(args.into_iter().map(Into::::into)) - } - fn write_args<'a>(&mut self, args: impl IntoIterator>); - fn write_interned_args(&mut self, args: impl IntoIterator>>) { - self.extend(args.into_iter().map(Into::>::into)) - } - fn write_display_arg(&mut self, arg: impl fmt::Display) { - self.write_display_args([arg]); - } - fn write_owned_arg(&mut self, arg: impl Into) { - self.extend([arg.into()]); - } - fn write_arg(&mut self, arg: impl AsRef) { - self.extend([arg.as_ref()]); - } - /// writes `--{name}={value}` - fn write_long_option_eq(&mut self, name: impl AsRef, value: impl AsRef) { - let name = name.as_ref(); - let value = value.as_ref(); - let mut option = - OsString::with_capacity(name.len().saturating_add(value.len()).saturating_add(3)); - option.push("--"); - option.push(name); - option.push("="); - option.push(value); - self.write_owned_arg(option); - } - fn write_interned_arg(&mut self, arg: impl Into>) { - self.extend([arg.into()]); - } - /// finds the first option that is `--{option_name}={value}` and returns `value` - fn get_long_option_eq(&self, option_name: impl AsRef) -> Option<&OsStr>; -} - -pub trait ArgsWriterArg: - AsRef - + From> - + for<'a> From> - + for<'a> From<&'a OsStr> - + From -{ -} - -impl ArgsWriterArg for Interned {} - -impl ArgsWriterArg for OsString {} - -pub struct ArgsWriter(pub Vec); - -impl Default for ArgsWriter { - fn default() -> Self { - Self(Default::default()) - } -} - -impl ArgsWriter { - fn get_long_option_eq_helper(&self, option_name: &str) -> Option<&OsStr> { - self.0.iter().find_map(|arg| { - os_str_strip_prefix(arg.as_ref(), "--") - .and_then(|arg| os_str_strip_prefix(arg, option_name)) - .and_then(|arg| os_str_strip_prefix(arg, "=")) - }) - } -} - -impl<'a, A: ArgsWriterArg> Extend<&'a str> for ArgsWriter { - fn extend>(&mut self, iter: T) { - self.extend(iter.into_iter().map(AsRef::::as_ref)) - } -} - -impl<'a, A: ArgsWriterArg> Extend<&'a OsStr> for ArgsWriter { - fn extend>(&mut self, iter: T) { - self.0.extend(iter.into_iter().map(Into::into)) - } -} - -impl<'a, A: ArgsWriterArg> Extend<&'a Path> for ArgsWriter { - fn extend>(&mut self, iter: T) { - self.extend(iter.into_iter().map(AsRef::::as_ref)) - } -} - -impl Extend for ArgsWriter { - fn extend>(&mut self, iter: T) { - self.extend(iter.into_iter().map(OsString::from)) - } -} - -impl Extend for ArgsWriter { - fn extend>(&mut self, iter: T) { - self.0.extend(iter.into_iter().map(Into::into)) - } -} - -impl Extend for ArgsWriter { - fn extend>(&mut self, iter: T) { - self.extend(iter.into_iter().map(OsString::from)) - } -} - -impl Extend> for ArgsWriter { - fn extend>>(&mut self, iter: T) { - self.extend(iter.into_iter().map(Interned::::from)) - } -} - -impl Extend> for ArgsWriter { - fn extend>>(&mut self, iter: T) { - self.0.extend(iter.into_iter().map(Into::into)) - } -} - -impl Extend> for ArgsWriter { - fn extend>>(&mut self, iter: T) { - self.extend(iter.into_iter().map(Interned::::from)) - } -} - -impl<'a, A: ArgsWriterArg> Extend> for ArgsWriter { - fn extend>>(&mut self, iter: T) { - self.0.extend(iter.into_iter().map(|v| { - match v { - Cow::Borrowed(v) => Cow::::Borrowed(v.as_ref()), - Cow::Owned(v) => Cow::Owned(v.into()), - } - .into() - })) - } -} - -impl<'a, A: ArgsWriterArg> Extend> for ArgsWriter { - fn extend>>(&mut self, iter: T) { - self.0.extend(iter.into_iter().map(Into::into)) - } -} - -impl<'a, A: ArgsWriterArg> Extend> for ArgsWriter { - fn extend>>(&mut self, iter: T) { - self.0.extend(iter.into_iter().map(|v| { - match v { - Cow::Borrowed(v) => Cow::::Borrowed(v.as_ref()), - Cow::Owned(v) => Cow::Owned(v.into()), - } - .into() - })) - } -} - -impl WriteArgs for ArgsWriter { - fn write_args<'a>(&mut self, args: impl IntoIterator>) { - self.0.extend(args.into_iter().map(|v| v.as_ref().into())) - } - fn get_long_option_eq(&self, option_name: impl AsRef) -> Option<&OsStr> { - self.get_long_option_eq_helper(option_name.as_ref()) - } -} - -pub trait ToArgs: clap::Args + 'static + Send + Sync + Hash + Eq + fmt::Debug + Clone { - fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)); - fn to_interned_args(&self) -> Interned<[Interned]> { - Intern::intern_owned(self.to_interned_args_vec()) - } - fn to_interned_args_vec(&self) -> Vec> { - let mut retval = ArgsWriter::default(); - self.to_args(&mut retval); - retval.0 - } - fn to_os_string_args(&self) -> Vec { - let mut retval = ArgsWriter::default(); - self.to_args(&mut retval); - retval.0 - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct JobKindAndArgs { - pub kind: K, - pub args: K::Args, -} - -impl JobKindAndArgs { - pub fn args_to_jobs( - self, - dependencies: ::KindsAndArgs, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result> { - K::args_to_jobs( - JobArgsAndDependencies { - args: self, - dependencies, - }, - params, - global_params, - ) - } -} - -impl> Copy for JobKindAndArgs {} - -impl From> for DynJobArgs { - fn from(value: JobKindAndArgs) -> Self { - let JobKindAndArgs { kind, args } = value; - DynJobArgs::new(kind, args) - } -} - -impl TryFrom for JobKindAndArgs { - type Error = DynJobArgs; - fn try_from(value: DynJobArgs) -> Result { - value.downcast() - } -} - -#[derive(Debug, PartialEq, Eq, Hash)] -pub struct JobAndKind { - pub kind: K, - pub job: K::Job, -} - -impl> Clone for JobAndKind { - fn clone(&self) -> Self { - Self { - kind: self.kind.clone(), - job: self.job.clone(), - } - } -} - -impl> Copy for JobAndKind {} - -impl From> for DynJob { - fn from(value: JobAndKind) -> Self { - let JobAndKind { kind, job } = value; - DynJob::new(kind, job) - } -} - -impl> TryFrom for JobAndKind { - type Error = DynJob; - fn try_from(value: DynJob) -> Result { - value.downcast() - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct JobKindAndDependencies { - pub kind: K, - pub dependencies: K::Dependencies, -} - -impl Default for JobKindAndDependencies { - fn default() -> Self { - Self::new(K::default()) - } -} - -impl JobKindAndDependencies { - pub fn new(kind: K) -> Self { - Self { - kind, - dependencies: kind.dependencies(), - } - } -} - -#[derive(Debug, PartialEq, Eq, Hash)] -pub struct JobAndDependencies { - pub job: JobAndKind, - pub dependencies: ::JobsAndKinds, -} - -impl JobAndDependencies { - pub fn get_job(&self) -> &J - where - Self: GetJob, - { - GetJob::get_job(self) - } - pub fn base_job(&self) -> &BaseJob { - self.job.kind.base_job(&self.job.job, &self.dependencies) - } -} - -impl Clone for JobAndDependencies -where - K::Job: Clone, - ::JobsAndKinds: Clone, -{ - fn clone(&self) -> Self { - Self { - job: self.job.clone(), - dependencies: self.dependencies.clone(), - } - } -} - -impl Copy for JobAndDependencies -where - K::Job: Copy, - ::JobsAndKinds: Copy, -{ -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct JobArgsAndDependencies { - pub args: JobKindAndArgs, - pub dependencies: ::KindsAndArgs, -} - -impl Copy for JobArgsAndDependencies -where - K::Args: Copy, - ::KindsAndArgs: Copy, -{ -} - -impl JobArgsAndDependencies { - pub fn args_to_jobs( - self, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result> { - K::args_to_jobs(self, params, global_params) - } - pub fn base_job_args(&self) -> &BaseJobArgs { - self.args - .kind - .base_job_args(&self.args.args, &self.dependencies) - } -} - -impl>, D: JobKind> JobArgsAndDependencies { - pub fn args_to_jobs_simple( - self, - params: &JobParams, - global_params: &GlobalParams, - f: F, - ) -> eyre::Result> - where - F: FnOnce(K, K::Args, &mut JobAndDependencies) -> eyre::Result, - { - let Self { - args: JobKindAndArgs { kind, args }, - dependencies, - } = self; - let mut dependencies = dependencies.args_to_jobs(params, global_params)?; - let job = f(kind, args, &mut dependencies)?; - Ok(JobAndDependencies { - job: JobAndKind { kind, job }, - dependencies, - }) - } -} - -impl>, D: JobKind> - JobArgsAndDependencies> -{ - pub fn args_to_jobs_external_simple( - self, - params: &JobParams, - global_params: &GlobalParams, - f: F, - ) -> eyre::Result<( - C::AdditionalJobData, - ::JobsAndKinds, - )> - where - F: FnOnce( - external::ExternalCommandArgs, - &mut JobAndDependencies, - ) -> eyre::Result, - { - let Self { - args: JobKindAndArgs { kind: _, args }, - dependencies, - } = self; - let mut dependencies = dependencies.args_to_jobs(params, global_params)?; - let additional_job_data = f(args, &mut dependencies)?; - Ok((additional_job_data, dependencies)) - } -} - -pub trait JobDependencies: 'static + Send + Sync + Hash + Eq + fmt::Debug + Copy { - type KindsAndArgs: 'static + Send + Sync + Hash + Eq + fmt::Debug + Clone; - type JobsAndKinds: 'static + Send + Sync + Hash + Eq + fmt::Debug; - fn kinds_dyn_extend>(self, dyn_kinds: &mut E); - fn kinds_dyn(self) -> Vec { - let mut retval = Vec::new(); - self.kinds_dyn_extend(&mut retval); - retval - } - fn into_dyn_jobs_extend>(jobs: Self::JobsAndKinds, dyn_jobs: &mut E); - fn into_dyn_jobs(jobs: Self::JobsAndKinds) -> Vec { - let mut retval = Vec::new(); - Self::into_dyn_jobs_extend(jobs, &mut retval); - retval - } - #[track_caller] - fn from_dyn_args_prefix>( - args: &mut I, - ) -> Self::KindsAndArgs; - #[track_caller] - fn from_dyn_args>(args: I) -> Self::KindsAndArgs { - let mut iter = args.into_iter(); - let retval = Self::from_dyn_args_prefix(&mut iter); - if iter.next().is_some() { - panic!("wrong number of dependencies"); - } - retval - } -} - -pub trait JobDependenciesHasBase: JobDependencies { - fn base_job_args(args: &Self::KindsAndArgs) -> &BaseJobArgs; - fn base_job(jobs: &Self::JobsAndKinds) -> &BaseJob; - #[track_caller] - fn base_job_args_dyn(dependencies_args: &[DynJobArgs]) -> &BaseJobArgs; - #[track_caller] - fn base_job_dyn(dependencies: &[DynJob]) -> &BaseJob; -} - -impl JobDependencies for JobKindAndDependencies { - type KindsAndArgs = JobArgsAndDependencies; - type JobsAndKinds = JobAndDependencies; - - fn kinds_dyn_extend>(self, dyn_kinds: &mut E) { - let Self { kind, dependencies } = self; - dependencies.kinds_dyn_extend(dyn_kinds); - dyn_kinds.extend([DynJobKind::new(kind)]); - } - - fn into_dyn_jobs_extend>( - jobs: Self::JobsAndKinds, - dyn_jobs: &mut E, - ) { - let JobAndDependencies { job, dependencies } = jobs; - K::Dependencies::into_dyn_jobs_extend(dependencies, dyn_jobs); - dyn_jobs.extend([job.into()]); - } - - #[track_caller] - fn from_dyn_args_prefix>( - args: &mut I, - ) -> Self::KindsAndArgs { - let dependencies = K::Dependencies::from_dyn_args_prefix(args); - let Some(args) = args.next() else { - panic!("wrong number of dependencies"); - }; - match args.downcast() { - Ok(args) => JobArgsAndDependencies { args, dependencies }, - Err(args) => { - panic!( - "wrong type of dependency, expected {} got:\n{args:?}", - std::any::type_name::() - ) - } - } - } -} - -impl JobDependenciesHasBase for JobKindAndDependencies { - fn base_job_args(args: &Self::KindsAndArgs) -> &BaseJobArgs { - args.base_job_args() - } - - fn base_job(jobs: &Self::JobsAndKinds) -> &BaseJob { - jobs.base_job() - } - - #[track_caller] - fn base_job_args_dyn(dependencies_args: &[DynJobArgs]) -> &BaseJobArgs { - let [dependencies_args @ .., args] = dependencies_args else { - panic!("wrong number of dependencies"); - }; - let Some((kind, args)) = args.downcast_ref::() else { - panic!( - "wrong type of dependency, expected {} got:\n{args:?}", - std::any::type_name::() - ) - }; - kind.base_job_args_dyn(args, dependencies_args) - } - - #[track_caller] - fn base_job_dyn(dependencies: &[DynJob]) -> &BaseJob { - let [dependencies @ .., job] = dependencies else { - panic!("wrong number of dependencies"); - }; - let Some((kind, job)) = job.downcast_ref::() else { - panic!( - "wrong type of dependency, expected {} got:\n{job:?}", - std::any::type_name::() - ) - }; - kind.base_job_dyn(job, dependencies) - } -} - -macro_rules! impl_job_dependencies { - (@impl $(($v:ident: $T:ident),)*) => { - impl<$($T: JobDependencies),*> JobDependencies for ($($T,)*) { - type KindsAndArgs = ($($T::KindsAndArgs,)*); - type JobsAndKinds = ($($T::JobsAndKinds,)*); - - fn kinds_dyn_extend>(self, dyn_kinds: &mut E) { - #![allow(unused_variables)] - let ($($v,)*) = self; - $($T::kinds_dyn_extend($v, dyn_kinds);)* - } - - fn into_dyn_jobs_extend>( - jobs: Self::JobsAndKinds, - dyn_jobs: &mut E, - ) { - #![allow(unused_variables)] - let ($($v,)*) = jobs; - $($T::into_dyn_jobs_extend($v, dyn_jobs);)* - } - - #[track_caller] - fn from_dyn_args_prefix>( - args: &mut I, - ) -> Self::KindsAndArgs { - #![allow(unused_variables)] - $(let $v = $T::from_dyn_args_prefix(args);)* - ($($v,)*) - } - } - }; - ($($first:tt, $($rest:tt,)*)?) => { - impl_job_dependencies!(@impl $($first, $($rest,)*)?); - $(impl_job_dependencies!($($rest,)*);)? - }; -} - -impl_job_dependencies! { - (v0: T0), - (v1: T1), - (v2: T2), - (v3: T3), - (v4: T4), - (v5: T5), - (v6: T6), - (v7: T7), - (v8: T8), - (v9: T9), - (v10: T10), - (v11: T11), -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct JobParams { - main_module: Module, -} - -impl AsRef for JobParams { - fn as_ref(&self) -> &Self { - self - } -} - -impl JobParams { - pub fn new_canonical(main_module: Module) -> Self { - Self { main_module } - } - pub fn new(main_module: impl AsRef>) -> Self { - Self::new_canonical(main_module.as_ref().canonical()) - } - pub fn main_module(&self) -> &Module { - &self.main_module - } -} - -#[derive(Clone, Debug)] -pub struct GlobalParams { - top_level_cmd: Option, - application_name: Interned, -} - -impl AsRef for GlobalParams { - fn as_ref(&self) -> &Self { - self - } -} - -impl GlobalParams { - pub fn new(top_level_cmd: Option, application_name: impl AsRef) -> Self { - Self { - top_level_cmd, - application_name: application_name.as_ref().intern(), - } - } - pub fn top_level_cmd(&self) -> Option<&clap::Command> { - self.top_level_cmd.as_ref() - } - pub fn into_top_level_cmd(self) -> Option { - self.top_level_cmd - } - pub fn extract_clap_error(&self, e: eyre::Report) -> eyre::Result { - let e = e.downcast::()?; - Ok(match &self.top_level_cmd { - Some(cmd) => e.with_cmd(cmd), - None => e, - }) - } - pub fn exit_if_clap_error(&self, e: eyre::Report) -> eyre::Report { - match self.extract_clap_error(e) { - Ok(e) => e.exit(), - Err(e) => e, - } - } - pub fn clap_error( - &self, - kind: clap::error::ErrorKind, - message: impl fmt::Display, - ) -> clap::Error { - match self.top_level_cmd.clone() { - Some(top_level_cmd) => top_level_cmd.clone().error(kind, message), - None => clap::Error::raw(kind, message), - } - } - pub fn application_name(&self) -> Interned { - self.application_name - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct CommandParams { - pub command_line: Interned<[Interned]>, - pub current_dir: Option>, -} - -impl CommandParams { - fn to_unix_shell_line( - self, - output: &mut String, - mut escape_arg: impl FnMut(&OsStr, &mut String) -> Result<(), E>, - ) -> Result<(), E> { - let Self { - command_line, - current_dir, - } = self; - let mut end = None; - let mut separator = if let Some(current_dir) = current_dir { - output.push_str("(cd "); - end = Some(")"); - if !current_dir - .as_os_str() - .as_encoded_bytes() - .first() - .is_some_and(|ch| ch.is_ascii_alphanumeric() || matches!(ch, b'/' | b'\\' | b'.')) - { - output.push_str("-- "); - } - escape_arg(current_dir.as_ref(), output)?; - "; exec -- " - } else { - "" - }; - for arg in command_line { - output.push_str(separator); - separator = " "; - escape_arg(&arg, output)?; - } - if let Some(end) = end { - output.push_str(end); - } - Ok(()) - } -} - -pub trait JobKindHelper: 'static + Send + Sync + Hash + Eq + fmt::Debug + Copy { - fn base_job_args<'a>( - self, - args: &'a ::Args, - dependencies: &'a <::Dependencies as JobDependencies>::KindsAndArgs, - ) -> &'a BaseJobArgs - where - Self: JobKind; - fn base_job<'a>( - self, - job: &'a ::Job, - dependencies: &'a <::Dependencies as JobDependencies>::JobsAndKinds, - ) -> &'a BaseJob - where - Self: JobKind; - #[track_caller] - fn base_job_args_dyn<'a>( - self, - args: &'a ::Args, - dependencies_args: &'a [DynJobArgs], - ) -> &'a BaseJobArgs - where - Self: JobKind; - #[track_caller] - fn base_job_dyn<'a>( - self, - job: &'a ::Job, - dependencies: &'a [DynJob], - ) -> &'a BaseJob - where - Self: JobKind; -} - -impl> JobKindHelper for K { - fn base_job_args<'a>( - self, - _args: &'a ::Args, - dependencies: &'a <::Dependencies as JobDependencies>::KindsAndArgs, - ) -> &'a BaseJobArgs { - K::Dependencies::base_job_args(dependencies) - } - fn base_job<'a>( - self, - _job: &'a ::Job, - dependencies: &'a <::Dependencies as JobDependencies>::JobsAndKinds, - ) -> &'a BaseJob { - K::Dependencies::base_job(dependencies) - } - #[track_caller] - fn base_job_args_dyn<'a>( - self, - _args: &'a ::Args, - dependencies_args: &'a [DynJobArgs], - ) -> &'a BaseJobArgs { - K::Dependencies::base_job_args_dyn(dependencies_args) - } - #[track_caller] - fn base_job_dyn<'a>( - self, - _job: &'a ::Job, - dependencies: &'a [DynJob], - ) -> &'a BaseJob { - K::Dependencies::base_job_dyn(dependencies) - } -} - -pub trait JobKind: JobKindHelper { - type Args: ToArgs; - type Job: 'static + Send + Sync + Hash + Eq + fmt::Debug + Serialize + DeserializeOwned; - type Dependencies: JobDependencies; - fn dependencies(self) -> Self::Dependencies; - fn args_to_jobs( - args: JobArgsAndDependencies, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result>; - fn inputs(self, job: &Self::Job) -> Interned<[JobItemName]>; - fn outputs(self, job: &Self::Job) -> Interned<[JobItemName]>; - fn name(self) -> Interned; - fn external_command_params(self, job: &Self::Job) -> Option; - fn run( - self, - job: &Self::Job, - inputs: &[JobItem], - params: &JobParams, - global_params: &GlobalParams, - acquired_job: &mut AcquiredJob, - ) -> eyre::Result>; - fn subcommand_hidden(self) -> bool { - false - } - fn external_program(self) -> Option> { - None - } -} - -trait DynJobKindTrait: 'static + Send + Sync + fmt::Debug { - fn as_any(&self) -> &dyn Any; - fn as_arc_any(self: Arc) -> Arc; - fn eq_dyn(&self, other: &dyn DynJobKindTrait) -> bool; - fn hash_dyn(&self, state: &mut dyn Hasher); - fn dependencies_kinds_dyn(&self) -> Vec; - fn args_group_id_dyn(&self) -> Option; - fn augment_args_dyn(&self, cmd: clap::Command) -> clap::Command; - fn augment_args_for_update_dyn(&self, cmd: clap::Command) -> clap::Command; - fn from_arg_matches_dyn( - &self, - matches: &mut clap::ArgMatches, - ) -> clap::error::Result; - fn name_dyn(&self) -> Interned; - fn subcommand_hidden_dyn(&self) -> bool; - fn deserialize_job_from_json_str(self: Arc, json: &str) -> serde_json::Result; - fn deserialize_job_from_json_value( - self: Arc, - json: &serde_json::Value, - ) -> serde_json::Result; -} - -impl DynJobKindTrait for K { - fn as_any(&self) -> &dyn Any { - self - } - - fn as_arc_any(self: Arc) -> Arc { - self - } - - fn eq_dyn(&self, other: &dyn DynJobKindTrait) -> bool { - other - .as_any() - .downcast_ref::() - .is_some_and(|other| self == other) - } - - fn hash_dyn(&self, mut state: &mut dyn Hasher) { - self.hash(&mut state); - } - - fn dependencies_kinds_dyn(&self) -> Vec { - self.dependencies().kinds_dyn() - } - - fn args_group_id_dyn(&self) -> Option { - ::group_id() - } - - fn augment_args_dyn(&self, cmd: clap::Command) -> clap::Command { - ::augment_args(cmd) - } - - fn augment_args_for_update_dyn(&self, cmd: clap::Command) -> clap::Command { - ::augment_args_for_update(cmd) - } - - fn from_arg_matches_dyn( - &self, - matches: &mut clap::ArgMatches, - ) -> clap::error::Result { - Ok(DynJobArgs::new( - *self, - ::from_arg_matches_mut(matches)?, - )) - } - - fn name_dyn(&self) -> Interned { - self.name() - } - - fn subcommand_hidden_dyn(&self) -> bool { - self.subcommand_hidden() - } - - fn deserialize_job_from_json_str(self: Arc, json: &str) -> serde_json::Result { - Ok(DynJob::from_arc(self, serde_json::from_str(json)?)) - } - - fn deserialize_job_from_json_value( - self: Arc, - json: &serde_json::Value, - ) -> serde_json::Result { - Ok(DynJob::from_arc(self, Deserialize::deserialize(json)?)) - } -} - -#[derive(Clone)] -pub struct DynJobKind(Arc); - -impl DynJobKind { - pub fn from_arc(job_kind: Arc) -> Self { - Self(job_kind) - } - pub fn new(job_kind: K) -> Self { - Self(Arc::new(job_kind)) - } - pub fn type_id(&self) -> TypeId { - DynJobKindTrait::as_any(&*self.0).type_id() - } - pub fn downcast(&self) -> Option { - DynJobKindTrait::as_any(&*self.0).downcast_ref().copied() - } - pub fn downcast_arc(self) -> Result, Self> { - if self.downcast::().is_some() { - Ok(Arc::downcast::(self.0.as_arc_any()) - .ok() - .expect("already checked type")) - } else { - Err(self) - } - } - pub fn dependencies_kinds(&self) -> Vec { - DynJobKindTrait::dependencies_kinds_dyn(&*self.0) - } - pub fn args_group_id(&self) -> Option { - DynJobKindTrait::args_group_id_dyn(&*self.0) - } - pub fn augment_args(&self, cmd: clap::Command) -> clap::Command { - DynJobKindTrait::augment_args_dyn(&*self.0, cmd) - } - pub fn augment_args_for_update(&self, cmd: clap::Command) -> clap::Command { - DynJobKindTrait::augment_args_for_update_dyn(&*self.0, cmd) - } - pub fn from_arg_matches( - &self, - matches: &mut clap::ArgMatches, - ) -> clap::error::Result { - DynJobKindTrait::from_arg_matches_dyn(&*self.0, matches) - } - pub fn name(&self) -> Interned { - DynJobKindTrait::name_dyn(&*self.0) - } - pub fn subcommand_hidden(&self) -> bool { - DynJobKindTrait::subcommand_hidden_dyn(&*self.0) - } - pub fn deserialize_job_from_json_str(self, json: &str) -> serde_json::Result { - DynJobKindTrait::deserialize_job_from_json_str(self.0, json) - } - pub fn deserialize_job_from_json_value( - self, - json: &serde_json::Value, - ) -> serde_json::Result { - DynJobKindTrait::deserialize_job_from_json_value(self.0, json) - } - fn make_subcommand_without_args(&self) -> clap::Command { - clap::Command::new(Interned::into_inner(self.name())).hide(self.subcommand_hidden()) - } - pub fn make_subcommand(&self) -> clap::Command { - let mut subcommand = self.make_subcommand_without_args(); - for dependency in self.dependencies_kinds() { - subcommand = dependency.augment_args(subcommand); - } - self.augment_args(subcommand) - } - pub fn make_subcommand_for_update(&self) -> clap::Command { - let mut subcommand = self.make_subcommand_without_args(); - for dependency in self.dependencies_kinds() { - subcommand = dependency.augment_args_for_update(subcommand); - } - self.augment_args_for_update(subcommand) - } -} - -impl Hash for DynJobKind { - fn hash(&self, state: &mut H) { - self.type_id().hash(state); - DynJobKindTrait::hash_dyn(&*self.0, state); - } -} - -impl PartialEq for DynJobKind { - fn eq(&self, other: &Self) -> bool { - DynJobKindTrait::eq_dyn(&*self.0, &*other.0) - } -} - -impl Eq for DynJobKind {} - -impl fmt::Debug for DynJobKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl Serialize for DynJobKind { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.name().serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for DynJobKind { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let name = Cow::::deserialize(deserializer)?; - match Self::registry().get_by_name(&name) { - Some(retval) => Ok(retval.clone()), - None => Err(D::Error::custom(format_args!( - "unknown job kind: name not found in registry: {name:?}" - ))), - } - } -} - -#[derive(Copy, Clone, Debug, Default)] -pub struct DynJobKindValueParser; - -#[derive(Clone, PartialEq, Eq, Hash)] -struct DynJobKindValueEnum { - name: Interned, - job_kind: DynJobKind, -} - -impl clap::ValueEnum for DynJobKindValueEnum { - fn value_variants<'a>() -> &'a [Self] { - Interned::into_inner( - registry::JobKindRegistrySnapshot::get() - .iter_with_names() - .map(|(name, job_kind)| Self { - name, - job_kind: job_kind.clone(), - }) - .collect(), - ) - } - - fn to_possible_value(&self) -> Option { - Some(clap::builder::PossibleValue::new(Interned::into_inner( - self.name, - ))) - } -} - -impl clap::builder::TypedValueParser for DynJobKindValueParser { - type Value = DynJobKind; - - fn parse_ref( - &self, - cmd: &clap::Command, - arg: Option<&clap::Arg>, - value: &std::ffi::OsStr, - ) -> clap::error::Result { - clap::builder::EnumValueParser::::new() - .parse_ref(cmd, arg, value) - .map(|v| v.job_kind) - } - - fn possible_values( - &self, - ) -> Option + '_>> { - static ENUM_VALUE_PARSER: OnceLock> = - OnceLock::new(); - ENUM_VALUE_PARSER - .get_or_init(clap::builder::EnumValueParser::::new) - .possible_values() - } -} - -impl clap::builder::ValueParserFactory for DynJobKind { - type Parser = DynJobKindValueParser; - - fn value_parser() -> Self::Parser { - DynJobKindValueParser::default() - } -} - -trait DynExtendInternedStr { - fn extend_from_slice(&mut self, items: &[Interned]); -} - -impl Extend> for dyn DynExtendInternedStr + '_ { - fn extend>>(&mut self, iter: T) { - let mut buf = [Interned::default(); 64]; - let mut buf_len = 0; - iter.into_iter().for_each(|item| { - buf[buf_len] = item; - buf_len += 1; - if buf_len == buf.len() { - ::extend_from_slice(self, &buf); - buf_len = 0; - } - }); - if buf_len > 0 { - ::extend_from_slice( - self, - &buf[..buf_len], - ); - } - } -} - -impl>> DynExtendInternedStr for T { - fn extend_from_slice(&mut self, items: &[Interned]) { - self.extend(items.iter().copied()); - } -} - -#[derive(PartialEq, Eq, Hash, Clone)] -struct DynJobArgsInner(JobKindAndArgs); - -impl fmt::Debug for DynJobArgsInner { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self(JobKindAndArgs { kind, args }) = self; - f.debug_struct("DynJobArgs") - .field("kind", kind) - .field("args", args) - .finish() - } -} - -trait DynJobArgsTrait: 'static + Send + Sync + fmt::Debug { - fn as_any(&self) -> &dyn Any; - fn as_arc_any(self: Arc) -> Arc; - fn kind_type_id(&self) -> TypeId; - fn eq_dyn(&self, other: &dyn DynJobArgsTrait) -> bool; - fn hash_dyn(&self, state: &mut dyn Hasher); - fn kind(&self) -> DynJobKind; - fn to_args_extend_vec(&self, args: Vec>) -> Vec>; - fn clone_into_arc(&self) -> Arc; - fn update_from_arg_matches( - &mut self, - matches: &mut clap::ArgMatches, - ) -> clap::error::Result<()>; - #[track_caller] - fn args_to_jobs( - self: Arc, - dependencies_args: Vec, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result<(DynJob, Vec)>; - #[track_caller] - fn base_job_args_dyn<'a>(&'a self, dependencies_args: &'a [DynJobArgs]) -> &'a BaseJobArgs; -} - -impl DynJobArgsTrait for DynJobArgsInner { - fn as_any(&self) -> &dyn Any { - self - } - - fn as_arc_any(self: Arc) -> Arc { - self - } - - fn kind_type_id(&self) -> TypeId { - TypeId::of::() - } - - fn eq_dyn(&self, other: &dyn DynJobArgsTrait) -> bool { - other - .as_any() - .downcast_ref::() - .is_some_and(|other| self == other) - } - - fn hash_dyn(&self, mut state: &mut dyn Hasher) { - self.hash(&mut state); - } - - fn kind(&self) -> DynJobKind { - DynJobKind::new(self.0.kind) - } - - fn to_args_extend_vec(&self, args: Vec>) -> Vec> { - let mut writer = ArgsWriter(args); - self.0.args.to_args(&mut writer); - writer.0 - } - - fn clone_into_arc(&self) -> Arc { - Arc::new(self.clone()) - } - - fn update_from_arg_matches( - &mut self, - matches: &mut clap::ArgMatches, - ) -> clap::error::Result<()> { - clap::FromArgMatches::update_from_arg_matches_mut(&mut self.0.args, matches) - } - - #[track_caller] - fn args_to_jobs( - self: Arc, - dependencies_args: Vec, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result<(DynJob, Vec)> { - let JobAndDependencies { job, dependencies } = JobArgsAndDependencies { - args: Arc::unwrap_or_clone(self).0, - dependencies: K::Dependencies::from_dyn_args(dependencies_args), - } - .args_to_jobs(params, global_params)?; - Ok((job.into(), K::Dependencies::into_dyn_jobs(dependencies))) - } - - #[track_caller] - fn base_job_args_dyn<'a>(&'a self, dependencies_args: &'a [DynJobArgs]) -> &'a BaseJobArgs { - self.0 - .kind - .base_job_args_dyn(&self.0.args, dependencies_args) - } -} - -#[derive(Clone)] -pub struct DynJobArgs(Arc); - -impl DynJobArgs { - pub fn new(kind: K, args: K::Args) -> Self { - Self(Arc::new(DynJobArgsInner(JobKindAndArgs { kind, args }))) - } - pub fn kind_type_id(&self) -> TypeId { - DynJobArgsTrait::kind_type_id(&*self.0) - } - pub fn downcast_ref(&self) -> Option<(&K, &K::Args)> { - let DynJobArgsInner::(JobKindAndArgs { kind, args }) = - DynJobArgsTrait::as_any(&*self.0).downcast_ref()?; - Some((kind, args)) - } - pub fn downcast(self) -> Result, Self> { - if self.downcast_ref::().is_some() { - let this = Arc::downcast::>(self.0.as_arc_any()) - .ok() - .expect("already checked type"); - Ok(Arc::unwrap_or_clone(this).0) - } else { - Err(self) - } - } - pub fn kind(&self) -> DynJobKind { - DynJobArgsTrait::kind(&*self.0) - } - pub fn to_args_vec(&self) -> Vec> { - self.to_args_extend_vec(Vec::new()) - } - pub fn to_args_extend_vec(&self, args: Vec>) -> Vec> { - DynJobArgsTrait::to_args_extend_vec(&*self.0, args) - } - fn make_mut(&mut self) -> &mut dyn DynJobArgsTrait { - // can't just return the reference if the first get_mut returns Some since - // as of rustc 1.90.0 this causes a false-positive lifetime error. - if Arc::get_mut(&mut self.0).is_none() { - self.0 = DynJobArgsTrait::clone_into_arc(&*self.0); - } - Arc::get_mut(&mut self.0).expect("clone_into_arc returns a new arc with a ref-count of 1") - } - pub fn update_from_arg_matches( - &mut self, - matches: &mut clap::ArgMatches, - ) -> clap::error::Result<()> { - DynJobArgsTrait::update_from_arg_matches(self.make_mut(), matches) - } - pub fn args_to_jobs( - self, - dependencies_args: Vec, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result<(DynJob, Vec)> { - DynJobArgsTrait::args_to_jobs(self.0, dependencies_args, params, global_params) - } - #[track_caller] - pub fn base_job_args_dyn<'a>(&'a self, dependencies_args: &'a [DynJobArgs]) -> &'a BaseJobArgs { - DynJobArgsTrait::base_job_args_dyn(&*self.0, dependencies_args) - } -} - -impl Hash for DynJobArgs { - fn hash(&self, state: &mut H) { - self.kind_type_id().hash(state); - DynJobArgsTrait::hash_dyn(&*self.0, state); - } -} - -impl PartialEq for DynJobArgs { - fn eq(&self, other: &Self) -> bool { - DynJobArgsTrait::eq_dyn(&*self.0, &*other.0) - } -} - -impl Eq for DynJobArgs {} - -impl fmt::Debug for DynJobArgs { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[derive(PartialEq, Eq, Hash)] -struct DynJobInner { - kind: Arc, - job: K::Job, - inputs: Interned<[JobItemName]>, - outputs: Interned<[JobItemName]>, - external_command_params: Option, -} - -impl> Clone for DynJobInner { - fn clone(&self) -> Self { - Self { - kind: self.kind.clone(), - job: self.job.clone(), - inputs: self.inputs, - outputs: self.outputs, - external_command_params: self.external_command_params, - } - } -} - -impl fmt::Debug for DynJobInner { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - kind, - job, - inputs, - outputs, - external_command_params, - } = self; - f.debug_struct("DynJob") - .field("kind", kind) - .field("job", job) - .field("inputs", inputs) - .field("outputs", outputs) - .field("external_command_params", external_command_params) - .finish() - } -} - -trait DynJobTrait: 'static + Send + Sync + fmt::Debug { - fn as_any(&self) -> &dyn Any; - fn as_arc_any(self: Arc) -> Arc; - fn eq_dyn(&self, other: &dyn DynJobTrait) -> bool; - fn hash_dyn(&self, state: &mut dyn Hasher); - fn kind_type_id(&self) -> TypeId; - fn kind(&self) -> DynJobKind; - fn inputs(&self) -> Interned<[JobItemName]>; - fn outputs(&self) -> Interned<[JobItemName]>; - fn external_command_params(&self) -> Option; - fn serialize_to_json_ascii(&self) -> serde_json::Result; - fn serialize_to_json_value(&self) -> serde_json::Result; - fn run( - &self, - inputs: &[JobItem], - params: &JobParams, - global_params: &GlobalParams, - acquired_job: &mut AcquiredJob, - ) -> eyre::Result>; - #[track_caller] - fn base_job_dyn<'a>(&'a self, dependencies: &'a [DynJob]) -> &'a BaseJob; -} - -impl DynJobTrait for DynJobInner { - fn as_any(&self) -> &dyn Any { - self - } - - fn as_arc_any(self: Arc) -> Arc { - self - } - - fn eq_dyn(&self, other: &dyn DynJobTrait) -> bool { - other - .as_any() - .downcast_ref::() - .is_some_and(|other| self == other) - } - - fn hash_dyn(&self, mut state: &mut dyn Hasher) { - self.hash(&mut state); - } - - fn kind_type_id(&self) -> TypeId { - TypeId::of::() - } - - fn kind(&self) -> DynJobKind { - DynJobKind(self.kind.clone()) - } - - fn inputs(&self) -> Interned<[JobItemName]> { - self.inputs - } - - fn outputs(&self) -> Interned<[JobItemName]> { - self.outputs - } - - fn external_command_params(&self) -> Option { - self.external_command_params - } - - fn serialize_to_json_ascii(&self) -> serde_json::Result { - crate::util::serialize_to_json_ascii(&self.job) - } - - fn serialize_to_json_value(&self) -> serde_json::Result { - serde_json::to_value(&self.job) - } - - fn run( - &self, - inputs: &[JobItem], - params: &JobParams, - global_params: &GlobalParams, - acquired_job: &mut AcquiredJob, - ) -> eyre::Result> { - self.kind - .run(&self.job, inputs, params, global_params, acquired_job) - } - - #[track_caller] - fn base_job_dyn<'a>(&'a self, dependencies: &'a [DynJob]) -> &'a BaseJob { - self.kind.base_job_dyn(&self.job, dependencies) - } -} - -#[derive(Clone, Debug)] -pub struct DynJob(Arc); - -impl DynJob { - pub fn from_arc(job_kind: Arc, job: K::Job) -> Self { - let inputs = job_kind.inputs(&job); - let outputs = job_kind.outputs(&job); - let external_command_params = job_kind.external_command_params(&job); - Self(Arc::new(DynJobInner { - kind: job_kind, - job, - inputs, - outputs, - external_command_params, - })) - } - pub fn new(job_kind: K, job: K::Job) -> Self { - Self::from_arc(Arc::new(job_kind), job) - } - pub fn kind_type_id(&self) -> TypeId { - self.0.kind_type_id() - } - pub fn downcast_ref(&self) -> Option<(&K, &K::Job)> { - let DynJobInner { kind, job, .. } = self.0.as_any().downcast_ref()?; - Some((kind, job)) - } - pub fn downcast>(self) -> Result, Self> { - if self.kind_type_id() == TypeId::of::() { - let DynJobInner { kind, job, .. } = Arc::unwrap_or_clone( - self.0 - .as_arc_any() - .downcast::>() - .expect("already checked type"), - ); - Ok(JobAndKind { kind: *kind, job }) - } else { - Err(self) - } - } - pub fn kind(&self) -> DynJobKind { - DynJobTrait::kind(&*self.0) - } - pub fn inputs(&self) -> Interned<[JobItemName]> { - DynJobTrait::inputs(&*self.0) - } - pub fn outputs(&self) -> Interned<[JobItemName]> { - DynJobTrait::outputs(&*self.0) - } - pub fn serialize_to_json_ascii(&self) -> serde_json::Result { - DynJobTrait::serialize_to_json_ascii(&*self.0) - } - pub fn serialize_to_json_value(&self) -> serde_json::Result { - DynJobTrait::serialize_to_json_value(&*self.0) - } - pub fn external_command_params(&self) -> Option { - DynJobTrait::external_command_params(&*self.0) - } - #[track_caller] - pub fn internal_command_params_with_program_prefix( - &self, - internal_program_prefix: &[Interned], - platform: Option<&DynPlatform>, - extra_args: &[Interned], - ) -> CommandParams { - let mut command_line = internal_program_prefix.to_vec(); - let command_line = match RunSingleJob::try_add_subcommand(platform, self, &mut command_line) - { - Ok(()) => { - command_line.extend_from_slice(extra_args); - Intern::intern_owned(command_line) - } - Err(e) => panic!("Serializing job {:?} failed: {e}", self.kind().name()), - }; - CommandParams { - command_line, - current_dir: None, - } - } - #[track_caller] - pub fn internal_command_params( - &self, - platform: Option<&DynPlatform>, - extra_args: &[Interned], - ) -> CommandParams { - self.internal_command_params_with_program_prefix( - &[program_name_for_internal_jobs()], - platform, - extra_args, - ) - } - #[track_caller] - pub fn command_params_with_internal_program_prefix( - &self, - internal_program_prefix: &[Interned], - platform: Option<&DynPlatform>, - extra_args: &[Interned], - ) -> CommandParams { - match self.external_command_params() { - Some(v) => v, - None => self.internal_command_params_with_program_prefix( - internal_program_prefix, - platform, - extra_args, - ), - } - } - #[track_caller] - pub fn command_params( - &self, - platform: Option<&DynPlatform>, - extra_args: &[Interned], - ) -> CommandParams { - self.command_params_with_internal_program_prefix( - &[program_name_for_internal_jobs()], - platform, - extra_args, - ) - } - pub fn run( - &self, - inputs: &[JobItem], - params: &JobParams, - global_params: &GlobalParams, - acquired_job: &mut AcquiredJob, - ) -> eyre::Result> { - DynJobTrait::run(&*self.0, inputs, params, global_params, acquired_job) - } - #[track_caller] - pub fn base_job_dyn<'a>(&'a self, dependencies: &'a [DynJob]) -> &'a BaseJob { - DynJobTrait::base_job_dyn(&*self.0, dependencies) - } -} - -impl Eq for DynJob {} - -impl PartialEq for DynJob { - fn eq(&self, other: &Self) -> bool { - DynJobTrait::eq_dyn(&*self.0, &*other.0) - } -} - -impl Hash for DynJob { - fn hash(&self, state: &mut H) { - DynJobTrait::hash_dyn(&*self.0, state); - } -} - -#[derive(Serialize, Deserialize)] -#[serde(rename = "DynJob")] -struct DynJobSerde { - kind: DynJobKind, - job: serde_json::Value, -} - -impl Serialize for DynJob { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - DynJobSerde { - kind: self.kind(), - job: self.serialize_to_json_value().map_err(S::Error::custom)?, - } - .serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for DynJob { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let DynJobSerde { kind, job } = Deserialize::deserialize(deserializer)?; - kind.deserialize_job_from_json_value(&job) - .map_err(D::Error::custom) - } -} - -pub trait RunBuild: Sized { - fn main_without_platform(application_name: impl AsRef, make_params: F) - where - Self: clap::Parser + Clone, - F: FnOnce(Self, Extra) -> eyre::Result, - { - let application_name = application_name.as_ref(); - match Self::try_main_without_platform(application_name, make_params) { - Ok(()) => {} - Err(e) => { - let e = GlobalParams::new(Some(Self::command()), application_name) - .exit_if_clap_error(e); - eprintln!("{e:#}"); - std::process::exit(1); - } - } - } - fn try_main_without_platform( - application_name: impl AsRef, - make_params: F, - ) -> eyre::Result<()> - where - Self: clap::Parser + Clone, - F: FnOnce(Self, Extra) -> eyre::Result, - { - let args = Self::parse(); - let global_params = GlobalParams::new(Some(Self::command()), application_name); - args.clone() - .run_without_platform(|extra| make_params(args, extra), &global_params) - .map_err(|e| global_params.exit_if_clap_error(e)) - } - fn run_without_platform( - self, - make_params: F, - global_params: &GlobalParams, - ) -> eyre::Result<()> - where - F: FnOnce(Extra) -> eyre::Result; - fn get_platform(&self) -> Option<&DynPlatform>; - fn main(application_name: impl AsRef, make_params: F) - where - Self: clap::Parser + Clone, - F: FnOnce(Self, DynPlatform, Extra) -> eyre::Result, - { - let application_name = application_name.as_ref(); - match Self::try_main(application_name, make_params) { - Ok(()) => {} - Err(e) => { - let e = GlobalParams::new(Some(Self::command()), application_name) - .exit_if_clap_error(e); - eprintln!("{e:#}"); - std::process::exit(1); - } - } - } - fn try_main(application_name: impl AsRef, make_params: F) -> eyre::Result<()> - where - Self: clap::Parser + Clone, - F: FnOnce(Self, DynPlatform, Extra) -> eyre::Result, - { - let args = Self::parse(); - let global_params = GlobalParams::new(Some(Self::command()), application_name); - let Some(platform) = args.get_platform().cloned() else { - return args.handle_missing_platform(&global_params); - }; - args.clone() - .run( - |platform, extra| make_params(args, platform, extra), - platform, - &global_params, - ) - .map_err(|e| global_params.exit_if_clap_error(e)) - } - fn handle_missing_platform(self, global_params: &GlobalParams) -> eyre::Result<()> { - global_params - .clap_error( - clap::error::ErrorKind::MissingRequiredArgument, - "--platform is required", - ) - .exit(); - } - fn run( - self, - make_params: F, - platform: DynPlatform, - global_params: &GlobalParams, - ) -> eyre::Result<()> - where - F: FnOnce(DynPlatform, Extra) -> eyre::Result, - { - self.run_without_platform(|extra| make_params(platform, extra), global_params) - } -} - -impl RunBuild for JobArgsAndDependencies { - fn run_without_platform( - self, - make_params: F, - global_params: &GlobalParams, - ) -> eyre::Result<()> - where - F: FnOnce(NoArgs) -> eyre::Result, - { - let params = make_params(NoArgs)?; - self.args_to_jobs(¶ms, global_params)? - .run_without_platform(|_| Ok(params), global_params) - } - fn get_platform(&self) -> Option<&DynPlatform> { - self.base_job_args().platform.as_ref() - } - fn run( - self, - make_params: F, - platform: DynPlatform, - global_params: &GlobalParams, - ) -> eyre::Result<()> - where - F: FnOnce(DynPlatform, NoArgs) -> eyre::Result, - { - let params = make_params(platform.clone(), NoArgs)?; - self.args_to_jobs(¶ms, global_params)? - .run(|_, _| Ok(params), platform, global_params) - } -} - -impl RunBuild for JobAndDependencies { - fn run_without_platform( - self, - make_params: F, - global_params: &GlobalParams, - ) -> eyre::Result<()> - where - F: FnOnce(NoArgs) -> eyre::Result, - { - let params = make_params(NoArgs)?; - let Self { job, dependencies } = self; - let mut jobs = vec![DynJob::from(job)]; - K::Dependencies::into_dyn_jobs_extend(dependencies, &mut jobs); - let mut job_graph = JobGraph::new(); - job_graph.add_jobs(jobs); // add all at once to avoid recomputing graph properties multiple times - job_graph.run(¶ms, global_params) - } - fn get_platform(&self) -> Option<&DynPlatform> { - self.base_job().platform() - } - fn run( - self, - make_params: F, - platform: DynPlatform, - global_params: &GlobalParams, - ) -> eyre::Result<()> - where - F: FnOnce(DynPlatform, NoArgs) -> eyre::Result, - { - let params = make_params(platform, NoArgs)?; - let Self { job, dependencies } = self; - let mut jobs = vec![DynJob::from(job)]; - K::Dependencies::into_dyn_jobs_extend(dependencies, &mut jobs); - let mut job_graph = JobGraph::new(); - job_graph.add_jobs(jobs); // add all at once to avoid recomputing graph properties multiple times - job_graph.run(¶ms, global_params) - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct RunSingleJob { - pub platform: Option, - pub job: DynJob, - pub extra: Extra, -} - -impl RunSingleJob { - pub const SUBCOMMAND_NAME: &'static str = "run-single-job"; - fn try_add_subcommand( - platform: Option<&DynPlatform>, - job: &DynJob, - subcommand_line: &mut Vec>, - ) -> serde_json::Result<()> { - let mut json = job.serialize_to_json_ascii()?; - json.insert_str(0, "--json="); - subcommand_line.push(Self::SUBCOMMAND_NAME.intern().into()); - if let Some(platform) = platform { - subcommand_line.push( - format!("--platform={}", platform.name()) - .intern_deref() - .into(), - ); - } - subcommand_line.push( - format!("--name={}", job.kind().name()) - .intern_deref() - .into(), - ); - subcommand_line.push(json.intern_deref().into()); - Ok(()) - } -} - -impl TryFrom> for RunSingleJob { - type Error = clap::Error; - - fn try_from(value: RunSingleJobClap) -> Result { - let RunSingleJobClap::RunSingleJob { - platform, - name: job_kind, - json, - extra, - } = value; - let name = job_kind.name(); - job_kind - .deserialize_job_from_json_str(&json) - .map_err(|e| { - clap::Error::raw( - clap::error::ErrorKind::ValueValidation, - format_args!("failed to parse job {name} from JSON: {e}"), - ) - }) - .map(|job| Self { - platform, - job, - extra, - }) - } -} - -#[derive(clap::Subcommand)] -enum RunSingleJobClap { - #[command(name = RunSingleJob::SUBCOMMAND_NAME, hide = true)] - RunSingleJob { - #[arg(long)] - platform: Option, - #[arg(long)] - name: DynJobKind, - #[arg(long)] - json: String, - #[command(flatten)] - extra: Extra, - }, -} - -impl clap::Subcommand for RunSingleJob { - fn augment_subcommands(cmd: clap::Command) -> clap::Command { - RunSingleJobClap::::augment_subcommands(cmd) - } - - fn augment_subcommands_for_update(cmd: clap::Command) -> clap::Command { - RunSingleJobClap::::augment_subcommands(cmd) - } - - fn has_subcommand(name: &str) -> bool { - RunSingleJobClap::::has_subcommand(name) - } -} - -impl clap::FromArgMatches for RunSingleJob { - fn from_arg_matches(matches: &clap::ArgMatches) -> clap::error::Result { - RunSingleJobClap::from_arg_matches(matches)?.try_into() - } - fn from_arg_matches_mut(matches: &mut clap::ArgMatches) -> clap::error::Result { - RunSingleJobClap::from_arg_matches_mut(matches)?.try_into() - } - fn update_from_arg_matches(&mut self, matches: &clap::ArgMatches) -> clap::error::Result<()> { - *self = Self::from_arg_matches(matches)?; - Ok(()) - } - fn update_from_arg_matches_mut( - &mut self, - matches: &mut clap::ArgMatches, - ) -> clap::error::Result<()> { - *self = Self::from_arg_matches_mut(matches)?; - Ok(()) - } -} - -impl RunBuild for RunSingleJob { - fn run_without_platform( - self, - make_params: F, - global_params: &GlobalParams, - ) -> eyre::Result<()> - where - F: FnOnce(Extra) -> eyre::Result, - { - let params = make_params(self.extra)?; - let mut job_graph = JobGraph::new(); - job_graph.add_jobs([self.job]); - job_graph.run(¶ms, global_params) - } - fn get_platform(&self) -> Option<&DynPlatform> { - self.platform.as_ref() - } -} - -#[derive(Clone, PartialEq, Eq, Hash, clap::Subcommand)] -pub enum Completions { - #[non_exhaustive] - Completions { - #[arg(default_value = Self::shell_str_from_env(), required = Self::shell_from_env().is_none())] - shell: clap_complete::aot::Shell, - }, -} - -impl Completions { - pub fn new(shell: clap_complete::aot::Shell) -> Self { - Self::Completions { shell } - } - pub fn from_env() -> Option { - Some(Self::Completions { - shell: Self::shell_from_env()?, - }) - } - fn shell_from_env() -> Option { - static SHELL: OnceLock> = OnceLock::new(); - *SHELL.get_or_init(clap_complete::aot::Shell::from_env) - } - fn shell_str_from_env() -> clap::builder::Resettable { - static SHELL_STR: OnceLock> = OnceLock::new(); - SHELL_STR - .get_or_init(|| Self::shell_from_env().map(|v| v.to_string())) - .as_deref() - .map(Into::into) - .into() - } -} - -impl RunBuild for Completions { - fn run_without_platform( - self, - _make_params: F, - global_params: &GlobalParams, - ) -> eyre::Result<()> - where - F: FnOnce(NoArgs) -> eyre::Result, - { - let Self::Completions { shell } = self; - let Some(cmd) = global_params.top_level_cmd() else { - eyre::bail!("completions command requires GlobalParams::top_level_cmd() to be Some"); - }; - let bin_name = cmd.get_bin_name().map(str::intern).unwrap_or_else(|| { - program_name_for_internal_jobs() - .to_interned_str() - .expect("program name is invalid UTF-8") - }); - clap_complete::aot::generate( - shell, - &mut cmd.clone(), - &*bin_name, - &mut std::io::BufWriter::new(std::io::stdout().lock()), - ); - Ok(()) - } - fn handle_missing_platform(self, global_params: &GlobalParams) -> eyre::Result<()> { - self.run_without_platform(|_| unreachable!(), global_params) - } - fn get_platform(&self) -> Option<&DynPlatform> { - None - } -} - -#[derive( - clap::Args, - Copy, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Debug, - Default, - Serialize, - Deserialize, -)] -pub struct NoArgs; - -impl ToArgs for NoArgs { - fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) { - let Self {} = self; - } -} - -#[derive(Clone, PartialEq, Eq, Hash, clap::Parser)] -pub enum BuildCli { - #[clap(flatten)] - Job(AnyJobSubcommand), - #[clap(flatten)] - RunSingleJob(RunSingleJob), - #[clap(flatten)] - Completions(Completions), - #[cfg(unix)] - #[clap(flatten)] - CreateUnixShellScript(CreateUnixShellScript), -} - -impl RunBuild for BuildCli { - fn run_without_platform( - self, - make_params: F, - global_params: &GlobalParams, - ) -> eyre::Result<()> - where - F: FnOnce(Extra) -> eyre::Result, - { - match self { - BuildCli::Job(v) => v.run_without_platform(make_params, global_params), - BuildCli::RunSingleJob(v) => v.run_without_platform(make_params, global_params), - BuildCli::Completions(v) => { - v.run_without_platform(|NoArgs {}| unreachable!(), global_params) - } - #[cfg(unix)] - BuildCli::CreateUnixShellScript(v) => { - v.run_without_platform(make_params, global_params) - } - } - } - fn handle_missing_platform(self, global_params: &GlobalParams) -> eyre::Result<()> { - match self { - BuildCli::Job(v) => v.handle_missing_platform(global_params), - BuildCli::RunSingleJob(v) => v.handle_missing_platform(global_params), - BuildCli::Completions(v) => v.handle_missing_platform(global_params), - #[cfg(unix)] - BuildCli::CreateUnixShellScript(v) => v.handle_missing_platform(global_params), - } - } - fn get_platform(&self) -> Option<&DynPlatform> { - match self { - BuildCli::Job(v) => v.get_platform(), - BuildCli::RunSingleJob(v) => v.get_platform(), - BuildCli::Completions(v) => v.get_platform(), - #[cfg(unix)] - BuildCli::CreateUnixShellScript(v) => v.get_platform(), - } - } - fn run( - self, - make_params: F, - platform: DynPlatform, - global_params: &GlobalParams, - ) -> eyre::Result<()> - where - F: FnOnce(DynPlatform, Extra) -> eyre::Result, - { - match self { - BuildCli::Job(v) => v.run(make_params, platform, global_params), - BuildCli::RunSingleJob(v) => v.run(make_params, platform, global_params), - BuildCli::Completions(v) => { - v.run(|_, NoArgs {}| unreachable!(), platform, global_params) - } - #[cfg(unix)] - BuildCli::CreateUnixShellScript(v) => v.run(make_params, platform, global_params), - } - } -} - -#[cfg(unix)] -#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Subcommand)] -enum CreateUnixShellScriptInner { - CreateUnixShellScript { - #[arg(name = "i-know-this-is-incomplete", long, required = true, action = ArgAction::SetTrue)] - _incomplete: (), - #[command(subcommand)] - inner: AnyJobSubcommand, - }, -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct CreateUnixShellScript(CreateUnixShellScriptInner); - -impl RunBuild for CreateUnixShellScript { - fn run_without_platform( - self, - make_params: F, - global_params: &GlobalParams, - ) -> eyre::Result<()> - where - F: FnOnce(Extra) -> eyre::Result, - { - let platform = self.get_platform().cloned(); - let CreateUnixShellScriptInner::CreateUnixShellScript { - _incomplete: (), - inner: - AnyJobSubcommand { - args, - dependencies_args, - extra, - }, - } = self.0; - let extra_args = extra.to_interned_args_vec(); - let params = make_params(extra)?; - let bin_name = global_params - .top_level_cmd() - .and_then(clap::Command::get_bin_name) - .map(|v| OsStr::new(v).intern()); - let (job, dependencies) = args.args_to_jobs(dependencies_args, ¶ms, global_params)?; - let mut job_graph = JobGraph::new(); - job_graph.add_jobs([job].into_iter().chain(dependencies)); - std::io::stdout().write_all( - job_graph - .to_unix_shell_script_with_internal_program_prefix( - &[bin_name.unwrap_or_else(|| program_name_for_internal_jobs())], - platform.as_ref(), - &extra_args, - ) - .as_bytes(), - )?; - Ok(()) - } - fn get_platform(&self) -> Option<&DynPlatform> { - let CreateUnixShellScriptInner::CreateUnixShellScript { inner, .. } = &self.0; - inner.get_platform() - } -} - -impl clap::FromArgMatches for CreateUnixShellScript { - fn from_arg_matches(matches: &clap::ArgMatches) -> Result { - clap::FromArgMatches::from_arg_matches(matches).map(Self) - } - fn from_arg_matches_mut(matches: &mut clap::ArgMatches) -> Result { - clap::FromArgMatches::from_arg_matches_mut(matches).map(Self) - } - fn update_from_arg_matches(&mut self, matches: &clap::ArgMatches) -> Result<(), clap::Error> { - self.0.update_from_arg_matches(matches) - } - fn update_from_arg_matches_mut( - &mut self, - matches: &mut clap::ArgMatches, - ) -> Result<(), clap::Error> { - self.0.update_from_arg_matches_mut(matches) - } -} - -#[cfg(unix)] -impl clap::Subcommand for CreateUnixShellScript { - fn augment_subcommands(cmd: clap::Command) -> clap::Command { - CreateUnixShellScriptInner::::augment_subcommands(cmd) - } - - fn augment_subcommands_for_update(cmd: clap::Command) -> clap::Command { - CreateUnixShellScriptInner::::augment_subcommands_for_update(cmd) - } - - fn has_subcommand(name: &str) -> bool { - CreateUnixShellScriptInner::::has_subcommand(name) - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct AnyJobSubcommand { - pub args: DynJobArgs, - pub dependencies_args: Vec, - pub extra: Extra, -} - -impl AnyJobSubcommand { - pub fn from_subcommand_arg_matches( - job_kind: &DynJobKind, - matches: &mut clap::ArgMatches, - ) -> clap::error::Result { - let dependencies = job_kind.dependencies_kinds(); - let dependencies_args = Result::from_iter( - dependencies - .into_iter() - .map(|dependency| dependency.from_arg_matches(matches)), - )?; - Ok(Self { - args: job_kind.clone().from_arg_matches(matches)?, - dependencies_args, - extra: Extra::from_arg_matches_mut(matches)?, - }) - } - pub fn update_from_subcommand_arg_matches( - &mut self, - job_kind: &DynJobKind, - matches: &mut clap::ArgMatches, - ) -> clap::error::Result<()> { - let Self { - args, - dependencies_args, - extra, - } = self; - if *job_kind == args.kind() { - for dependency in dependencies_args { - dependency.update_from_arg_matches(matches)?; - } - args.update_from_arg_matches(matches)?; - } else { - let dependencies = job_kind.dependencies_kinds(); - let new_dependencies_args = Result::from_iter( - dependencies - .into_iter() - .map(|dependency| dependency.from_arg_matches(matches)), - )?; - *args = job_kind.clone().from_arg_matches(matches)?; - *dependencies_args = new_dependencies_args; - } - extra.update_from_arg_matches_mut(matches) - } -} - -impl clap::Subcommand for AnyJobSubcommand { - fn augment_subcommands(mut cmd: clap::Command) -> clap::Command { - let snapshot = registry::JobKindRegistrySnapshot::get(); - for job_kind in &snapshot { - cmd = cmd.subcommand(Extra::augment_args(job_kind.make_subcommand())); - } - cmd - } - - fn augment_subcommands_for_update(mut cmd: clap::Command) -> clap::Command { - let snapshot = registry::JobKindRegistrySnapshot::get(); - for job_kind in &snapshot { - cmd = cmd.subcommand(Extra::augment_args_for_update( - job_kind.make_subcommand_for_update(), - )); - } - cmd - } - - fn has_subcommand(name: &str) -> bool { - registry::JobKindRegistrySnapshot::get() - .get_by_name(name) - .is_some() - } -} - -impl clap::FromArgMatches for AnyJobSubcommand { - fn from_arg_matches(matches: &clap::ArgMatches) -> clap::error::Result { - Self::from_arg_matches_mut(&mut matches.clone()) - } - - fn from_arg_matches_mut(matches: &mut clap::ArgMatches) -> clap::error::Result { - if let Some((name, mut matches)) = matches.remove_subcommand() { - let job_kind_registry_snapshot = registry::JobKindRegistrySnapshot::get(); - if let Some(job_kind) = job_kind_registry_snapshot.get_by_name(&name) { - Self::from_subcommand_arg_matches(job_kind, &mut matches) - } else { - Err(clap::Error::raw( - clap::error::ErrorKind::InvalidSubcommand, - format!("the subcommand '{name}' wasn't recognized"), - )) - } - } else { - Err(clap::Error::raw( - clap::error::ErrorKind::MissingSubcommand, - "a subcommand is required but one was not provided", - )) - } - } - - fn update_from_arg_matches(&mut self, matches: &clap::ArgMatches) -> clap::error::Result<()> { - Self::update_from_arg_matches_mut(self, &mut matches.clone()) - } - - fn update_from_arg_matches_mut( - &mut self, - matches: &mut clap::ArgMatches, - ) -> clap::error::Result<()> { - if let Some((name, mut matches)) = matches.remove_subcommand() { - let job_kind_registry_snapshot = registry::JobKindRegistrySnapshot::get(); - if let Some(job_kind) = job_kind_registry_snapshot.get_by_name(&name) { - self.update_from_subcommand_arg_matches(job_kind, &mut matches) - } else { - Err(clap::Error::raw( - clap::error::ErrorKind::InvalidSubcommand, - format!("the subcommand '{name}' wasn't recognized"), - )) - } - } else { - Err(clap::Error::raw( - clap::error::ErrorKind::MissingSubcommand, - "a subcommand is required but one was not provided", - )) - } - } -} - -impl RunBuild for AnyJobSubcommand { - fn run_without_platform( - self, - make_params: F, - global_params: &GlobalParams, - ) -> eyre::Result<()> - where - F: FnOnce(Extra) -> eyre::Result, - { - let Self { - args, - dependencies_args, - extra, - } = self; - let params = make_params(extra)?; - let (job, dependencies) = args.args_to_jobs(dependencies_args, ¶ms, global_params)?; - let mut job_graph = JobGraph::new(); - job_graph.add_jobs([job].into_iter().chain(dependencies)); // add all at once to avoid recomputing graph properties multiple times - job_graph.run(¶ms, global_params) - } - fn get_platform(&self) -> Option<&DynPlatform> { - self.args - .base_job_args_dyn(&self.dependencies_args) - .platform - .as_ref() - } -} - -pub fn program_name_for_internal_jobs() -> Interned { - static PROGRAM_NAME: OnceLock> = OnceLock::new(); - *PROGRAM_NAME.get_or_init(|| { - std::env::args_os() - .next() - .expect("can't get program name") - .intern_deref() - }) -} - -#[derive(clap::Args, Debug, Clone, Hash, PartialEq, Eq)] -#[group(id = "BaseJob")] -#[non_exhaustive] -pub struct BaseJobArgs { - /// the directory to put the generated main output file and associated files in - #[arg(short, long, value_hint = clap::ValueHint::DirPath)] - pub output: Option, - #[arg(long, env = "FAYALITE_KEEP_TEMP_DIR")] - pub keep_temp_dir: bool, - /// the stem of the generated main output file, e.g. to get foo.v, pass --file-stem=foo - #[arg(long)] - pub file_stem: Option, - /// run commands even if their results are already cached - #[arg(long, env = Self::RUN_EVEN_IF_CACHED_ENV_NAME)] - pub run_even_if_cached: bool, - /// platform - #[arg(long)] - pub platform: Option, -} - -impl BaseJobArgs { - pub const RUN_EVEN_IF_CACHED_ENV_NAME: &'static str = "FAYALITE_RUN_EVEN_IF_CACHED"; - pub fn from_output_dir_and_env(output: PathBuf, platform: Option) -> Self { - Self { - output: Some(output), - keep_temp_dir: false, - file_stem: None, - run_even_if_cached: std::env::var_os(Self::RUN_EVEN_IF_CACHED_ENV_NAME).is_some(), - platform, - } - } -} - -impl ToArgs for BaseJobArgs { - fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) { - let Self { - output, - keep_temp_dir, - file_stem, - run_even_if_cached, - platform, - } = self; - if let Some(output) = output { - args.write_long_option_eq("output", output); - } - if *keep_temp_dir { - args.write_arg("--keep-temp-dir"); - } - if let Some(file_stem) = file_stem { - args.write_long_option_eq("file-stem", file_stem); - } - if *run_even_if_cached { - args.write_arg("--run-even-if-cached"); - } - if let Some(platform) = platform { - args.write_long_option_eq("platform", platform.name()); - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct BaseJob { - output_dir: Interned, - #[serde(skip)] - temp_dir: Option>, - file_stem: Interned, - run_even_if_cached: bool, - platform: Option, -} - -impl Hash for BaseJob { - fn hash(&self, state: &mut H) { - let Self { - output_dir, - temp_dir: _, - file_stem, - run_even_if_cached, - platform, - } = self; - output_dir.hash(state); - file_stem.hash(state); - run_even_if_cached.hash(state); - platform.hash(state); - } -} - -impl Eq for BaseJob {} - -impl PartialEq for BaseJob { - fn eq(&self, other: &Self) -> bool { - let Self { - output_dir, - temp_dir: _, - file_stem, - run_even_if_cached, - ref platform, - } = *self; - output_dir == other.output_dir - && file_stem == other.file_stem - && run_even_if_cached == other.run_even_if_cached - && *platform == other.platform - } -} - -impl BaseJob { - pub fn output_dir(&self) -> Interned { - self.output_dir - } - pub fn temp_dir(&self) -> Option<&Arc> { - self.temp_dir.as_ref() - } - pub fn file_stem(&self) -> Interned { - self.file_stem - } - pub fn file_with_ext(&self, ext: impl AsRef) -> Interned { - let mut retval = self.output_dir().join(self.file_stem()); - retval.set_extension(ext); - retval.intern_deref() - } - pub fn run_even_if_cached(&self) -> bool { - self.run_even_if_cached - } - pub fn platform(&self) -> Option<&DynPlatform> { - self.platform.as_ref() - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] -pub struct BaseJobKind; - -impl JobKindHelper for BaseJobKind { - fn base_job<'a>( - self, - job: &'a ::Job, - _dependencies: &'a <::Dependencies as JobDependencies>::JobsAndKinds, - ) -> &'a BaseJob { - job - } - fn base_job_args<'a>( - self, - args: &'a ::Args, - _dependencies: &'a <::Dependencies as JobDependencies>::KindsAndArgs, - ) -> &'a BaseJobArgs { - args - } - #[track_caller] - fn base_job_args_dyn<'a>( - self, - args: &'a ::Args, - dependencies_args: &'a [DynJobArgs], - ) -> &'a BaseJobArgs { - let [] = dependencies_args else { - panic!("wrong number of dependencies"); - }; - args - } - #[track_caller] - fn base_job_dyn<'a>( - self, - job: &'a ::Job, - dependencies: &'a [DynJob], - ) -> &'a BaseJob { - let [] = dependencies else { - panic!("wrong number of dependencies"); - }; - job - } -} - -impl JobKind for BaseJobKind { - type Args = BaseJobArgs; - type Job = BaseJob; - type Dependencies = (); - - fn dependencies(self) -> Self::Dependencies { - () - } - - fn args_to_jobs( - args: JobArgsAndDependencies, - params: &JobParams, - _global_params: &GlobalParams, - ) -> eyre::Result> { - let BaseJobArgs { - output, - keep_temp_dir, - file_stem, - run_even_if_cached, - platform, - } = args.args.args; - let (output_dir, temp_dir) = if let Some(output) = output { - (Intern::intern_owned(output), None) - } else { - // we create the temp dir here rather than in run so other - // jobs can have their paths based on the chosen temp dir - let temp_dir = TempDir::new()?; - let output_dir = temp_dir.path().intern(); - let temp_dir = if keep_temp_dir { - // use TempDir::into_path() to no longer automatically delete the temp dir - let temp_dir_path = temp_dir.into_path(); - println!("created temporary directory: {}", temp_dir_path.display()); - None - } else { - Some(Arc::new(temp_dir)) - }; - (output_dir, temp_dir) - }; - let file_stem = file_stem - .map(Intern::intern_deref) - .unwrap_or(params.main_module().name().into()); - Ok(JobAndDependencies { - job: JobAndKind { - kind: BaseJobKind, - job: BaseJob { - output_dir, - temp_dir, - file_stem, - run_even_if_cached, - platform, - }, - }, - dependencies: (), - }) - } - - fn inputs(self, _job: &Self::Job) -> Interned<[JobItemName]> { - Interned::default() - } - - fn outputs(self, job: &Self::Job) -> Interned<[JobItemName]> { - [JobItemName::Path { - path: job.output_dir, - }] - .intern_slice() - } - - fn name(self) -> Interned { - "base-job".intern() - } - - fn external_command_params(self, job: &Self::Job) -> Option { - Some(CommandParams { - command_line: [ - "mkdir".intern().into(), - "-p".intern().into(), - "--".intern().into(), - job.output_dir.into(), - ] - .intern_slice(), - current_dir: None, - }) - } - - fn run( - self, - job: &Self::Job, - inputs: &[JobItem], - _params: &JobParams, - _global_params: &GlobalParams, - _acquired_job: &mut AcquiredJob, - ) -> eyre::Result> { - let [] = inputs else { - panic!("invalid inputs for BaseJob"); - }; - std::fs::create_dir_all(&*job.output_dir)?; - Ok(vec![JobItem::Path { - path: job.output_dir, - }]) - } - - fn subcommand_hidden(self) -> bool { - true - } -} - -pub trait GetJob { - fn get_job(this: &Self) -> &J; -} - -impl> GetJob for &'_ T { - fn get_job(this: &Self) -> &J { - T::get_job(this) - } -} - -impl> GetJob for &'_ mut T { - fn get_job(this: &Self) -> &J { - T::get_job(this) - } -} - -impl> GetJob for Box { - fn get_job(this: &Self) -> &J { - T::get_job(this) - } -} - -pub struct GetJobPositionDependencies(PhantomData); - -impl Default for GetJobPositionDependencies { - fn default() -> Self { - Self(Default::default()) - } -} - -impl fmt::Debug for GetJobPositionDependencies { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "GetJobPositionDependencies<{}>", - std::any::type_name::() - ) - } -} - -impl Hash for GetJobPositionDependencies { - fn hash(&self, _state: &mut H) {} -} - -impl Ord for GetJobPositionDependencies { - fn cmp(&self, _other: &Self) -> Ordering { - Ordering::Equal - } -} - -impl PartialOrd for GetJobPositionDependencies { - fn partial_cmp(&self, _other: &Self) -> Option { - Some(Ordering::Equal) - } -} - -impl Eq for GetJobPositionDependencies {} - -impl PartialEq for GetJobPositionDependencies { - fn eq(&self, _other: &Self) -> bool { - true - } -} - -impl Clone for GetJobPositionDependencies { - fn clone(&self) -> Self { - Self(PhantomData) - } -} - -impl Copy for GetJobPositionDependencies {} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] -pub struct GetJobPositionJob; - -impl>>> - GetJob> for JobAndDependencies -{ - fn get_job(this: &Self) -> &J { - GetJob::get_job(&this.dependencies) - } -} - -impl GetJob for JobAndDependencies { - fn get_job(this: &Self) -> &K::Job { - &this.job.job - } -} - -impl>>> - GetJob> for JobArgsAndDependencies -{ - fn get_job(this: &Self) -> &J { - GetJob::get_job(&this.dependencies) - } -} - -impl GetJob for JobArgsAndDependencies { - fn get_job(this: &Self) -> &K::Args { - &this.args.args - } -} - -impl>> - GetJob> for JobKindAndDependencies -{ - fn get_job(this: &Self) -> &J { - GetJob::get_job(&this.dependencies) - } -} - -impl GetJob for JobKindAndDependencies { - fn get_job(this: &Self) -> &K { - &this.kind - } -} diff --git a/crates/fayalite/src/build/external.rs b/crates/fayalite/src/build/external.rs deleted file mode 100644 index 1a90414..0000000 --- a/crates/fayalite/src/build/external.rs +++ /dev/null @@ -1,1177 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - build::{ - ArgsWriter, CommandParams, GlobalParams, JobAndDependencies, JobAndKind, - JobArgsAndDependencies, JobDependencies, JobDependenciesHasBase, JobItem, JobItemName, - JobKind, JobKindAndArgs, JobParams, ToArgs, WriteArgs, - }, - intern::{Intern, Interned}, - util::{job_server::AcquiredJob, streaming_read_utf8::streaming_read_utf8}, -}; -use base64::{Engine, prelude::BASE64_URL_SAFE_NO_PAD}; -use clap::builder::OsStringValueParser; -use eyre::{Context, ensure, eyre}; -use serde::{ - Deserialize, Deserializer, Serialize, Serializer, - de::{DeserializeOwned, Error}, -}; -use std::{ - borrow::Cow, - collections::BTreeMap, - ffi::{OsStr, OsString}, - fmt, - hash::{Hash, Hasher}, - io::Write, - marker::PhantomData, - path::{Path, PathBuf}, - process::ExitStatus, - sync::OnceLock, -}; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize, Deserialize)] -#[non_exhaustive] -pub enum ExternalJobCacheVersion { - /// not used, used to be for `FormalCacheVersion` - V1, - V2, -} - -impl ExternalJobCacheVersion { - pub const CURRENT: Self = Self::V2; -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[non_exhaustive] -pub enum MaybeUtf8 { - Utf8(String), - Binary(Vec), -} - -impl MaybeUtf8 { - pub fn as_bytes(&self) -> &[u8] { - match self { - MaybeUtf8::Utf8(v) => v.as_bytes(), - MaybeUtf8::Binary(v) => v, - } - } - pub fn as_os_str(&self) -> &OsStr { - #![allow(unreachable_code)] - #[cfg(unix)] - { - return std::os::unix::ffi::OsStrExt::from_bytes(self.as_bytes()); - } - #[cfg(target_os = "wasi")] - { - return std::os::wasi::ffi::OsStrExt::from_bytes(self.as_bytes()); - } - // implementing WTF-8 is too much of a pain so don't have a special case for windows - if let Ok(s) = str::from_utf8(self.as_bytes()) { - return OsStr::new(s); - } - panic!("invalid UTF-8 conversion to OsStr is not implemented on this platform"); - } - pub fn as_path(&self) -> &Path { - Path::new(self.as_os_str()) - } -} - -#[derive(Serialize, Deserialize)] -#[serde(rename = "MaybeUtf8")] -enum MaybeUtf8Serde<'a> { - Utf8(Cow<'a, str>), - Binary(String), -} - -impl<'de> Deserialize<'de> for MaybeUtf8 { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Ok(match MaybeUtf8Serde::deserialize(deserializer)? { - MaybeUtf8Serde::Utf8(v) => Self::Utf8(v.into_owned()), - MaybeUtf8Serde::Binary(v) => BASE64_URL_SAFE_NO_PAD - .decode(&*v) - .map_err(D::Error::custom)? - .into(), - }) - } -} - -impl Serialize for MaybeUtf8 { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - MaybeUtf8::Utf8(v) => MaybeUtf8Serde::Utf8(Cow::Borrowed(v)), - MaybeUtf8::Binary(v) => MaybeUtf8Serde::Binary(BASE64_URL_SAFE_NO_PAD.encode(v)), - } - .serialize(serializer) - } -} - -impl From> for MaybeUtf8 { - fn from(value: Vec) -> Self { - match String::from_utf8(value) { - Ok(value) => Self::Utf8(value), - Err(e) => Self::Binary(e.into_bytes()), - } - } -} - -impl From for MaybeUtf8 { - fn from(value: String) -> Self { - Self::Utf8(value) - } -} - -impl From for MaybeUtf8 { - fn from(value: PathBuf) -> Self { - Self::from(value.into_os_string().into_encoded_bytes()) - } -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize)] -#[serde(rename = "File")] -pub struct ExternalJobCacheV2File<'a> { - pub name: MaybeUtf8, - pub contents: Cow<'a, MaybeUtf8>, -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct ExternalJobCacheV2Files(pub BTreeMap); - -impl Serialize for ExternalJobCacheV2Files { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.collect_seq( - self.0 - .iter() - .map(|(name, contents)| ExternalJobCacheV2File { - name: name.clone().into(), - contents: Cow::Borrowed(contents), - }), - ) - } -} - -impl<'de> Deserialize<'de> for ExternalJobCacheV2Files { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Ok(Self( - Vec::deserialize(deserializer)? - .into_iter() - .map(|ExternalJobCacheV2File { name, contents }| { - (name.as_path().to_path_buf(), contents.into_owned()) - }) - .collect(), - )) - } -} - -#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] -#[serde(rename = "ExternalJobCache")] -pub struct ExternalJobCacheV2 { - pub version: ExternalJobCacheVersion, - pub inputs_hash: blake3::Hash, - pub stdout_stderr: String, - pub result: Result, -} - -impl ExternalJobCacheV2 { - fn read_from_file(cache_json_path: Interned) -> eyre::Result { - let cache_str = std::fs::read_to_string(&*cache_json_path) - .wrap_err_with(|| format!("can't read {cache_json_path:?}"))?; - serde_json::from_str(&cache_str) - .wrap_err_with(|| format!("can't decode {cache_json_path:?}")) - } - fn write_to_file(&self, cache_json_path: Interned) -> eyre::Result<()> { - let cache_str = serde_json::to_string_pretty(&self).expect("serialization can't fail"); - std::fs::write(&*cache_json_path, cache_str) - .wrap_err_with(|| format!("can't write {cache_json_path:?}")) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct ExternalJobCaching { - cache_json_path: Interned, - run_even_if_cached: bool, -} - -#[derive(Default)] -struct JobCacheHasher(blake3::Hasher); - -impl JobCacheHasher { - fn hash_size(&mut self, size: usize) { - self.0.update(&u64::to_le_bytes( - size.try_into().expect("size should fit in u64"), - )); - } - fn hash_sized_bytes(&mut self, bytes: &[u8]) { - self.hash_size(bytes.len()); - self.0.update(bytes); - } - fn hash_sized_os_str(&mut self, s: &OsStr) { - self.hash_sized_bytes(s.as_encoded_bytes()); - } - fn hash_iter>( - &mut self, - iter: I, - mut f: F, - ) { - let iter = iter.into_iter(); - self.hash_size(iter.len()); - iter.for_each(|item| f(self, item)); - } - fn try_hash_iter< - F: FnMut(&mut Self, I::Item) -> Result<(), E>, - E, - I: IntoIterator, - >( - &mut self, - iter: I, - mut f: F, - ) -> Result<(), E> { - let mut iter = iter.into_iter(); - self.hash_size(iter.len()); - iter.try_for_each(|item| f(self, item)) - } -} - -fn write_file_atomically_no_clobber C, C: AsRef<[u8]>>( - path: impl AsRef, - containing_dir: impl AsRef, - contents: F, -) -> std::io::Result<()> { - let path = path.as_ref(); - let containing_dir = containing_dir.as_ref(); - if !matches!(std::fs::exists(&path), Ok(true)) { - // use File::create_new rather than tempfile's code to get normal file permissions rather than mode 600 on Unix. - let mut file = tempfile::Builder::new() - .make_in(containing_dir, |path| std::fs::File::create_new(path))?; - file.write_all(contents().as_ref())?; // write all in one operation to avoid a bunch of tiny writes - file.into_temp_path().persist_noclobber(path)?; - } - Ok(()) -} - -impl ExternalJobCaching { - pub fn get_cache_dir_from_output_dir(output_dir: impl AsRef) -> PathBuf { - output_dir.as_ref().join(".fayalite-job-cache") - } - pub fn make_cache_dir( - cache_dir: impl AsRef, - application_name: &str, - ) -> std::io::Result<()> { - let cache_dir = cache_dir.as_ref(); - std::fs::create_dir_all(cache_dir)?; - write_file_atomically_no_clobber(cache_dir.join("CACHEDIR.TAG"), cache_dir, || { - format!( - "Signature: 8a477f597d28d172789f06886806bc55\n\ - # This file is a cache directory tag created by {application_name}.\n\ - # For information about cache directory tags see https://bford.info/cachedir/\n" - ) - })?; - write_file_atomically_no_clobber(cache_dir.join(".gitignore"), cache_dir, || { - format!( - "# This is a cache directory created by {application_name}.\n\ - # ignore all files\n\ - *\n" - ) - }) - } - pub fn new( - output_dir: impl AsRef, - application_name: &str, - json_file_stem: impl AsRef, - run_even_if_cached: bool, - ) -> std::io::Result { - let cache_dir = Self::get_cache_dir_from_output_dir(output_dir); - Self::make_cache_dir(&cache_dir, application_name)?; - let mut cache_json_path = cache_dir; - cache_json_path.push(json_file_stem.as_ref()); - cache_json_path.set_extension("json"); - Ok(Self { - cache_json_path: Path::intern_owned(cache_json_path), - run_even_if_cached, - }) - } - fn write_stdout_stderr(stdout_stderr: &str) { - if stdout_stderr == "" { - return; - } - // use print! so output goes to Rust test output capture - if stdout_stderr.ends_with('\n') { - print!("{stdout_stderr}"); - } else { - println!("{stdout_stderr}"); - } - } - /// returns `Err(_)` if reading the cache failed, otherwise returns `Ok(_)` with the results from the cache - fn run_from_cache( - self, - inputs_hash: blake3::Hash, - output_file_paths: impl IntoIterator>, - ) -> Result, ()> { - if self.run_even_if_cached { - return Err(()); - } - let Ok(ExternalJobCacheV2 { - version: ExternalJobCacheVersion::CURRENT, - inputs_hash: cached_inputs_hash, - stdout_stderr, - result, - }) = ExternalJobCacheV2::read_from_file(self.cache_json_path) - else { - return Err(()); - }; - if inputs_hash != cached_inputs_hash { - return Err(()); - } - match result { - Ok(outputs) => { - for output_file_path in output_file_paths { - let Some(output_data) = outputs.0.get(&*output_file_path) else { - if let Ok(true) = std::fs::exists(&*output_file_path) { - // assume the existing file is the correct one - continue; - } - return Err(()); - }; - let Ok(()) = std::fs::write(&*output_file_path, output_data.as_bytes()) else { - return Err(()); - }; - } - Self::write_stdout_stderr(&stdout_stderr); - Ok(Ok(())) - } - Err(error) => { - Self::write_stdout_stderr(&stdout_stderr); - Ok(Err(error)) - } - } - } - fn make_command( - command_line: Interned<[Interned]>, - ) -> eyre::Result { - ensure!(!command_line.is_empty(), "command line must not be empty"); - let mut cmd = std::process::Command::new(&*command_line[0]); - cmd.args(command_line[1..].iter().map(|arg| &**arg)) - .stdin(std::process::Stdio::null()); - Ok(cmd) - } - pub fn run( - self, - command_line: Interned<[Interned]>, - input_file_paths: impl IntoIterator>, - output_file_paths: impl IntoIterator> + Clone, - run_fn: F, - exit_status_to_error: impl FnOnce(ExitStatus) -> eyre::Report, - ) -> eyre::Result<()> - where - F: FnOnce(std::process::Command) -> eyre::Result>, - { - let mut hasher = JobCacheHasher::default(); - hasher.hash_iter(command_line.iter(), |hasher, arg| { - hasher.hash_sized_os_str(arg) - }); - let mut input_file_paths = - Vec::<&Path>::from_iter(input_file_paths.into_iter().map(Interned::into_inner)); - input_file_paths.sort_unstable(); - input_file_paths.dedup(); - hasher.try_hash_iter( - &input_file_paths, - |hasher, input_file_path| -> eyre::Result<()> { - hasher.hash_sized_os_str(input_file_path.as_ref()); - hasher.hash_sized_bytes( - &std::fs::read(input_file_path).wrap_err_with(|| { - format!("can't read job input file: {input_file_path:?}") - })?, - ); - Ok(()) - }, - )?; - let inputs_hash = hasher.0.finalize(); - match self.run_from_cache(inputs_hash, output_file_paths.clone()) { - Ok(result) => return result.map_err(|e| eyre!(e)), - Err(()) => {} - } - let (pipe_reader, stdout, stderr) = std::io::pipe() - .and_then(|(r, w)| Ok((r, w.try_clone()?, w))) - .wrap_err_with(|| format!("when trying to create a pipe to run: {command_line:?}"))?; - let mut cmd = Self::make_command(command_line)?; - cmd.stdout(stdout).stderr(stderr); - let mut stdout_stderr = String::new(); - let result = std::thread::scope(|scope| { - std::thread::Builder::new() - .name(format!("stdout:{}", command_line[0].display())) - .spawn_scoped(scope, || { - let _ = streaming_read_utf8(std::io::BufReader::new(pipe_reader), |s| { - stdout_stderr.push_str(s); - // use print! so output goes to Rust test output capture - print!("{s}"); - std::io::Result::Ok(()) - }); - if !stdout_stderr.is_empty() && !stdout_stderr.ends_with('\n') { - println!(); - } - }) - .expect("spawn shouldn't fail"); - run_fn(cmd) - })?; - if let Err(exit_status) = result { - // check if the user may have terminated it or something, don't cache the failure - let user_maybe_terminated; - #[cfg(unix)] - { - user_maybe_terminated = std::os::unix::process::ExitStatusExt::signal(&exit_status) - .is_some() - || exit_status.code().is_none_or(|code| code > 1); - } - #[cfg(not(unix))] - { - user_maybe_terminated = !exit_status.success(); - } - if user_maybe_terminated { - let _ = std::fs::remove_file(self.cache_json_path); - return Err(exit_status_to_error(exit_status)); - } - } - let result = result.map_err(exit_status_to_error); - ExternalJobCacheV2 { - version: ExternalJobCacheVersion::CURRENT, - inputs_hash, - stdout_stderr, - result: match &result { - Ok(()) => Ok(ExternalJobCacheV2Files(Result::from_iter( - output_file_paths.into_iter().map( - |output_file_path: Interned| -> eyre::Result<_> { - let output_file_path = &*output_file_path; - Ok(( - PathBuf::from(output_file_path), - MaybeUtf8::from(std::fs::read(output_file_path).wrap_err_with( - || format!("can't read job output file: {output_file_path:?}"), - )?), - )) - }, - ), - )?)), - Err(e) => Err(format!("{e:#}")), - }, - } - .write_to_file(self.cache_json_path)?; - result - } - pub fn run_maybe_cached( - this: Option, - command_line: Interned<[Interned]>, - input_file_paths: impl IntoIterator>, - output_file_paths: impl IntoIterator> + Clone, - run_fn: F, - exit_status_to_error: impl FnOnce(ExitStatus) -> eyre::Report, - ) -> eyre::Result<()> - where - F: FnOnce(std::process::Command) -> eyre::Result>, - { - match this { - Some(this) => this.run( - command_line, - input_file_paths, - output_file_paths, - run_fn, - exit_status_to_error, - ), - None => run_fn(Self::make_command(command_line)?)?.map_err(exit_status_to_error), - } - } -} - -#[derive(Clone, Eq, Hash)] -pub struct ExternalCommandJobKind(PhantomData); - -impl fmt::Debug for ExternalCommandJobKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ExternalCommandJobKind<{}>", std::any::type_name::()) - } -} - -impl PartialEq for ExternalCommandJobKind { - fn eq(&self, _other: &Self) -> bool { - true - } -} - -impl Ord for ExternalCommandJobKind { - fn cmp(&self, _other: &Self) -> std::cmp::Ordering { - std::cmp::Ordering::Equal - } -} - -impl PartialOrd for ExternalCommandJobKind { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Default for ExternalCommandJobKind { - fn default() -> Self { - Self(PhantomData) - } -} - -impl Copy for ExternalCommandJobKind {} - -impl ExternalCommandJobKind { - pub const fn new() -> Self { - Self(PhantomData) - } -} - -#[derive(Copy, Clone)] -struct ExternalProgramPathValueParser(ExternalProgram); - -fn parse_which_result( - which_result: which::Result, - program_name: impl Into, - program_path_arg_name: impl FnOnce() -> String, -) -> Result, ResolveProgramPathError> { - let which_result = match which_result { - Ok(v) => v, - Err(inner) => { - return Err(ResolveProgramPathError { - inner, - program_name: program_name.into(), - program_path_arg_name: program_path_arg_name(), - }); - } - }; - Ok(which_result.intern_deref()) -} - -impl clap::builder::TypedValueParser for ExternalProgramPathValueParser { - type Value = Interned; - - fn parse_ref( - &self, - cmd: &clap::Command, - arg: Option<&clap::Arg>, - value: &OsStr, - ) -> clap::error::Result { - let program_path_arg_name = self.0.program_path_arg_name; - OsStringValueParser::new() - .try_map(move |program_name| { - parse_which_result(which::which(&program_name), program_name, || { - program_path_arg_name.into() - }) - }) - .parse_ref(cmd, arg, value) - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)] -#[group(id = T::args_group_id())] -#[non_exhaustive] -pub struct ExternalCommandArgs { - #[command(flatten)] - pub program_path: ExternalProgramPath, - #[arg( - name = Interned::into_inner(T::run_even_if_cached_arg_name()), - long = T::run_even_if_cached_arg_name(), - )] - pub run_even_if_cached: bool, - #[command(flatten)] - pub additional_args: T::AdditionalArgs, -} - -#[derive(Clone, Debug)] -pub struct ResolveProgramPathError { - inner: which::Error, - program_name: OsString, - program_path_arg_name: String, -} - -impl fmt::Display for ResolveProgramPathError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - inner, - program_name, - program_path_arg_name, - } = self; - write!( - f, - "{program_path_arg_name}: failed to resolve {program_name:?} to a valid program: {inner}", - ) - } -} - -impl std::error::Error for ResolveProgramPathError {} - -pub fn resolve_program_path( - program_name: Option<&OsStr>, - default_program_name: impl AsRef, - program_path_env_var_name: Option<&OsStr>, -) -> Result, ResolveProgramPathError> { - let default_program_name = default_program_name.as_ref(); - let owned_program_name; - let program_name = if let Some(program_name) = program_name { - program_name - } else if let Some(v) = program_path_env_var_name.and_then(std::env::var_os) { - owned_program_name = v; - &owned_program_name - } else { - default_program_name - }; - parse_which_result(which::which(program_name), program_name, || { - default_program_name.display().to_string() - }) -} - -impl ExternalCommandArgs { - pub fn with_resolved_program_path( - program_path: Interned, - additional_args: T::AdditionalArgs, - ) -> Self { - Self::new( - ExternalProgramPath::with_resolved_program_path(program_path), - additional_args, - ) - } - pub fn new( - program_path: ExternalProgramPath, - additional_args: T::AdditionalArgs, - ) -> Self { - Self { - program_path, - run_even_if_cached: false, - additional_args, - } - } - pub fn resolve_program_path( - program_name: Option<&OsStr>, - additional_args: T::AdditionalArgs, - ) -> Result { - Ok(Self::new( - ExternalProgramPath::resolve_program_path(program_name)?, - additional_args, - )) - } -} - -impl ToArgs for ExternalCommandArgs { - fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) { - let Self { - program_path, - run_even_if_cached, - ref additional_args, - } = *self; - program_path.to_args(args); - if run_even_if_cached { - args.write_display_arg(format_args!("--{}", T::run_even_if_cached_arg_name())); - } - additional_args.to_args(args); - } -} - -#[derive(Copy, Clone)] -struct ExternalCommandJobParams { - command_params: CommandParams, - inputs: Interned<[JobItemName]>, - outputs: Interned<[JobItemName]>, - output_paths: Interned<[Interned]>, -} - -impl ExternalCommandJobParams { - fn new(job: &ExternalCommandJob) -> Self { - let output_paths = T::output_paths(job); - let mut command_line = ArgsWriter(vec![job.program_path.as_interned_os_str()]); - T::command_line_args(job, &mut command_line); - Self { - command_params: CommandParams { - command_line: Intern::intern_owned(command_line.0), - current_dir: T::current_dir(job), - }, - inputs: T::inputs(job), - outputs: output_paths - .iter() - .map(|&path| JobItemName::Path { path }) - .collect(), - output_paths, - } - } -} - -#[derive(Deserialize, Serialize)] -pub struct ExternalCommandJob { - additional_job_data: T::AdditionalJobData, - program_path: Interned, - output_dir: Interned, - run_even_if_cached: bool, - #[serde(skip)] - params_cache: OnceLock, -} - -impl Eq for ExternalCommandJob {} - -impl> Clone for ExternalCommandJob { - fn clone(&self) -> Self { - let Self { - ref additional_job_data, - program_path, - output_dir, - run_even_if_cached, - ref params_cache, - } = *self; - Self { - additional_job_data: additional_job_data.clone(), - program_path, - output_dir, - run_even_if_cached, - params_cache: params_cache.clone(), - } - } -} - -impl fmt::Debug for ExternalCommandJob { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - additional_job_data, - program_path, - output_dir, - run_even_if_cached, - params_cache: _, - } = self; - write!(f, "ExternalCommandJob<{}>", std::any::type_name::())?; - f.debug_struct("") - .field("additional_job_data", additional_job_data) - .field("program_path", program_path) - .field("output_dir", output_dir) - .field("run_even_if_cached", run_even_if_cached) - .finish() - } -} - -impl PartialEq for ExternalCommandJob { - fn eq(&self, other: &Self) -> bool { - let Self { - additional_job_data, - program_path, - output_dir, - run_even_if_cached, - params_cache: _, - } = self; - *additional_job_data == other.additional_job_data - && *program_path == other.program_path - && *output_dir == other.output_dir - && *run_even_if_cached == other.run_even_if_cached - } -} - -impl Hash for ExternalCommandJob { - fn hash(&self, state: &mut H) { - let Self { - additional_job_data, - program_path, - output_dir, - run_even_if_cached, - params_cache: _, - } = self; - additional_job_data.hash(state); - program_path.hash(state); - output_dir.hash(state); - run_even_if_cached.hash(state); - } -} - -impl ExternalCommandJob { - pub fn additional_job_data(&self) -> &T::AdditionalJobData { - &self.additional_job_data - } - pub fn program_path(&self) -> Interned { - self.program_path - } - pub fn output_dir(&self) -> Interned { - self.output_dir - } - pub fn run_even_if_cached(&self) -> bool { - self.run_even_if_cached - } - fn params(&self) -> &ExternalCommandJobParams { - self.params_cache - .get_or_init(|| ExternalCommandJobParams::new(self)) - } - pub fn command_params(&self) -> CommandParams { - self.params().command_params - } - pub fn inputs(&self) -> Interned<[JobItemName]> { - self.params().inputs - } - pub fn output_paths(&self) -> Interned<[Interned]> { - self.params().output_paths - } - pub fn outputs(&self) -> Interned<[JobItemName]> { - self.params().outputs - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct ExternalProgramPath { - program_path: Interned, - _phantom: PhantomData, -} - -impl ExternalProgramPath { - pub fn with_resolved_program_path(program_path: Interned) -> Self { - Self { - program_path, - _phantom: PhantomData, - } - } - pub fn resolve_program_path( - program_name: Option<&OsStr>, - ) -> Result { - let ExternalProgram { - default_program_name, - program_path_arg_name: _, - program_path_arg_value_name: _, - program_path_env_var_name, - } = ExternalProgram::new::(); - Ok(Self { - program_path: resolve_program_path( - program_name, - default_program_name, - program_path_env_var_name.as_ref().map(OsStr::new), - )?, - _phantom: PhantomData, - }) - } - pub fn program_path(&self) -> Interned { - self.program_path - } -} - -impl fmt::Debug for ExternalProgramPath { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - program_path, - _phantom: _, - } = self; - write!(f, "ExternalProgramPath<{}>", std::any::type_name::())?; - f.debug_tuple("").field(program_path).finish() - } -} - -impl clap::FromArgMatches for ExternalProgramPath { - fn from_arg_matches(matches: &clap::ArgMatches) -> Result { - let id = Interned::into_inner(ExternalProgram::new::().program_path_arg_name); - // don't remove argument so later instances of Self can use it too - let program_path = *matches.get_one(id).expect("arg should always be present"); - Ok(Self { - program_path, - _phantom: PhantomData, - }) - } - - fn update_from_arg_matches(&mut self, matches: &clap::ArgMatches) -> Result<(), clap::Error> { - *self = Self::from_arg_matches(matches)?; - Ok(()) - } -} - -impl clap::Args for ExternalProgramPath { - fn augment_args(cmd: clap::Command) -> clap::Command { - let external_program @ ExternalProgram { - default_program_name, - program_path_arg_name, - program_path_arg_value_name, - program_path_env_var_name, - } = ExternalProgram::new::(); - let arg = cmd - .get_arguments() - .find(|arg| *arg.get_id().as_str() == *program_path_arg_name); - if let Some(arg) = arg { - // don't insert duplicate arguments. - // check that the previous argument actually matches this argument: - assert!(!arg.is_required_set()); - assert!(matches!(arg.get_action(), clap::ArgAction::Set)); - assert_eq!(arg.get_long(), Some(&*program_path_arg_name)); - assert_eq!( - arg.get_value_names(), - Some(&[clap::builder::Str::from(program_path_arg_value_name)][..]) - ); - assert_eq!( - arg.get_env(), - program_path_env_var_name.as_ref().map(OsStr::new) - ); - assert_eq!( - arg.get_default_values(), - &[OsStr::new(&default_program_name)] - ); - assert_eq!(arg.get_value_hint(), clap::ValueHint::CommandName); - cmd - } else { - cmd.arg( - clap::Arg::new(Interned::into_inner(program_path_arg_name)) - .required(false) - .value_parser(ExternalProgramPathValueParser(external_program)) - .action(clap::ArgAction::Set) - .long(program_path_arg_name) - .value_name(program_path_arg_value_name) - .env(program_path_env_var_name.map(Interned::into_inner)) - .default_value(default_program_name) - .value_hint(clap::ValueHint::CommandName), - ) - } - } - - fn augment_args_for_update(cmd: clap::Command) -> clap::Command { - Self::augment_args(cmd) - } -} - -impl ToArgs for ExternalProgramPath { - fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) { - let ExternalProgram { - program_path_arg_name, - .. - } = ExternalProgram::new::(); - let Self { - program_path, - _phantom: _, - } = self; - if args.get_long_option_eq(program_path_arg_name) != Some(program_path.as_os_str()) { - args.write_long_option_eq(program_path_arg_name, program_path); - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -#[non_exhaustive] -pub struct ExternalProgram { - default_program_name: Interned, - program_path_arg_name: Interned, - program_path_arg_value_name: Interned, - program_path_env_var_name: Option>, -} - -impl ExternalProgram { - pub fn new() -> Self { - Self { - default_program_name: T::default_program_name(), - program_path_arg_name: T::program_path_arg_name(), - program_path_arg_value_name: T::program_path_arg_value_name(), - program_path_env_var_name: T::program_path_env_var_name(), - } - } - pub fn default_program_name(&self) -> Interned { - self.default_program_name - } - pub fn program_path_arg_name(&self) -> Interned { - self.program_path_arg_name - } - pub fn program_path_arg_value_name(&self) -> Interned { - self.program_path_arg_value_name - } - pub fn program_path_env_var_name(&self) -> Option> { - self.program_path_env_var_name - } -} - -impl From for ExternalProgram { - fn from(_value: T) -> Self { - Self::new::() - } -} - -impl From for Interned { - fn from(_value: T) -> Self { - ExternalProgram::new::().intern_sized() - } -} - -pub trait ExternalProgramTrait: - 'static + Send + Sync + Hash + Ord + fmt::Debug + Default + Copy -{ - fn program_path_arg_name() -> Interned { - Self::default_program_name() - } - fn program_path_arg_value_name() -> Interned { - Intern::intern_owned(Self::program_path_arg_name().to_uppercase()) - } - fn default_program_name() -> Interned; - fn program_path_env_var_name() -> Option> { - Some(Intern::intern_owned( - Self::program_path_arg_name() - .to_uppercase() - .replace('-', "_"), - )) - } -} - -pub trait ExternalCommand: 'static + Send + Sync + Hash + Eq + fmt::Debug + Sized + Clone { - type AdditionalArgs: ToArgs; - type AdditionalJobData: 'static - + Send - + Sync - + Hash - + Eq - + fmt::Debug - + Serialize - + DeserializeOwned; - type BaseJobPosition; - type Dependencies: JobDependenciesHasBase; - type ExternalProgram: ExternalProgramTrait; - fn dependencies() -> Self::Dependencies; - fn args_to_jobs( - args: JobArgsAndDependencies>, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result<( - Self::AdditionalJobData, - ::JobsAndKinds, - )>; - fn inputs(job: &ExternalCommandJob) -> Interned<[JobItemName]>; - fn output_paths(job: &ExternalCommandJob) -> Interned<[Interned]>; - fn command_line_args(job: &ExternalCommandJob, args: &mut W); - fn current_dir(job: &ExternalCommandJob) -> Option>; - fn job_kind_name() -> Interned; - fn args_group_id() -> clap::Id { - Interned::into_inner(Self::job_kind_name()).into() - } - fn run_even_if_cached_arg_name() -> Interned { - Intern::intern_owned(format!("{}-run-even-if-cached", Self::job_kind_name())) - } - fn subcommand_hidden() -> bool { - false - } -} - -impl JobKind for ExternalCommandJobKind { - type Args = ExternalCommandArgs; - type Job = ExternalCommandJob; - type Dependencies = T::Dependencies; - - fn dependencies(self) -> Self::Dependencies { - T::dependencies() - } - - fn args_to_jobs( - args: JobArgsAndDependencies, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result> { - let JobKindAndArgs { - kind, - args: - ExternalCommandArgs { - program_path: - ExternalProgramPath { - program_path, - _phantom: _, - }, - run_even_if_cached, - additional_args: _, - }, - } = args.args; - let (additional_job_data, dependencies) = T::args_to_jobs(args, params, global_params)?; - let base_job = T::Dependencies::base_job(&dependencies); - let job = ExternalCommandJob { - additional_job_data, - program_path, - output_dir: base_job.output_dir(), - run_even_if_cached: base_job.run_even_if_cached() | run_even_if_cached, - params_cache: OnceLock::new(), - }; - job.params(); // fill cache - Ok(JobAndDependencies { - job: JobAndKind { kind, job }, - dependencies, - }) - } - - fn inputs(self, job: &Self::Job) -> Interned<[JobItemName]> { - job.inputs() - } - - fn outputs(self, job: &Self::Job) -> Interned<[JobItemName]> { - job.outputs() - } - - fn name(self) -> Interned { - T::job_kind_name() - } - - fn external_command_params(self, job: &Self::Job) -> Option { - Some(job.command_params()) - } - - fn run( - self, - job: &Self::Job, - inputs: &[JobItem], - _params: &JobParams, - global_params: &GlobalParams, - acquired_job: &mut AcquiredJob, - ) -> eyre::Result> { - assert!( - inputs.iter().map(JobItem::name).eq(job.inputs()), - "{}\ninputs:\n{inputs:?}\njob.inputs():\n{:?}", - std::any::type_name::(), - job.inputs(), - ); - let CommandParams { - command_line, - current_dir, - } = job.command_params(); - ExternalJobCaching::new( - &job.output_dir, - &global_params.application_name(), - &T::job_kind_name(), - job.run_even_if_cached, - )? - .run( - command_line, - inputs - .iter() - .flat_map(|item| match item { - JobItem::Path { path } => std::slice::from_ref(path), - JobItem::DynamicPaths { - paths, - source_job_name: _, - } => paths, - }) - .copied(), - job.output_paths(), - |mut cmd| { - if let Some(current_dir) = current_dir { - cmd.current_dir(current_dir); - } - let status = acquired_job.run_command(cmd, |cmd| cmd.status())?; - if !status.success() { - Ok(Err(status)) - } else { - Ok(Ok(())) - } - }, - |status| eyre!("running {command_line:?} failed: {status}"), - )?; - Ok(job - .output_paths() - .iter() - .map(|&path| JobItem::Path { path }) - .collect()) - } - - fn subcommand_hidden(self) -> bool { - T::subcommand_hidden() - } - - fn external_program(self) -> Option> { - Some(ExternalProgram::new::().intern_sized()) - } -} diff --git a/crates/fayalite/src/build/firrtl.rs b/crates/fayalite/src/build/firrtl.rs deleted file mode 100644 index b5574a9..0000000 --- a/crates/fayalite/src/build/firrtl.rs +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - build::{ - BaseJob, BaseJobKind, CommandParams, DynJobKind, GlobalParams, JobAndDependencies, - JobArgsAndDependencies, JobItem, JobItemName, JobKind, JobKindAndDependencies, JobParams, - ToArgs, WriteArgs, - }, - firrtl::{ExportOptions, FileBackend}, - intern::{Intern, InternSlice, Interned}, - util::job_server::AcquiredJob, -}; -use clap::Args; -use serde::{Deserialize, Serialize}; -use std::path::{Path, PathBuf}; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] -pub struct FirrtlJobKind; - -#[derive(Args, Debug, Clone, Hash, PartialEq, Eq)] -#[group(id = "Firrtl")] -#[non_exhaustive] -pub struct FirrtlArgs { - #[command(flatten)] - pub export_options: ExportOptions, -} - -impl ToArgs for FirrtlArgs { - fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) { - let Self { export_options } = self; - export_options.to_args(args); - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Firrtl { - base: BaseJob, - export_options: ExportOptions, -} - -impl Firrtl { - fn make_firrtl_file_backend(&self) -> FileBackend { - FileBackend { - dir_path: PathBuf::from(&*self.base.output_dir()), - top_fir_file_stem: Some(self.base.file_stem().into()), - circuit_name: None, - } - } - pub fn firrtl_file(&self) -> Interned { - self.base.file_with_ext("fir") - } -} - -impl JobKind for FirrtlJobKind { - type Args = FirrtlArgs; - type Job = Firrtl; - type Dependencies = JobKindAndDependencies; - - fn dependencies(self) -> Self::Dependencies { - JobKindAndDependencies::new(BaseJobKind) - } - - fn args_to_jobs( - args: JobArgsAndDependencies, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result> { - args.args_to_jobs_simple( - params, - global_params, - |_kind, FirrtlArgs { export_options }, dependencies| { - Ok(Firrtl { - base: dependencies.get_job::().clone(), - export_options, - }) - }, - ) - } - - fn inputs(self, job: &Self::Job) -> Interned<[JobItemName]> { - [JobItemName::Path { - path: job.base.output_dir(), - }] - .intern_slice() - } - - fn outputs(self, job: &Self::Job) -> Interned<[JobItemName]> { - [JobItemName::Path { - path: job.firrtl_file(), - }] - .intern_slice() - } - - fn name(self) -> Interned { - "firrtl".intern() - } - - fn external_command_params(self, _job: &Self::Job) -> Option { - None - } - - fn run( - self, - job: &Self::Job, - inputs: &[JobItem], - params: &JobParams, - _global_params: &GlobalParams, - _acquired_job: &mut AcquiredJob, - ) -> eyre::Result> { - let [JobItem::Path { path: input_path }] = *inputs else { - panic!("wrong inputs, expected a single `Path`"); - }; - assert_eq!(input_path, job.base.output_dir()); - crate::firrtl::export( - job.make_firrtl_file_backend(), - params.main_module(), - job.export_options, - )?; - Ok(vec![JobItem::Path { - path: job.firrtl_file(), - }]) - } -} - -pub(crate) fn built_in_job_kinds() -> impl IntoIterator { - [DynJobKind::new(FirrtlJobKind)] -} diff --git a/crates/fayalite/src/build/formal.rs b/crates/fayalite/src/build/formal.rs deleted file mode 100644 index 69c0f2c..0000000 --- a/crates/fayalite/src/build/formal.rs +++ /dev/null @@ -1,388 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - build::{ - BaseJob, CommandParams, DynJobKind, GetJobPositionDependencies, GlobalParams, - JobAndDependencies, JobArgsAndDependencies, JobDependencies, JobItem, JobItemName, JobKind, - JobKindAndDependencies, JobParams, ToArgs, WriteArgs, - external::{ - ExternalCommand, ExternalCommandJob, ExternalCommandJobKind, ExternalProgramTrait, - }, - verilog::{UnadjustedVerilog, VerilogDialect, VerilogJob, VerilogJobKind}, - }, - intern::{Intern, InternSlice, Interned}, - module::NameId, - testing::FormalMode, - util::job_server::AcquiredJob, -}; -use clap::Args; -use eyre::Context; -use serde::{Deserialize, Serialize}; -use std::{ - ffi::{OsStr, OsString}, - fmt::{self, Write}, - path::Path, -}; - -#[derive(Args, Clone, Debug, PartialEq, Eq, Hash)] -#[non_exhaustive] -pub struct FormalArgs { - #[arg(long = "sby-extra-arg", value_name = "ARG")] - pub sby_extra_args: Vec, - #[arg(long, default_value_t)] - pub formal_mode: FormalMode, - #[arg(long, default_value_t = Self::DEFAULT_DEPTH)] - pub formal_depth: u64, - #[arg(long, default_value = Self::DEFAULT_SOLVER)] - pub formal_solver: String, - #[arg(long = "smtbmc-extra-arg", value_name = "ARG")] - pub smtbmc_extra_args: Vec, -} - -impl FormalArgs { - pub const DEFAULT_DEPTH: u64 = 20; - pub const DEFAULT_SOLVER: &'static str = "z3"; -} - -impl ToArgs for FormalArgs { - fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) { - let Self { - sby_extra_args, - formal_mode, - formal_depth, - formal_solver, - smtbmc_extra_args, - } = self; - for arg in sby_extra_args { - args.write_long_option_eq("sby-extra-arg", arg); - } - args.write_display_args([ - format_args!("--formal-mode={formal_mode}"), - format_args!("--formal-depth={formal_depth}"), - format_args!("--formal-solver={formal_solver}"), - ]); - for arg in smtbmc_extra_args { - args.write_long_option_eq("smtbmc-extra-arg", arg); - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] -pub struct WriteSbyFileJobKind; - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)] -pub struct WriteSbyFileJob { - sby_extra_args: Interned<[Interned]>, - formal_mode: FormalMode, - formal_depth: u64, - formal_solver: Interned, - smtbmc_extra_args: Interned<[Interned]>, - sby_file: Interned, - output_dir: Interned, - main_verilog_file: Interned, -} - -impl WriteSbyFileJob { - pub fn sby_extra_args(&self) -> Interned<[Interned]> { - self.sby_extra_args - } - pub fn formal_mode(&self) -> FormalMode { - self.formal_mode - } - pub fn formal_depth(&self) -> u64 { - self.formal_depth - } - pub fn formal_solver(&self) -> Interned { - self.formal_solver - } - pub fn smtbmc_extra_args(&self) -> Interned<[Interned]> { - self.smtbmc_extra_args - } - pub fn sby_file(&self) -> Interned { - self.sby_file - } - pub fn output_dir(&self) -> Interned { - self.output_dir - } - pub fn main_verilog_file(&self) -> Interned { - self.main_verilog_file - } - fn write_sby( - &self, - output: &mut OsString, - additional_files: &[Interned], - main_module_name_id: NameId, - ) -> eyre::Result<()> { - let Self { - sby_extra_args: _, - formal_mode, - formal_depth, - formal_solver, - smtbmc_extra_args, - sby_file: _, - output_dir: _, - main_verilog_file, - } = self; - write!( - output, - "[options]\n\ - mode {formal_mode}\n\ - depth {formal_depth}\n\ - wait on\n\ - \n\ - [engines]\n\ - smtbmc {formal_solver} -- --" - ) - .expect("writing to OsString can't fail"); - for i in smtbmc_extra_args { - output.push(" "); - output.push(i); - } - output.push( - "\n\ - \n\ - [script]\n", - ); - for verilog_file in VerilogJob::all_verilog_files(*main_verilog_file, additional_files)? { - output.push("read_verilog -sv -formal \""); - output.push(verilog_file); - output.push("\"\n"); - } - let circuit_name = crate::firrtl::get_circuit_name(main_module_name_id); - // workaround for wires disappearing -- set `keep` on all wires - writeln!( - output, - "hierarchy -top {circuit_name}\n\ - proc\n\ - setattr -set keep 1 w:\\*\n\ - prep", - ) - .expect("writing to OsString can't fail"); - Ok(()) - } -} - -impl JobKind for WriteSbyFileJobKind { - type Args = FormalArgs; - type Job = WriteSbyFileJob; - type Dependencies = JobKindAndDependencies; - - fn dependencies(self) -> Self::Dependencies { - Default::default() - } - - fn args_to_jobs( - mut args: JobArgsAndDependencies, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result> { - args.dependencies - .dependencies - .args - .args - .additional_args - .verilog_dialect - .get_or_insert(VerilogDialect::Yosys); - args.args_to_jobs_simple(params, global_params, |_kind, args, dependencies| { - let FormalArgs { - sby_extra_args, - formal_mode, - formal_depth, - formal_solver, - smtbmc_extra_args, - } = args; - let base_job = dependencies.get_job::(); - Ok(WriteSbyFileJob { - sby_extra_args: sby_extra_args.into_iter().map(Interned::from).collect(), - formal_mode, - formal_depth, - formal_solver: formal_solver.intern_deref(), - smtbmc_extra_args: smtbmc_extra_args.into_iter().map(Interned::from).collect(), - sby_file: base_job.file_with_ext("sby"), - output_dir: base_job.output_dir(), - main_verilog_file: dependencies.get_job::().main_verilog_file(), - }) - }) - } - - fn inputs(self, _job: &Self::Job) -> Interned<[JobItemName]> { - [JobItemName::DynamicPaths { - source_job_name: VerilogJobKind.name(), - }] - .intern_slice() - } - - fn outputs(self, job: &Self::Job) -> Interned<[JobItemName]> { - [JobItemName::Path { path: job.sby_file }].intern_slice() - } - - fn name(self) -> Interned { - "write-sby-file".intern() - } - - fn external_command_params(self, _job: &Self::Job) -> Option { - None - } - - fn run( - self, - job: &Self::Job, - inputs: &[JobItem], - params: &JobParams, - _global_params: &GlobalParams, - _acquired_job: &mut AcquiredJob, - ) -> eyre::Result> { - assert!(inputs.iter().map(JobItem::name).eq(self.inputs(job))); - let [additional_files] = inputs else { - unreachable!(); - }; - let additional_files = VerilogJob::unwrap_additional_files(additional_files); - let mut contents = OsString::new(); - job.write_sby( - &mut contents, - additional_files, - params.main_module().name_id(), - )?; - let path = job.sby_file; - std::fs::write(path, contents.as_encoded_bytes()) - .wrap_err_with(|| format!("writing {path:?} failed"))?; - Ok(vec![JobItem::Path { path }]) - } - - fn subcommand_hidden(self) -> bool { - true - } -} - -#[derive(Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] -pub struct Formal { - #[serde(flatten)] - write_sby_file: WriteSbyFileJob, - sby_file_name: Interned, -} - -impl fmt::Debug for Formal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - write_sby_file: - WriteSbyFileJob { - sby_extra_args, - formal_mode, - formal_depth, - formal_solver, - smtbmc_extra_args, - sby_file, - output_dir: _, - main_verilog_file, - }, - sby_file_name, - } = self; - f.debug_struct("Formal") - .field("sby_extra_args", sby_extra_args) - .field("formal_mode", formal_mode) - .field("formal_depth", formal_depth) - .field("formal_solver", formal_solver) - .field("smtbmc_extra_args", smtbmc_extra_args) - .field("sby_file", sby_file) - .field("sby_file_name", sby_file_name) - .field("main_verilog_file", main_verilog_file) - .finish_non_exhaustive() - } -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] -pub struct Symbiyosys; - -impl ExternalProgramTrait for Symbiyosys { - fn default_program_name() -> Interned { - "sby".intern() - } -} - -#[derive(Clone, Hash, PartialEq, Eq, Debug, Args)] -pub struct FormalAdditionalArgs {} - -impl ToArgs for FormalAdditionalArgs { - fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) { - let Self {} = self; - } -} - -impl ExternalCommand for Formal { - type AdditionalArgs = FormalAdditionalArgs; - type AdditionalJobData = Formal; - type BaseJobPosition = GetJobPositionDependencies< - GetJobPositionDependencies< - GetJobPositionDependencies<::BaseJobPosition>, - >, - >; - type Dependencies = JobKindAndDependencies; - type ExternalProgram = Symbiyosys; - - fn dependencies() -> Self::Dependencies { - Default::default() - } - - fn args_to_jobs( - args: JobArgsAndDependencies>, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result<( - Self::AdditionalJobData, - ::JobsAndKinds, - )> { - args.args_to_jobs_external_simple(params, global_params, |args, dependencies| { - let FormalAdditionalArgs {} = args.additional_args; - let write_sby_file = dependencies.get_job::().clone(); - Ok(Formal { - sby_file_name: write_sby_file - .sby_file() - .interned_file_name() - .expect("known to have file name"), - write_sby_file, - }) - }) - } - - fn inputs(job: &ExternalCommandJob) -> Interned<[JobItemName]> { - [ - JobItemName::Path { - path: job.additional_job_data().write_sby_file.sby_file(), - }, - JobItemName::Path { - path: job.additional_job_data().write_sby_file.main_verilog_file(), - }, - JobItemName::DynamicPaths { - source_job_name: VerilogJobKind.name(), - }, - ] - .intern_slice() - } - - fn output_paths(_job: &ExternalCommandJob) -> Interned<[Interned]> { - Interned::default() - } - - fn command_line_args(job: &ExternalCommandJob, args: &mut W) { - // args.write_str_arg("-j1"); // sby seems not to respect job count in parallel mode - args.write_arg("-f"); - args.write_interned_arg(job.additional_job_data().sby_file_name); - args.write_interned_args(job.additional_job_data().write_sby_file.sby_extra_args()); - } - - fn current_dir(job: &ExternalCommandJob) -> Option> { - Some(job.output_dir()) - } - - fn job_kind_name() -> Interned { - "formal".intern() - } -} - -pub(crate) fn built_in_job_kinds() -> impl IntoIterator { - [ - DynJobKind::new(WriteSbyFileJobKind), - DynJobKind::new(ExternalCommandJobKind::::new()), - ] -} diff --git a/crates/fayalite/src/build/graph.rs b/crates/fayalite/src/build/graph.rs deleted file mode 100644 index bed8829..0000000 --- a/crates/fayalite/src/build/graph.rs +++ /dev/null @@ -1,855 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - build::{ - DynJob, GlobalParams, JobItem, JobItemName, JobParams, program_name_for_internal_jobs, - }, - intern::Interned, - platform::DynPlatform, - util::{HashMap, HashSet, job_server::AcquiredJob}, -}; -use eyre::{ContextCompat, eyre}; -use petgraph::{ - algo::{DfsSpace, kosaraju_scc, toposort}, - graph::DiGraph, - visit::{GraphBase, Visitable}, -}; -use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error, ser::SerializeSeq}; -use std::{ - cell::OnceCell, - collections::{BTreeMap, BTreeSet, VecDeque}, - convert::Infallible, - ffi::OsStr, - fmt::{self, Write}, - panic, - rc::Rc, - str::Utf8Error, - sync::mpsc, - thread::{self, ScopedJoinHandle}, -}; - -macro_rules! write_str { - ($s:expr, $($rest:tt)*) => { - write!($s, $($rest)*).expect("String::write_fmt can't fail") - }; -} - -#[derive(Clone, Debug)] -enum JobGraphNode { - Job(DynJob), - Item { - #[allow(dead_code, reason = "name used for debugging")] - name: JobItemName, - source_job: Option, - }, -} - -type JobGraphInner = DiGraph; - -#[derive(Clone, Default)] -pub struct JobGraph { - jobs: HashMap::NodeId>, - items: HashMap::NodeId>, - graph: JobGraphInner, - topological_order: Vec<::NodeId>, - space: DfsSpace<::NodeId, ::Map>, -} - -impl fmt::Debug for JobGraph { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - jobs: _, - items: _, - graph, - topological_order, - space: _, - } = self; - f.debug_struct("JobGraph") - .field("graph", graph) - .field("topological_order", topological_order) - .finish_non_exhaustive() - } -} - -#[derive(Clone, Debug)] -pub enum JobGraphError { - CycleError { - job: DynJob, - output: JobItemName, - }, - MultipleJobsCreateSameOutput { - output_item: JobItemName, - existing_job: DynJob, - new_job: DynJob, - }, -} - -impl std::error::Error for JobGraphError {} - -impl fmt::Display for JobGraphError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::CycleError { job, output } => write!( - f, - "job can't be added to job graph because it would introduce a cyclic dependency through this job output:\n\ - {output:?}\n\ - job:\n{job:?}", - ), - JobGraphError::MultipleJobsCreateSameOutput { - output_item, - existing_job, - new_job, - } => write!( - f, - "job can't be added to job graph because the new job has an output that is also produced by an existing job.\n\ - conflicting output:\n\ - {output_item:?}\n\ - existing job:\n\ - {existing_job:?}\n\ - new job:\n\ - {new_job:?}", - ), - } - } -} - -#[derive(Copy, Clone, Debug)] -enum EscapeForUnixShellState { - DollarSingleQuote, - SingleQuote, - Unquoted, -} - -#[derive(Clone)] -pub struct EscapeForUnixShell<'a> { - state: EscapeForUnixShellState, - prefix: [u8; 3], - bytes: &'a [u8], -} - -impl<'a> fmt::Debug for EscapeForUnixShell<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl<'a> fmt::Display for EscapeForUnixShell<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for c in self.clone() { - f.write_char(c)?; - } - Ok(()) - } -} - -impl<'a> EscapeForUnixShell<'a> { - pub fn new(s: &'a (impl ?Sized + AsRef)) -> Self { - Self::from_bytes(s.as_ref().as_encoded_bytes()) - } - fn make_prefix(bytes: &[u8]) -> [u8; 3] { - let mut prefix = [0; 3]; - prefix[..bytes.len()].copy_from_slice(bytes); - prefix - } - pub fn from_bytes(bytes: &'a [u8]) -> Self { - let mut needs_single_quote = bytes.is_empty(); - for &b in bytes { - match b { - b'!' | b'\'' | b'\"' | b' ' => needs_single_quote = true, - 0..0x20 | 0x7F.. => { - return Self { - state: EscapeForUnixShellState::DollarSingleQuote, - prefix: Self::make_prefix(b"$'"), - bytes, - }; - } - _ => {} - } - } - if needs_single_quote { - Self { - state: EscapeForUnixShellState::SingleQuote, - prefix: Self::make_prefix(b"'"), - bytes, - } - } else { - Self { - state: EscapeForUnixShellState::Unquoted, - prefix: Self::make_prefix(b""), - bytes, - } - } - } -} - -impl Iterator for EscapeForUnixShell<'_> { - type Item = char; - - fn next(&mut self) -> Option { - match &mut self.prefix { - [0, 0, 0] => {} - [0, 0, v] | // find first - [0, v, _] | // non-zero byte - [v, _, _] => { - let retval = *v as char; - *v = 0; - return Some(retval); - } - } - let Some(&next_byte) = self.bytes.split_off_first() else { - return match self.state { - EscapeForUnixShellState::DollarSingleQuote - | EscapeForUnixShellState::SingleQuote => { - self.state = EscapeForUnixShellState::Unquoted; - Some('\'') - } - EscapeForUnixShellState::Unquoted => None, - }; - }; - match self.state { - EscapeForUnixShellState::DollarSingleQuote => match next_byte { - b'\'' | b'\\' => { - self.prefix = Self::make_prefix(&[next_byte]); - Some('\\') - } - b'\t' => { - self.prefix = Self::make_prefix(b"t"); - Some('\\') - } - b'\n' => { - self.prefix = Self::make_prefix(b"n"); - Some('\\') - } - b'\r' => { - self.prefix = Self::make_prefix(b"r"); - Some('\\') - } - 0x20..=0x7E => Some(next_byte as char), - _ => { - self.prefix = [ - b'x', - char::from_digit(next_byte as u32 >> 4, 0x10).expect("known to be in range") - as u8, - char::from_digit(next_byte as u32 & 0xF, 0x10) - .expect("known to be in range") as u8, - ]; - Some('\\') - } - }, - EscapeForUnixShellState::SingleQuote => { - if next_byte == b'\'' { - self.prefix = Self::make_prefix(b"\\''"); - Some('\'') - } else { - Some(next_byte as char) - } - } - EscapeForUnixShellState::Unquoted => match next_byte { - b' ' | b'!' | b'"' | b'#' | b'$' | b'&' | b'\'' | b'(' | b')' | b'*' | b',' - | b';' | b'<' | b'>' | b'?' | b'[' | b'\\' | b']' | b'^' | b'`' | b'{' | b'|' - | b'}' | b'~' => { - self.prefix = Self::make_prefix(&[next_byte]); - Some('\\') - } - _ => Some(next_byte as char), - }, - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -#[non_exhaustive] -pub enum UnixMakefileEscapeKind { - NonRecipe, - RecipeWithoutShellEscaping, - RecipeWithShellEscaping, -} - -#[derive(Copy, Clone)] -pub struct EscapeForUnixMakefile<'a> { - s: &'a OsStr, - kind: UnixMakefileEscapeKind, -} - -impl<'a> fmt::Debug for EscapeForUnixMakefile<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl<'a> fmt::Display for EscapeForUnixMakefile<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.do_write( - f, - fmt::Write::write_str, - fmt::Write::write_char, - |_, _| Ok(()), - |_| unreachable!("already checked that the input causes no UTF-8 errors"), - ) - } -} - -impl<'a> EscapeForUnixMakefile<'a> { - fn do_write( - &self, - state: &mut S, - write_str: impl Fn(&mut S, &str) -> Result<(), E>, - write_char: impl Fn(&mut S, char) -> Result<(), E>, - add_variable: impl Fn(&mut S, &'static str) -> Result<(), E>, - utf8_error: impl Fn(Utf8Error) -> E, - ) -> Result<(), E> { - let escape_recipe_char = |c| match c { - '$' => write_str(state, "$$"), - '\0'..='\x1F' | '\x7F' => { - panic!("can't escape a control character for Unix Makefile: {c:?}"); - } - _ => write_char(state, c), - }; - match self.kind { - UnixMakefileEscapeKind::NonRecipe => str::from_utf8(self.s.as_encoded_bytes()) - .map_err(&utf8_error)? - .chars() - .try_for_each(|c| match c { - '=' => { - add_variable(state, "EQUALS = =")?; - write_str(state, "$(EQUALS)") - } - ';' => panic!("can't escape a semicolon (;) for Unix Makefile"), - '$' => write_str(state, "$$"), - '\\' | ' ' | '#' | ':' | '%' | '*' | '?' | '[' | ']' | '~' => { - write_char(state, '\\')?; - write_char(state, c) - } - '\0'..='\x1F' | '\x7F' => { - panic!("can't escape a control character for Unix Makefile: {c:?}"); - } - _ => write_char(state, c), - }), - UnixMakefileEscapeKind::RecipeWithoutShellEscaping => { - str::from_utf8(self.s.as_encoded_bytes()) - .map_err(&utf8_error)? - .chars() - .try_for_each(escape_recipe_char) - } - UnixMakefileEscapeKind::RecipeWithShellEscaping => { - EscapeForUnixShell::new(self.s).try_for_each(escape_recipe_char) - } - } - } - pub fn new( - s: &'a (impl ?Sized + AsRef), - kind: UnixMakefileEscapeKind, - needed_variables: &mut BTreeSet<&'static str>, - ) -> Result { - let s = s.as_ref(); - let retval = Self { s, kind }; - retval.do_write( - needed_variables, - |_, _| Ok(()), - |_, _| Ok(()), - |needed_variables, variable| { - needed_variables.insert(variable); - Ok(()) - }, - |e| e, - )?; - Ok(retval) - } -} - -impl JobGraph { - pub fn new() -> Self { - Self::default() - } - fn try_add_item_node( - &mut self, - name: JobItemName, - new_source_job: Option, - new_nodes: &mut HashSet<::NodeId>, - ) -> Result<::NodeId, JobGraphError> { - use hashbrown::hash_map::Entry; - match self.items.entry(name) { - Entry::Occupied(item_entry) => { - let node_id = *item_entry.get(); - let JobGraphNode::Item { - name: _, - source_job, - } = &mut self.graph[node_id] - else { - unreachable!("known to be an item"); - }; - if let Some(new_source_job) = new_source_job { - if let Some(source_job) = source_job { - return Err(JobGraphError::MultipleJobsCreateSameOutput { - output_item: item_entry.key().clone(), - existing_job: source_job.clone(), - new_job: new_source_job, - }); - } else { - *source_job = Some(new_source_job); - } - } - Ok(node_id) - } - Entry::Vacant(item_entry) => { - let node_id = self.graph.add_node(JobGraphNode::Item { - name, - source_job: new_source_job, - }); - new_nodes.insert(node_id); - item_entry.insert(node_id); - Ok(node_id) - } - } - } - pub fn try_add_jobs>( - &mut self, - jobs: I, - ) -> Result<(), JobGraphError> { - use hashbrown::hash_map::Entry; - let jobs = jobs.into_iter(); - struct RemoveNewNodesOnError<'a> { - this: &'a mut JobGraph, - new_nodes: HashSet<::NodeId>, - } - impl Drop for RemoveNewNodesOnError<'_> { - fn drop(&mut self) { - for node in self.new_nodes.drain() { - self.this.graph.remove_node(node); - } - } - } - let mut remove_new_nodes_on_error = RemoveNewNodesOnError { - this: self, - new_nodes: HashSet::with_capacity_and_hasher(jobs.size_hint().0, Default::default()), - }; - let new_nodes = &mut remove_new_nodes_on_error.new_nodes; - let this = &mut *remove_new_nodes_on_error.this; - for job in jobs { - let Entry::Vacant(job_entry) = this.jobs.entry(job.clone()) else { - continue; - }; - let job_node_id = this - .graph - .add_node(JobGraphNode::Job(job_entry.key().clone())); - new_nodes.insert(job_node_id); - job_entry.insert(job_node_id); - for name in job.outputs() { - let item_node_id = this.try_add_item_node(name, Some(job.clone()), new_nodes)?; - this.graph.add_edge(job_node_id, item_node_id, ()); - } - for name in job.inputs() { - let item_node_id = this.try_add_item_node(name, None, new_nodes)?; - this.graph.add_edge(item_node_id, job_node_id, ()); - } - } - match toposort(&this.graph, Some(&mut this.space)) { - Ok(v) => { - this.topological_order = v; - // no need to remove any of the new nodes on drop since we didn't encounter any errors - remove_new_nodes_on_error.new_nodes.clear(); - Ok(()) - } - Err(_) => { - // there's at least one cycle, find one! - let cycle = kosaraju_scc(&this.graph) - .into_iter() - .find_map(|scc| { - if scc.len() <= 1 { - // can't be a cycle since our graph is bipartite -- - // jobs only connect to items, never jobs to jobs or items to items - None - } else { - Some(scc) - } - }) - .expect("we know there's a cycle"); - let cycle_set = HashSet::from_iter(cycle.iter().copied()); - let job = cycle - .into_iter() - .find_map(|node_id| { - if let JobGraphNode::Job(job) = &this.graph[node_id] { - Some(job.clone()) - } else { - None - } - }) - .expect("a job must be part of the cycle"); - let output = job - .outputs() - .into_iter() - .find(|output| cycle_set.contains(&this.items[output])) - .expect("an output must be part of the cycle"); - Err(JobGraphError::CycleError { job, output }) - } - } - } - #[track_caller] - pub fn add_jobs>(&mut self, jobs: I) { - match self.try_add_jobs(jobs) { - Ok(()) => {} - Err(e) => panic!("error: {e}"), - } - } - pub fn to_unix_makefile( - &self, - platform: Option<&DynPlatform>, - extra_args: &[Interned], - ) -> Result { - self.to_unix_makefile_with_internal_program_prefix( - &[program_name_for_internal_jobs()], - platform, - extra_args, - ) - } - pub fn to_unix_makefile_with_internal_program_prefix( - &self, - internal_program_prefix: &[Interned], - platform: Option<&DynPlatform>, - extra_args: &[Interned], - ) -> Result { - let mut retval = String::new(); - let mut needed_variables = BTreeSet::new(); - let mut phony_targets = BTreeSet::new(); - for &node_id in &self.topological_order { - let JobGraphNode::Job(job) = &self.graph[node_id] else { - continue; - }; - let outputs = job.outputs(); - if outputs.is_empty() { - retval.push_str(":"); - } else { - for output in job.outputs() { - match output { - JobItemName::Path { path } => { - write_str!( - retval, - "{} ", - EscapeForUnixMakefile::new( - &str::from_utf8(path.as_os_str().as_encoded_bytes())?, - UnixMakefileEscapeKind::NonRecipe, - &mut needed_variables - )? - ); - } - JobItemName::DynamicPaths { source_job_name } => { - write_str!( - retval, - "{} ", - EscapeForUnixMakefile::new( - &source_job_name, - UnixMakefileEscapeKind::NonRecipe, - &mut needed_variables - )? - ); - phony_targets.insert(Interned::into_inner(source_job_name)); - } - } - } - if outputs.len() == 1 { - retval.push_str(":"); - } else { - retval.push_str("&:"); - } - } - for input in job.inputs() { - match input { - JobItemName::Path { path } => { - write_str!( - retval, - " {}", - EscapeForUnixMakefile::new( - &str::from_utf8(path.as_os_str().as_encoded_bytes())?, - UnixMakefileEscapeKind::NonRecipe, - &mut needed_variables - )? - ); - } - JobItemName::DynamicPaths { source_job_name } => { - write_str!( - retval, - " {}", - EscapeForUnixMakefile::new( - &source_job_name, - UnixMakefileEscapeKind::NonRecipe, - &mut needed_variables - )? - ); - phony_targets.insert(Interned::into_inner(source_job_name)); - } - } - } - retval.push_str("\n\t"); - job.command_params_with_internal_program_prefix( - internal_program_prefix, - platform, - extra_args, - ) - .to_unix_shell_line(&mut retval, |arg, output| { - write_str!( - output, - "{}", - EscapeForUnixMakefile::new( - arg, - UnixMakefileEscapeKind::RecipeWithShellEscaping, - &mut needed_variables - )? - ); - Ok(()) - })?; - retval.push_str("\n\n"); - } - if !phony_targets.is_empty() { - retval.push_str("\n.PHONY:"); - for phony_target in phony_targets { - write_str!( - retval, - " {}", - EscapeForUnixMakefile::new( - phony_target, - UnixMakefileEscapeKind::NonRecipe, - &mut needed_variables - )? - ); - } - retval.push_str("\n"); - } - if !needed_variables.is_empty() { - retval.insert_str( - 0, - &String::from_iter(needed_variables.into_iter().map(|v| format!("{v}\n"))), - ); - } - Ok(retval) - } - pub fn to_unix_shell_script( - &self, - platform: Option<&DynPlatform>, - extra_args: &[Interned], - ) -> String { - self.to_unix_shell_script_with_internal_program_prefix( - &[program_name_for_internal_jobs()], - platform, - extra_args, - ) - } - pub fn to_unix_shell_script_with_internal_program_prefix( - &self, - internal_program_prefix: &[Interned], - platform: Option<&DynPlatform>, - extra_args: &[Interned], - ) -> String { - let mut retval = String::from( - "#!/bin/sh\n\ - set -ex\n", - ); - for &node_id in &self.topological_order { - let JobGraphNode::Job(job) = &self.graph[node_id] else { - continue; - }; - let Ok(()) = job - .command_params_with_internal_program_prefix( - internal_program_prefix, - platform, - extra_args, - ) - .to_unix_shell_line(&mut retval, |arg, output| -> Result<(), Infallible> { - write_str!(output, "{}", EscapeForUnixShell::new(&arg)); - Ok(()) - }); - retval.push_str("\n"); - } - retval - } - pub fn run(&self, params: &JobParams, global_params: &GlobalParams) -> eyre::Result<()> { - // use scope to auto-join threads on errors - thread::scope(|scope| { - struct WaitingJobState { - job_node_id: ::NodeId, - job: DynJob, - inputs: BTreeMap>, - } - let mut ready_jobs = VecDeque::new(); - let mut item_name_to_waiting_jobs_map = HashMap::<_, Vec<_>>::default(); - for &node_id in &self.topological_order { - let JobGraphNode::Job(job) = &self.graph[node_id] else { - continue; - }; - let waiting_job = WaitingJobState { - job_node_id: node_id, - job: job.clone(), - inputs: job - .inputs() - .iter() - .map(|&name| (name, OnceCell::new())) - .collect(), - }; - if waiting_job.inputs.is_empty() { - ready_jobs.push_back(waiting_job); - } else { - let waiting_job = Rc::new(waiting_job); - for &input_item in waiting_job.inputs.keys() { - item_name_to_waiting_jobs_map - .entry(input_item) - .or_default() - .push(waiting_job.clone()); - } - } - } - struct RunningJob<'scope> { - job: DynJob, - thread: ScopedJoinHandle<'scope, eyre::Result>>, - } - let mut running_jobs = HashMap::default(); - let (finished_jobs_sender, finished_jobs_receiver) = mpsc::channel(); - let mut next_finished_job = None; - loop { - if let Some(finished_job) = next_finished_job - .take() - .or_else(|| finished_jobs_receiver.try_recv().ok()) - { - let Some(RunningJob { job, thread }) = running_jobs.remove(&finished_job) - else { - unreachable!(); - }; - let output_items = thread.join().map_err(panic::resume_unwind)??; - assert!( - output_items.iter().map(JobItem::name).eq(job.outputs()), - "job's run() method returned the wrong output items:\n\ - output items:\n\ - {output_items:?}\n\ - expected outputs:\n\ - {:?}\n\ - job:\n\ - {job:?}", - job.outputs(), - ); - for output_item in output_items { - for waiting_job in item_name_to_waiting_jobs_map - .remove(&output_item.name()) - .unwrap_or_default() - { - let Ok(()) = - waiting_job.inputs[&output_item.name()].set(output_item.clone()) - else { - unreachable!(); - }; - if let Some(waiting_job) = Rc::into_inner(waiting_job) { - ready_jobs.push_back(waiting_job); - } - } - } - continue; - } - if let Some(WaitingJobState { - job_node_id, - job, - inputs, - }) = ready_jobs.pop_front() - { - struct RunningJobInThread<'a> { - job_node_id: ::NodeId, - job: DynJob, - inputs: Vec, - params: &'a JobParams, - global_params: &'a GlobalParams, - acquired_job: AcquiredJob, - finished_jobs_sender: mpsc::Sender<::NodeId>, - } - impl RunningJobInThread<'_> { - fn run(mut self) -> eyre::Result> { - self.job.run( - &self.inputs, - self.params, - self.global_params, - &mut self.acquired_job, - ) - } - } - impl Drop for RunningJobInThread<'_> { - fn drop(&mut self) { - let _ = self.finished_jobs_sender.send(self.job_node_id); - } - } - let name = job.kind().name(); - let running_job_in_thread = RunningJobInThread { - job_node_id, - job: job.clone(), - inputs: Result::from_iter(job.inputs().iter().map(|input_name| { - inputs.get(input_name).and_then(|v| v.get().cloned()).wrap_err_with(|| { - eyre!("failed when trying to run job {name}: nothing provided the input item: {input_name:?}") - }) - }))?, - params, - global_params, - acquired_job: AcquiredJob::acquire()?, - finished_jobs_sender: finished_jobs_sender.clone(), - }; - running_jobs.insert( - job_node_id, - RunningJob { - job, - thread: thread::Builder::new() - .name(format!("job:{name}")) - .spawn_scoped(scope, move || running_job_in_thread.run()) - .expect("failed to spawn thread for job"), - }, - ); - continue; - } - if running_jobs.is_empty() { - assert!(item_name_to_waiting_jobs_map.is_empty()); - assert!(ready_jobs.is_empty()); - return Ok(()); - } - // nothing to do yet, block to avoid busy waiting - next_finished_job = finished_jobs_receiver.recv().ok(); - } - }) - } -} - -impl Extend for JobGraph { - #[track_caller] - fn extend>(&mut self, iter: T) { - self.add_jobs(iter); - } -} - -impl FromIterator for JobGraph { - #[track_caller] - fn from_iter>(iter: T) -> Self { - let mut retval = Self::new(); - retval.add_jobs(iter); - retval - } -} - -impl Serialize for JobGraph { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut serializer = serializer.serialize_seq(Some(self.jobs.len()))?; - for &node_id in &self.topological_order { - let JobGraphNode::Job(job) = &self.graph[node_id] else { - continue; - }; - serializer.serialize_element(job)?; - } - serializer.end() - } -} - -impl<'de> Deserialize<'de> for JobGraph { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let jobs = Vec::::deserialize(deserializer)?; - let mut retval = JobGraph::new(); - retval.try_add_jobs(jobs).map_err(D::Error::custom)?; - Ok(retval) - } -} diff --git a/crates/fayalite/src/build/registry.rs b/crates/fayalite/src/build/registry.rs deleted file mode 100644 index bbd9f2c..0000000 --- a/crates/fayalite/src/build/registry.rs +++ /dev/null @@ -1,313 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - build::{DynJobKind, JobKind, built_in_job_kinds}, - intern::Interned, - util::InternedStrCompareAsStr, -}; -use std::{ - collections::BTreeMap, - fmt, - sync::{Arc, OnceLock, RwLock, RwLockWriteGuard}, -}; - -impl DynJobKind { - pub fn registry() -> JobKindRegistrySnapshot { - JobKindRegistrySnapshot(JobKindRegistry::get()) - } - #[track_caller] - pub fn register(self) { - JobKindRegistry::register(JobKindRegistry::lock(), self); - } -} - -#[derive(Clone, Debug)] -struct JobKindRegistry { - job_kinds: BTreeMap, -} - -enum JobKindRegisterError { - SameName { - name: InternedStrCompareAsStr, - old_job_kind: DynJobKind, - new_job_kind: DynJobKind, - }, -} - -impl fmt::Display for JobKindRegisterError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::SameName { - name, - old_job_kind, - new_job_kind, - } => write!( - f, - "two different `JobKind` can't share the same name:\n\ - {name:?}\n\ - old job kind:\n\ - {old_job_kind:?}\n\ - new job kind:\n\ - {new_job_kind:?}", - ), - } - } -} - -trait JobKindRegistryRegisterLock { - type Locked; - fn lock(self) -> Self::Locked; - fn make_mut(locked: &mut Self::Locked) -> &mut JobKindRegistry; -} - -impl JobKindRegistryRegisterLock for &'static RwLock> { - type Locked = RwLockWriteGuard<'static, Arc>; - fn lock(self) -> Self::Locked { - self.write().expect("shouldn't be poisoned") - } - fn make_mut(locked: &mut Self::Locked) -> &mut JobKindRegistry { - Arc::make_mut(locked) - } -} - -impl JobKindRegistryRegisterLock for &'_ mut JobKindRegistry { - type Locked = Self; - - fn lock(self) -> Self::Locked { - self - } - - fn make_mut(locked: &mut Self::Locked) -> &mut JobKindRegistry { - locked - } -} - -impl JobKindRegistry { - fn lock() -> &'static RwLock> { - static REGISTRY: OnceLock>> = OnceLock::new(); - REGISTRY.get_or_init(Default::default) - } - fn try_register( - lock: L, - job_kind: DynJobKind, - ) -> Result<(), JobKindRegisterError> { - use std::collections::btree_map::Entry; - let name = InternedStrCompareAsStr(job_kind.name()); - // run user code only outside of lock - let mut locked = lock.lock(); - let this = L::make_mut(&mut locked); - let result = match this.job_kinds.entry(name) { - Entry::Occupied(entry) => Err(JobKindRegisterError::SameName { - name, - old_job_kind: entry.get().clone(), - new_job_kind: job_kind, - }), - Entry::Vacant(entry) => { - entry.insert(job_kind); - Ok(()) - } - }; - drop(locked); - // outside of lock now, so we can test if it's the same DynJobKind - match result { - Err(JobKindRegisterError::SameName { - name: _, - old_job_kind, - new_job_kind, - }) if old_job_kind == new_job_kind => Ok(()), - result => result, - } - } - #[track_caller] - fn register(lock: L, job_kind: DynJobKind) { - match Self::try_register(lock, job_kind) { - Err(e) => panic!("{e}"), - Ok(()) => {} - } - } - fn get() -> Arc { - Self::lock().read().expect("shouldn't be poisoned").clone() - } -} - -impl Default for JobKindRegistry { - fn default() -> Self { - let mut retval = Self { - job_kinds: BTreeMap::new(), - }; - for job_kind in built_in_job_kinds() { - Self::register(&mut retval, job_kind); - } - retval - } -} - -#[derive(Clone, Debug)] -pub struct JobKindRegistrySnapshot(Arc); - -impl JobKindRegistrySnapshot { - pub fn get() -> Self { - JobKindRegistrySnapshot(JobKindRegistry::get()) - } - pub fn get_by_name<'a>(&'a self, name: &str) -> Option<&'a DynJobKind> { - self.0.job_kinds.get(name) - } - pub fn iter_with_names(&self) -> JobKindRegistryIterWithNames<'_> { - JobKindRegistryIterWithNames(self.0.job_kinds.iter()) - } - pub fn iter(&self) -> JobKindRegistryIter<'_> { - JobKindRegistryIter(self.0.job_kinds.values()) - } -} - -impl<'a> IntoIterator for &'a JobKindRegistrySnapshot { - type Item = &'a DynJobKind; - type IntoIter = JobKindRegistryIter<'a>; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl<'a> IntoIterator for &'a mut JobKindRegistrySnapshot { - type Item = &'a DynJobKind; - type IntoIter = JobKindRegistryIter<'a>; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -#[derive(Clone, Debug)] -pub struct JobKindRegistryIter<'a>( - std::collections::btree_map::Values<'a, InternedStrCompareAsStr, DynJobKind>, -); - -impl<'a> Iterator for JobKindRegistryIter<'a> { - type Item = &'a DynJobKind; - - fn next(&mut self) -> Option { - self.0.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - - fn count(self) -> usize - where - Self: Sized, - { - self.0.count() - } - - fn last(self) -> Option { - self.0.last() - } - - fn nth(&mut self, n: usize) -> Option { - self.0.nth(n) - } - - fn fold(self, init: B, f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.0.fold(init, f) - } -} - -impl<'a> std::iter::FusedIterator for JobKindRegistryIter<'a> {} - -impl<'a> ExactSizeIterator for JobKindRegistryIter<'a> {} - -impl<'a> DoubleEndedIterator for JobKindRegistryIter<'a> { - fn next_back(&mut self) -> Option { - self.0.next_back() - } - - fn nth_back(&mut self, n: usize) -> Option { - self.0.nth_back(n) - } - - fn rfold(self, init: B, f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.0.rfold(init, f) - } -} - -#[derive(Clone, Debug)] -pub struct JobKindRegistryIterWithNames<'a>( - std::collections::btree_map::Iter<'a, InternedStrCompareAsStr, DynJobKind>, -); - -impl<'a> Iterator for JobKindRegistryIterWithNames<'a> { - type Item = (Interned, &'a DynJobKind); - - fn next(&mut self) -> Option { - self.0.next().map(|(name, job_kind)| (name.0, job_kind)) - } - - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - - fn count(self) -> usize - where - Self: Sized, - { - self.0.count() - } - - fn last(self) -> Option { - self.0.last().map(|(name, job_kind)| (name.0, job_kind)) - } - - fn nth(&mut self, n: usize) -> Option { - self.0.nth(n).map(|(name, job_kind)| (name.0, job_kind)) - } - - fn fold(self, init: B, f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.0 - .map(|(name, job_kind)| (name.0, job_kind)) - .fold(init, f) - } -} - -impl<'a> std::iter::FusedIterator for JobKindRegistryIterWithNames<'a> {} - -impl<'a> ExactSizeIterator for JobKindRegistryIterWithNames<'a> {} - -impl<'a> DoubleEndedIterator for JobKindRegistryIterWithNames<'a> { - fn next_back(&mut self) -> Option { - self.0 - .next_back() - .map(|(name, job_kind)| (name.0, job_kind)) - } - - fn nth_back(&mut self, n: usize) -> Option { - self.0 - .nth_back(n) - .map(|(name, job_kind)| (name.0, job_kind)) - } - - fn rfold(self, init: B, f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.0 - .map(|(name, job_kind)| (name.0, job_kind)) - .rfold(init, f) - } -} - -#[track_caller] -pub fn register_job_kind(kind: K) { - DynJobKind::new(kind).register(); -} diff --git a/crates/fayalite/src/build/verilog.rs b/crates/fayalite/src/build/verilog.rs deleted file mode 100644 index 7ce77ec..0000000 --- a/crates/fayalite/src/build/verilog.rs +++ /dev/null @@ -1,418 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - build::{ - BaseJob, CommandParams, DynJobKind, GetJobPositionDependencies, GetJobPositionJob, - GlobalParams, JobAndDependencies, JobArgsAndDependencies, JobDependencies, JobItem, - JobItemName, JobKind, JobKindAndDependencies, JobParams, ToArgs, WriteArgs, - external::{ - ExternalCommand, ExternalCommandJob, ExternalCommandJobKind, ExternalProgramTrait, - }, - firrtl::{Firrtl, FirrtlJobKind}, - }, - intern::{Intern, InternSlice, Interned}, - util::job_server::AcquiredJob, -}; -use clap::Args; -use eyre::{Context, bail}; -use serde::{Deserialize, Serialize}; -use std::{ - ffi::{OsStr, OsString}, - fmt, mem, - path::Path, -}; - -/// based on [LLVM Circt's recommended lowering options][lowering-options] -/// -/// [lowering-options]: https://circt.llvm.org/docs/VerilogGeneration/#recommended-loweringoptions-by-target -#[derive(clap::ValueEnum, Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[non_exhaustive] -pub enum VerilogDialect { - Questa, - Spyglass, - Verilator, - Vivado, - Yosys, -} - -impl fmt::Display for VerilogDialect { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - -impl VerilogDialect { - pub fn as_str(self) -> &'static str { - match self { - VerilogDialect::Questa => "questa", - VerilogDialect::Spyglass => "spyglass", - VerilogDialect::Verilator => "verilator", - VerilogDialect::Vivado => "vivado", - VerilogDialect::Yosys => "yosys", - } - } - pub fn firtool_extra_args(self) -> &'static [&'static str] { - match self { - VerilogDialect::Questa => &["--lowering-options=emitWireInPorts"], - VerilogDialect::Spyglass => { - &["--lowering-options=explicitBitcast,disallowExpressionInliningInPorts"] - } - VerilogDialect::Verilator => &[ - "--lowering-options=locationInfoStyle=wrapInAtSquareBracket,disallowLocalVariables", - ], - VerilogDialect::Vivado => &["--lowering-options=mitigateVivadoArrayIndexConstPropBug"], - VerilogDialect::Yosys => { - &["--lowering-options=disallowLocalVariables,disallowPackedArrays"] - } - } - } -} - -#[derive(Args, Debug, Clone, PartialEq, Eq, Hash)] -#[non_exhaustive] -pub struct UnadjustedVerilogArgs { - #[arg(long = "firtool-extra-arg", value_name = "ARG")] - pub firtool_extra_args: Vec, - /// adapt the generated Verilog for a particular toolchain - #[arg(long)] - pub verilog_dialect: Option, - #[arg(long)] - pub verilog_debug: bool, -} - -impl ToArgs for UnadjustedVerilogArgs { - fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) { - let Self { - ref firtool_extra_args, - verilog_dialect, - verilog_debug, - } = *self; - for arg in firtool_extra_args { - args.write_long_option_eq("firtool-extra-arg", arg); - } - if let Some(verilog_dialect) = verilog_dialect { - args.write_long_option_eq("verilog-dialect", verilog_dialect.as_str()); - } - if verilog_debug { - args.write_arg("--verilog-debug"); - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] -pub struct Firtool; - -impl ExternalProgramTrait for Firtool { - fn default_program_name() -> Interned { - "firtool".intern() - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, Deserialize, Serialize)] -pub struct UnadjustedVerilog { - firrtl_file: Interned, - firrtl_file_name: Interned, - unadjusted_verilog_file: Interned, - unadjusted_verilog_file_name: Interned, - firtool_extra_args: Interned<[Interned]>, - verilog_dialect: Option, - verilog_debug: bool, -} - -impl UnadjustedVerilog { - pub fn firrtl_file(&self) -> Interned { - self.firrtl_file - } - pub fn unadjusted_verilog_file(&self) -> Interned { - self.unadjusted_verilog_file - } - pub fn firtool_extra_args(&self) -> Interned<[Interned]> { - self.firtool_extra_args - } - pub fn verilog_dialect(&self) -> Option { - self.verilog_dialect - } - pub fn verilog_debug(&self) -> bool { - self.verilog_debug - } -} - -impl ExternalCommand for UnadjustedVerilog { - type AdditionalArgs = UnadjustedVerilogArgs; - type AdditionalJobData = UnadjustedVerilog; - type BaseJobPosition = GetJobPositionDependencies; - type Dependencies = JobKindAndDependencies; - type ExternalProgram = Firtool; - - fn dependencies() -> Self::Dependencies { - Default::default() - } - - fn args_to_jobs( - args: JobArgsAndDependencies>, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result<( - Self::AdditionalJobData, - ::JobsAndKinds, - )> { - args.args_to_jobs_external_simple(params, global_params, |args, dependencies| { - let UnadjustedVerilogArgs { - firtool_extra_args, - verilog_dialect, - verilog_debug, - } = args.additional_args; - let unadjusted_verilog_file = dependencies - .dependencies - .job - .job - .file_with_ext("unadjusted.v"); - let firrtl_job = dependencies.get_job::(); - Ok(UnadjustedVerilog { - firrtl_file: firrtl_job.firrtl_file(), - firrtl_file_name: firrtl_job - .firrtl_file() - .interned_file_name() - .expect("known to have file name"), - unadjusted_verilog_file, - unadjusted_verilog_file_name: unadjusted_verilog_file - .interned_file_name() - .expect("known to have file name"), - firtool_extra_args: firtool_extra_args.into_iter().map(Interned::from).collect(), - verilog_dialect, - verilog_debug, - }) - }) - } - - fn inputs(job: &ExternalCommandJob) -> Interned<[JobItemName]> { - [JobItemName::Path { - path: job.additional_job_data().firrtl_file, - }] - .intern_slice() - } - - fn output_paths(job: &ExternalCommandJob) -> Interned<[Interned]> { - [job.additional_job_data().unadjusted_verilog_file].intern_slice() - } - - fn command_line_args(job: &ExternalCommandJob, args: &mut W) { - let UnadjustedVerilog { - firrtl_file: _, - firrtl_file_name, - unadjusted_verilog_file: _, - unadjusted_verilog_file_name, - firtool_extra_args, - verilog_dialect, - verilog_debug, - } = *job.additional_job_data(); - args.write_interned_arg(firrtl_file_name); - args.write_arg("-o"); - args.write_interned_arg(unadjusted_verilog_file_name); - if verilog_debug { - args.write_args(["-g", "--preserve-values=all"]); - } - if let Some(dialect) = verilog_dialect { - args.write_args(dialect.firtool_extra_args().iter().copied()); - } - args.write_interned_args(firtool_extra_args); - } - - fn current_dir(job: &ExternalCommandJob) -> Option> { - Some(job.output_dir()) - } - - fn job_kind_name() -> Interned { - "unadjusted-verilog".intern() - } - - fn subcommand_hidden() -> bool { - true - } - - fn run_even_if_cached_arg_name() -> Interned { - "firtool-run-even-if-cached".intern() - } -} - -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct VerilogJobKind; - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Args)] -#[non_exhaustive] -pub struct VerilogJobArgs {} - -impl ToArgs for VerilogJobArgs { - fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) { - let Self {} = self; - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct VerilogJob { - output_dir: Interned, - unadjusted_verilog_file: Interned, - main_verilog_file: Interned, -} - -impl VerilogJob { - pub fn output_dir(&self) -> Interned { - self.output_dir - } - pub fn unadjusted_verilog_file(&self) -> Interned { - self.unadjusted_verilog_file - } - pub fn main_verilog_file(&self) -> Interned { - self.main_verilog_file - } - #[track_caller] - pub fn unwrap_additional_files(additional_files: &JobItem) -> &[Interned] { - match additional_files { - JobItem::DynamicPaths { - paths, - source_job_name, - } if *source_job_name == VerilogJobKind.name() => paths, - v => panic!("expected VerilogJob's additional files JobItem: {v:?}"), - } - } - pub fn all_verilog_files( - main_verilog_file: Interned, - additional_files: &[Interned], - ) -> eyre::Result]>> { - let mut retval = Vec::with_capacity(additional_files.len().saturating_add(1)); - for verilog_file in [main_verilog_file].iter().chain(additional_files) { - if !["v", "sv"] - .iter() - .any(|extension| verilog_file.extension() == Some(extension.as_ref())) - { - continue; - } - let verilog_file = std::path::absolute(verilog_file).wrap_err_with(|| { - format!("converting {verilog_file:?} to an absolute path failed") - })?; - if verilog_file - .as_os_str() - .as_encoded_bytes() - .iter() - .any(|&ch| (ch != b' ' && ch != b'\t' && ch.is_ascii_whitespace()) || ch == b'"') - { - bail!("verilog file path contains characters that aren't permitted"); - } - retval.push(verilog_file.intern_deref()); - } - Ok(retval.intern_slice()) - } -} - -impl JobKind for VerilogJobKind { - type Args = VerilogJobArgs; - type Job = VerilogJob; - type Dependencies = JobKindAndDependencies>; - - fn dependencies(self) -> Self::Dependencies { - Default::default() - } - - fn args_to_jobs( - args: JobArgsAndDependencies, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result> { - args.args_to_jobs_simple(params, global_params, |_kind, args, dependencies| { - let VerilogJobArgs {} = args; - let base_job = dependencies.get_job::(); - Ok(VerilogJob { - output_dir: base_job.output_dir(), - unadjusted_verilog_file: dependencies - .job - .job - .additional_job_data() - .unadjusted_verilog_file(), - main_verilog_file: base_job.file_with_ext("v"), - }) - }) - } - - fn inputs(self, job: &Self::Job) -> Interned<[JobItemName]> { - [JobItemName::Path { - path: job.unadjusted_verilog_file, - }] - .intern_slice() - } - - fn outputs(self, job: &Self::Job) -> Interned<[JobItemName]> { - [ - JobItemName::Path { - path: job.main_verilog_file, - }, - JobItemName::DynamicPaths { - source_job_name: self.name(), - }, - ] - .intern_slice() - } - - fn name(self) -> Interned { - "verilog".intern() - } - - fn external_command_params(self, _job: &Self::Job) -> Option { - None - } - - fn run( - self, - job: &Self::Job, - inputs: &[JobItem], - _params: &JobParams, - _global_params: &GlobalParams, - _acquired_job: &mut AcquiredJob, - ) -> eyre::Result> { - assert!(inputs.iter().map(JobItem::name).eq(self.inputs(job))); - let input = std::fs::read_to_string(job.unadjusted_verilog_file())?; - let file_separator_prefix = "\n// ----- 8< ----- FILE \""; - let file_separator_suffix = "\" ----- 8< -----\n\n"; - let mut input = &*input; - let main_verilog_file = job.main_verilog_file(); - let mut file_name = Some(main_verilog_file); - let mut additional_outputs = Vec::new(); - loop { - let (chunk, next_file_name) = if let Some((chunk, rest)) = - input.split_once(file_separator_prefix) - { - let Some((next_file_name, rest)) = rest.split_once(file_separator_suffix) else { - bail!( - "parsing firtool's output failed: found {file_separator_prefix:?} but no {file_separator_suffix:?}" - ); - }; - input = rest; - let next_file_name = job.output_dir.join(next_file_name).intern_deref(); - additional_outputs.push(next_file_name); - (chunk, Some(next_file_name)) - } else { - (mem::take(&mut input), None) - }; - let Some(file_name) = mem::replace(&mut file_name, next_file_name) else { - break; - }; - std::fs::write(&file_name, chunk)?; - } - Ok(vec![ - JobItem::Path { - path: main_verilog_file, - }, - JobItem::DynamicPaths { - paths: additional_outputs, - source_job_name: self.name(), - }, - ]) - } -} - -pub(crate) fn built_in_job_kinds() -> impl IntoIterator { - [ - DynJobKind::new(ExternalCommandJobKind::::new()), - DynJobKind::new(VerilogJobKind), - ] -} diff --git a/crates/fayalite/src/bundle.rs b/crates/fayalite/src/bundle.rs index a0de189..995510e 100644 --- a/crates/fayalite/src/bundle.rs +++ b/crates/fayalite/src/bundle.rs @@ -2,25 +2,20 @@ // See Notices.txt for copyright information use crate::{ - expr::{ - CastToBits, Expr, ReduceBits, ToExpr, - ops::{ArrayLiteral, BundleLiteral, ExprPartialEq}, - }, - int::{Bool, DynSize}, - intern::{Intern, InternSlice, Interned}, - sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, + expr::{ops::BundleLiteral, Expr, ToExpr}, + intern::{Intern, Interned}, + sim::{SimValue, ToSimValue}, source_location::SourceLocation, ty::{ - CanonicalType, MatchVariantWithoutScope, OpaqueSimValue, OpaqueSimValueSize, - OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type, - TypeProperties, TypeWithDeref, impl_match_variant_as_self, + impl_match_variant_as_self, CanonicalType, MatchVariantWithoutScope, StaticType, Type, + TypeProperties, TypeWithDeref, }, - util::HashMap, }; -use serde::{Deserialize, Serialize}; +use bitvec::vec::BitVec; +use hashbrown::HashMap; use std::{fmt, marker::PhantomData}; -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct BundleField { pub name: Interned, pub flipped: bool, @@ -69,7 +64,7 @@ impl fmt::Display for FmtDebugInStruct { struct BundleImpl { fields: Interned<[BundleField]>, name_indexes: HashMap, usize>, - field_offsets: Interned<[OpaqueSimValueSize]>, + field_offsets: Interned<[usize]>, type_properties: TypeProperties, } @@ -89,9 +84,12 @@ impl std::fmt::Debug for BundleImpl { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("Bundle ")?; f.debug_set() - .entries(self.fields.iter().enumerate().map(|(index, field)| { - field.fmt_debug_in_struct(self.field_offsets[index].bit_width) - })) + .entries( + self.fields + .iter() + .enumerate() + .map(|(index, field)| field.fmt_debug_in_struct(self.field_offsets[index])), + ) .finish() } } @@ -116,7 +114,6 @@ impl BundleTypePropertiesBuilder { is_storable: true, is_castable_from_bits: true, bit_width: 0, - sim_only_values_len: 0, }) } pub const fn clone(&self) -> Self { @@ -124,12 +121,8 @@ impl BundleTypePropertiesBuilder { } #[must_use] pub const fn field(self, flipped: bool, field_props: TypeProperties) -> Self { - let Some(OpaqueSimValueSize { - bit_width, - sim_only_values_len, - }) = self.0.size().checked_add(field_props.size()) - else { - panic!("bundle is too big: size overflowed"); + let Some(bit_width) = self.0.bit_width.checked_add(field_props.bit_width) else { + panic!("bundle is too big: bit-width overflowed"); }; if flipped { Self(TypeProperties { @@ -137,7 +130,6 @@ impl BundleTypePropertiesBuilder { is_storable: false, is_castable_from_bits: false, bit_width, - sim_only_values_len, }) } else { Self(TypeProperties { @@ -146,7 +138,6 @@ impl BundleTypePropertiesBuilder { is_castable_from_bits: self.0.is_castable_from_bits & field_props.is_castable_from_bits, bit_width, - sim_only_values_len, }) } } @@ -164,14 +155,14 @@ impl Default for BundleTypePropertiesBuilder { impl Bundle { #[track_caller] pub fn new(fields: Interned<[BundleField]>) -> Self { - let mut name_indexes = HashMap::with_capacity_and_hasher(fields.len(), Default::default()); + let mut name_indexes = HashMap::with_capacity(fields.len()); let mut field_offsets = Vec::with_capacity(fields.len()); let mut type_props_builder = BundleTypePropertiesBuilder::new(); for (index, &BundleField { name, flipped, ty }) in fields.iter().enumerate() { if let Some(old_index) = name_indexes.insert(name, index) { panic!("duplicate field name {name:?}: at both index {old_index} and {index}"); } - field_offsets.push(type_props_builder.0.size()); + field_offsets.push(type_props_builder.0.bit_width); type_props_builder = type_props_builder.field(flipped, ty.type_properties()); } Self(Intern::intern_sized(BundleImpl { @@ -187,7 +178,7 @@ impl Bundle { pub fn field_by_name(&self, name: Interned) -> Option { Some(self.0.fields[*self.0.name_indexes.get(&name)?]) } - pub fn field_offsets(self) -> Interned<[OpaqueSimValueSize]> { + pub fn field_offsets(self) -> Interned<[usize]> { self.0.field_offsets } pub fn type_properties(self) -> TypeProperties { @@ -221,7 +212,6 @@ impl Bundle { impl Type for Bundle { type BaseType = Bundle; type MaskType = Bundle; - type SimValue = OpaqueSimValue; impl_match_variant_as_self!(); fn mask_type(&self) -> Self::MaskType { Self::new(Interned::from_iter(self.0.fields.into_iter().map( @@ -245,28 +235,6 @@ impl Type for Bundle { fn source_location() -> SourceLocation { SourceLocation::builtin() } - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - assert_eq!(self.type_properties().size(), opaque.size()); - opaque.to_owned() - } - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ) { - assert_eq!(self.type_properties().size(), opaque.size()); - assert_eq!(value.size(), opaque.size()); - value.clone_from_slice(opaque); - } - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> OpaqueSimValueWritten<'w> { - assert_eq!(self.type_properties().size(), writer.size()); - assert_eq!(value.size(), writer.size()); - writer.fill_cloned_from_slice(value.as_slice()) - } } pub trait BundleType: Type { @@ -275,102 +243,6 @@ pub trait BundleType: Type { fn fields(&self) -> Interned<[BundleField]>; } -pub struct BundleSimValueFromOpaque<'a> { - fields: std::slice::Iter<'static, BundleField>, - opaque: OpaqueSimValueSlice<'a>, -} - -impl<'a> BundleSimValueFromOpaque<'a> { - #[track_caller] - pub fn new(bundle_ty: T, opaque: OpaqueSimValueSlice<'a>) -> Self { - let fields = bundle_ty.fields(); - assert_eq!( - opaque.size(), - fields - .iter() - .map(|BundleField { ty, .. }| ty.size()) - .sum::() - ); - Self { - fields: Interned::into_inner(fields).iter(), - opaque, - } - } - #[track_caller] - fn field_ty_and_opaque(&mut self) -> (T, OpaqueSimValueSlice<'a>) { - let Some(&BundleField { - name: _, - flipped: _, - ty, - }) = self.fields.next() - else { - panic!("tried to read too many fields from BundleSimValueFromBits"); - }; - let (field_opaque, rest) = self.opaque.split_at(ty.size()); - self.opaque = rest; - (T::from_canonical(ty), field_opaque) - } - #[track_caller] - pub fn field_from_opaque(&mut self) -> SimValue { - let (field_ty, field_opaque) = self.field_ty_and_opaque::(); - SimValue::from_opaque(field_ty, field_opaque.to_owned()) - } - #[track_caller] - pub fn field_clone_from_opaque(&mut self, field_value: &mut SimValue) { - let (field_ty, field_opaque) = self.field_ty_and_opaque::(); - assert_eq!(field_ty, SimValue::ty(field_value)); - SimValue::opaque_mut(field_value).clone_from_slice(field_opaque); - } -} - -pub struct BundleSimValueToOpaque<'a> { - fields: std::slice::Iter<'static, BundleField>, - writer: OpaqueSimValueWriter<'a>, -} - -impl<'a> BundleSimValueToOpaque<'a> { - #[track_caller] - pub fn new(bundle_ty: T, writer: OpaqueSimValueWriter<'a>) -> Self { - let fields = bundle_ty.fields(); - assert_eq!( - writer.size(), - fields - .iter() - .map(|BundleField { ty, .. }| ty.size()) - .sum::() - ); - Self { - fields: Interned::into_inner(fields).iter(), - writer, - } - } - #[track_caller] - pub fn field(&mut self, field_value: &SimValue) { - let Some(&BundleField { - name: _, - flipped: _, - ty, - }) = self.fields.next() - else { - panic!("tried to write too many fields with BundleSimValueToOpaque"); - }; - assert_eq!(T::from_canonical(ty), SimValue::ty(field_value)); - self.writer.fill_prefix_with(ty.size(), |writer| { - writer.fill_cloned_from_slice(SimValue::opaque(field_value).as_slice()) - }); - } - #[track_caller] - pub fn finish(mut self) -> OpaqueSimValueWritten<'a> { - assert_eq!( - self.fields.next(), - None, - "wrote too few fields with BundleSimValueToOpaque" - ); - self.writer - .fill_cloned_from_slice(OpaqueSimValueSlice::empty()) - } -} - #[derive(Default)] pub struct NoBuilder; @@ -453,19 +325,7 @@ macro_rules! impl_tuple_builder_fields { } macro_rules! impl_tuples { - ( - [$({ - #[ - num = $num:tt, - field = $field:ident, - ty = $ty_var:ident: $Ty:ident, - lhs = $lhs_var:ident: $Lhs:ident, - rhs = $rhs_var:ident: $Rhs:ident - ] - $var:ident: $T:ident - })*] - [] - ) => { + ([$({#[num = $num:literal, field = $field:ident, ty = $ty_var:ident: $Ty:ident] $var:ident: $T:ident})*] []) => { impl_tuple_builder_fields! { {} [$({ @@ -477,7 +337,6 @@ macro_rules! impl_tuples { impl<$($T: Type,)*> Type for ($($T,)*) { type BaseType = Bundle; type MaskType = ($($T::MaskType,)*); - type SimValue = ($(SimValue<$T>,)*); type MatchVariant = ($(Expr<$T>,)*); type MatchActiveScope = (); type MatchVariantAndInactiveScope = MatchVariantWithoutScope; @@ -516,40 +375,13 @@ macro_rules! impl_tuples { fn source_location() -> SourceLocation { SourceLocation::builtin() } - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - #![allow(unused_mut, unused_variables)] - let mut v = BundleSimValueFromOpaque::new(*self, opaque); - $(let $var = v.field_from_opaque();)* - ($($var,)*) - } - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ) { - #![allow(unused_mut, unused_variables)] - let mut v = BundleSimValueFromOpaque::new(*self, opaque); - let ($($var,)*) = value; - $(v.field_clone_from_opaque($var);)* - } - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> OpaqueSimValueWritten<'w> { - #![allow(unused_mut, unused_variables)] - let mut v = BundleSimValueToOpaque::new(*self, writer); - let ($($var,)*) = value; - $(v.field($var);)* - v.finish() - } } impl<$($T: Type,)*> BundleType for ($($T,)*) { type Builder = TupleBuilder<($(Unfilled<$T>,)*)>; type FilledBuilder = TupleBuilder<($(Expr<$T>,)*)>; fn fields(&self) -> Interned<[BundleField]> { let ($($var,)*) = self; - [$(BundleField { name: stringify!($num).intern(), flipped: false, ty: $var.canonical() }),*].intern_slice() + [$(BundleField { name: stringify!($num).intern(), flipped: false, ty: $var.canonical() }),*][..].intern() } } impl<$($T: Type,)*> TypeWithDeref for ($($T,)*) { @@ -580,7 +412,7 @@ macro_rules! impl_tuples { $(let $var = $var.to_expr();)* let ty = ($(Expr::ty($var),)*); let field_values = [$(Expr::canonical($var)),*]; - BundleLiteral::new(ty, field_values.intern_slice()).to_expr() + BundleLiteral::new(ty, field_values[..].intern()).to_expr() } } impl<$($T: Type,)*> ToExpr for TupleBuilder<($(Expr<$T>,)*)> { @@ -590,107 +422,80 @@ macro_rules! impl_tuples { let ($($var,)*) = self.0; let ty = ($(Expr::ty($var),)*); let field_values = [$(Expr::canonical($var)),*]; - BundleLiteral::new(ty, field_values.intern_slice()).to_expr() + BundleLiteral::new(ty, field_values[..].intern()).to_expr() } } - impl<$($T: ToSimValueWithType,)*> ToSimValueWithType for ($($T,)*) { + impl<$($T: ToSimValue,)*> ToSimValue for ($($T,)*) { #[track_caller] - fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue { - SimValue::into_canonical(ToSimValueWithType::::to_sim_value_with_type(self, Bundle::from_canonical(ty))) + fn to_sim_value(&self, ty: CanonicalType) -> SimValue { + ToSimValue::::to_sim_value(self, Bundle::from_canonical(ty)).into_canonical() } #[track_caller] - fn into_sim_value_with_type(self, ty: CanonicalType) -> SimValue + fn into_sim_value(self, ty: CanonicalType) -> SimValue { - SimValue::into_canonical(ToSimValueWithType::::into_sim_value_with_type(self, Bundle::from_canonical(ty))) + ToSimValue::::into_sim_value(self, Bundle::from_canonical(ty)).into_canonical() + } + #[track_caller] + fn box_into_sim_value(self: Box, ty: CanonicalType) -> SimValue { + ToSimValue::::box_into_sim_value(self, Bundle::from_canonical(ty)).into_canonical() } } - impl<$($T: ToSimValueWithType,)*> ToSimValueWithType for ($($T,)*) { + impl<$($T: ToSimValue,)*> ToSimValue for ($($T,)*) { #[track_caller] - fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue { + fn to_sim_value(&self, ty: Bundle) -> SimValue { let ($($var,)*) = self; let [$($ty_var,)*] = *ty.fields() else { panic!("bundle has wrong number of fields"); }; - $(let $var = $var.to_sim_value_with_type($ty_var.ty);)* - ToSimValueWithType::into_sim_value_with_type(($($var,)*), ty) + $(let $var = $var.to_sim_value($ty_var.ty);)* + ToSimValue::into_sim_value(($($var,)*), ty) } #[track_caller] - fn into_sim_value_with_type(self, ty: Bundle) -> SimValue { + fn into_sim_value(self, ty: Bundle) -> SimValue { #![allow(unused_mut)] #![allow(clippy::unused_unit)] let ($($var,)*) = self; let [$($ty_var,)*] = *ty.fields() else { panic!("bundle has wrong number of fields"); }; - let mut opaque = OpaqueSimValue::empty(); - $(let $var = $var.into_sim_value_with_type($ty_var.ty); - assert_eq!(SimValue::ty(&$var), $ty_var.ty); - opaque.extend_from_slice(SimValue::opaque(&$var).as_slice()); + let mut bits: Option = None; + $(let $var = $var.into_sim_value($ty_var.ty); + assert_eq!($var.ty(), $ty_var.ty); + if !$var.bits().is_empty() { + if let Some(bits) = &mut bits { + bits.extend_from_bitslice($var.bits()); + } else { + let mut $var = $var.into_bits(); + $var.reserve(ty.type_properties().bit_width - $var.len()); + bits = Some($var); + } + } )* - SimValue::from_opaque(ty, opaque) + bits.unwrap_or_else(BitVec::new).into_sim_value(ty) + } + #[track_caller] + fn box_into_sim_value(self: Box, ty: Bundle) -> SimValue { + Self::into_sim_value(*self, ty) } } - impl<$($T: ToSimValueWithType<$Ty>, $Ty: Type,)*> ToSimValueWithType<($($Ty,)*)> for ($($T,)*) { + impl<$($T: ToSimValue<$Ty>, $Ty: Type,)*> ToSimValue<($($Ty,)*)> for ($($T,)*) { #[track_caller] - fn to_sim_value_with_type(&self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { + fn to_sim_value(&self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { let ($($var,)*) = self; let ($($ty_var,)*) = ty; - $(let $var = $var.to_sim_value_with_type($ty_var);)* - SimValue::from_value(ty, ($($var,)*)) + $(let $var = $var.to_sim_value($ty_var).into_canonical();)* + SimValue::from_canonical(ToSimValue::into_sim_value(($($var,)*), ty.canonical())) } #[track_caller] - fn into_sim_value_with_type(self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { + fn into_sim_value(self, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { let ($($var,)*) = self; let ($($ty_var,)*) = ty; - $(let $var = $var.into_sim_value_with_type($ty_var);)* - SimValue::from_value(ty, ($($var,)*)) - } - } - impl<$($T: ToSimValue,)*> ToSimValue for ($($T,)*) { - type Type = ($($T::Type,)*); - #[track_caller] - fn to_sim_value(&self) -> SimValue { - let ($($var,)*) = self; - $(let $var = $var.to_sim_value();)* - SimValue::from_value(($(SimValue::ty(&$var),)*), ($($var,)*)) + $(let $var = $var.into_sim_value($ty_var).into_canonical();)* + SimValue::from_canonical(ToSimValue::into_sim_value(($($var,)*), ty.canonical())) } #[track_caller] - fn into_sim_value(self) -> SimValue { - let ($($var,)*) = self; - $(let $var = $var.to_sim_value();)* - SimValue::from_value(($(SimValue::ty(&$var),)*), ($($var,)*)) - } - } - impl<$($Lhs: Type + ExprPartialEq<$Rhs>, $Rhs: Type,)*> ExprPartialEq<($($Rhs,)*)> for ($($Lhs,)*) { - fn cmp_eq(lhs: Expr, rhs: Expr<($($Rhs,)*)>) -> Expr { - let ($($lhs_var,)*) = *lhs; - let ($($rhs_var,)*) = *rhs; - ArrayLiteral::::new( - Bool, - FromIterator::from_iter([$(Expr::canonical(ExprPartialEq::cmp_eq($lhs_var, $rhs_var)),)*]), - ) - .cast_to_bits() - .all_one_bits() - } - - fn cmp_ne(lhs: Expr, rhs: Expr<($($Rhs,)*)>) -> Expr { - let ($($lhs_var,)*) = *lhs; - let ($($rhs_var,)*) = *rhs; - ArrayLiteral::::new( - Bool, - FromIterator::from_iter([$(Expr::canonical(ExprPartialEq::cmp_ne($lhs_var, $rhs_var)),)*]), - ) - .cast_to_bits() - .any_one_bits() - } - } - impl<$($Lhs: SimValuePartialEq<$Rhs>, $Rhs: Type,)*> SimValuePartialEq<($($Rhs,)*)> for ($($Lhs,)*) { - fn sim_value_eq(lhs: &SimValue, rhs: &SimValue<($($Rhs,)*)>) -> bool { - let ($($lhs_var,)*) = &**lhs; - let ($($rhs_var,)*) = &**rhs; - let retval = true; - $(let retval = retval && $lhs_var == $rhs_var;)* - retval + fn box_into_sim_value(self: Box, ty: ($($Ty,)*)) -> SimValue<($($Ty,)*)> { + Self::into_sim_value(*self, ty) } } }; @@ -702,25 +507,24 @@ macro_rules! impl_tuples { impl_tuples! { [] [ - {#[num = 0, field = field_0, ty = ty0: Ty0, lhs = lhs0: Lhs0, rhs = rhs0: Rhs0] v0: T0} - {#[num = 1, field = field_1, ty = ty1: Ty1, lhs = lhs1: Lhs1, rhs = rhs1: Rhs1] v1: T1} - {#[num = 2, field = field_2, ty = ty2: Ty2, lhs = lhs2: Lhs2, rhs = rhs2: Rhs2] v2: T2} - {#[num = 3, field = field_3, ty = ty3: Ty3, lhs = lhs3: Lhs3, rhs = rhs3: Rhs3] v3: T3} - {#[num = 4, field = field_4, ty = ty4: Ty4, lhs = lhs4: Lhs4, rhs = rhs4: Rhs4] v4: T4} - {#[num = 5, field = field_5, ty = ty5: Ty5, lhs = lhs5: Lhs5, rhs = rhs5: Rhs5] v5: T5} - {#[num = 6, field = field_6, ty = ty6: Ty6, lhs = lhs6: Lhs6, rhs = rhs6: Rhs6] v6: T6} - {#[num = 7, field = field_7, ty = ty7: Ty7, lhs = lhs7: Lhs7, rhs = rhs7: Rhs7] v7: T7} - {#[num = 8, field = field_8, ty = ty8: Ty8, lhs = lhs8: Lhs8, rhs = rhs8: Rhs8] v8: T8} - {#[num = 9, field = field_9, ty = ty9: Ty9, lhs = lhs9: Lhs9, rhs = rhs9: Rhs9] v9: T9} - {#[num = 10, field = field_10, ty = ty10: Ty10, lhs = lhs10: Lhs10, rhs = rhs10: Rhs10] v10: T10} - {#[num = 11, field = field_11, ty = ty11: Ty11, lhs = lhs11: Lhs11, rhs = rhs11: Rhs11] v11: T11} + {#[num = 0, field = field_0, ty = ty0: Ty0] v0: T0} + {#[num = 1, field = field_1, ty = ty1: Ty1] v1: T1} + {#[num = 2, field = field_2, ty = ty2: Ty2] v2: T2} + {#[num = 3, field = field_3, ty = ty3: Ty3] v3: T3} + {#[num = 4, field = field_4, ty = ty4: Ty4] v4: T4} + {#[num = 5, field = field_5, ty = ty5: Ty5] v5: T5} + {#[num = 6, field = field_6, ty = ty6: Ty6] v6: T6} + {#[num = 7, field = field_7, ty = ty7: Ty7] v7: T7} + {#[num = 8, field = field_8, ty = ty8: Ty8] v8: T8} + {#[num = 9, field = field_9, ty = ty9: Ty9] v9: T9} + {#[num = 10, field = field_10, ty = ty10: Ty10] v10: T10} + {#[num = 11, field = field_11, ty = ty11: Ty11] v11: T11} ] } impl Type for PhantomData { type BaseType = Bundle; type MaskType = (); - type SimValue = PhantomData; type MatchVariant = PhantomData; type MatchActiveScope = (); type MatchVariantAndInactiveScope = MatchVariantWithoutScope; @@ -753,24 +557,6 @@ impl Type for PhantomData { fn source_location() -> SourceLocation { SourceLocation::builtin() } - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - assert!(opaque.is_empty()); - *self - } - fn sim_value_clone_from_opaque( - &self, - _value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ) { - assert!(opaque.is_empty()); - } - fn sim_value_to_opaque<'w>( - &self, - _value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> OpaqueSimValueWritten<'w> { - writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty()) - } } pub struct PhantomDataBuilder(PhantomData); @@ -818,35 +604,26 @@ impl ToExpr for PhantomData { } } -impl ToSimValue for PhantomData { - type Type = PhantomData; - +impl ToSimValue for PhantomData { #[track_caller] - fn to_sim_value(&self) -> SimValue { - SimValue::from_value(*self, *self) + fn to_sim_value(&self, ty: Self) -> SimValue { + ToSimValue::into_sim_value(BitVec::new(), ty) } } -impl ToSimValueWithType for PhantomData { +impl ToSimValue for PhantomData { #[track_caller] - fn to_sim_value_with_type(&self, ty: Self) -> SimValue { - SimValue::from_value(ty, *self) - } -} - -impl ToSimValueWithType for PhantomData { - #[track_caller] - fn to_sim_value_with_type(&self, ty: Bundle) -> SimValue { + fn to_sim_value(&self, ty: Bundle) -> SimValue { assert!(ty.fields().is_empty()); - SimValue::from_opaque(ty, OpaqueSimValue::empty()) + ToSimValue::into_sim_value(BitVec::new(), ty) } } -impl ToSimValueWithType for PhantomData { +impl ToSimValue for PhantomData { #[track_caller] - fn to_sim_value_with_type(&self, canonical_ty: CanonicalType) -> SimValue { - let ty = Bundle::from_canonical(canonical_ty); + fn to_sim_value(&self, ty: CanonicalType) -> SimValue { + let ty = Bundle::from_canonical(ty); assert!(ty.fields().is_empty()); - SimValue::from_opaque(canonical_ty, OpaqueSimValue::empty()) + ToSimValue::into_sim_value(BitVec::new(), ty).into_canonical() } } diff --git a/crates/fayalite/src/cli.rs b/crates/fayalite/src/cli.rs new file mode 100644 index 0000000..66741ef --- /dev/null +++ b/crates/fayalite/src/cli.rs @@ -0,0 +1,797 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information +use crate::{ + bundle::{Bundle, BundleType}, + firrtl::{self, ExportOptions}, + intern::Interned, + module::Module, + util::{job_server::AcquiredJob, streaming_read_utf8::streaming_read_utf8}, +}; +use clap::{ + builder::{OsStringValueParser, TypedValueParser}, + Parser, Subcommand, ValueEnum, ValueHint, +}; +use eyre::{eyre, Report}; +use serde::{Deserialize, Serialize}; +use std::{ + error, + ffi::OsString, + fmt::{self, Write}, + fs, io, mem, + path::{Path, PathBuf}, + process, +}; +use tempfile::TempDir; + +pub type Result = std::result::Result; + +pub struct CliError(Report); + +impl fmt::Debug for CliError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::Display for CliError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl error::Error for CliError {} + +impl From for CliError { + fn from(value: io::Error) -> Self { + CliError(Report::new(value)) + } +} + +pub trait RunPhase { + type Output; + fn run(&self, arg: Arg) -> Result { + self.run_with_job(arg, &mut AcquiredJob::acquire()) + } + fn run_with_job(&self, arg: Arg, acquired_job: &mut AcquiredJob) -> Result; +} + +#[derive(Parser, Debug, Clone)] +#[non_exhaustive] +pub struct BaseArgs { + /// the directory to put the generated main output file and associated files in + #[arg(short, long, value_hint = ValueHint::DirPath, required = true)] + pub output: Option, + /// the stem of the generated main output file, e.g. to get foo.v, pass --file-stem=foo + #[arg(long)] + pub file_stem: Option, + #[arg(long, env = "FAYALITE_KEEP_TEMP_DIR")] + pub keep_temp_dir: bool, + #[arg(skip = false)] + pub redirect_output_for_rust_test: bool, +} + +impl BaseArgs { + fn make_firrtl_file_backend(&self) -> Result<(firrtl::FileBackend, Option)> { + let (dir_path, temp_dir) = match &self.output { + Some(output) => (output.clone(), None), + None => { + let temp_dir = TempDir::new()?; + if self.keep_temp_dir { + let temp_dir = temp_dir.into_path(); + println!("created temporary directory: {}", temp_dir.display()); + (temp_dir, None) + } else { + (temp_dir.path().to_path_buf(), Some(temp_dir)) + } + } + }; + Ok(( + firrtl::FileBackend { + dir_path, + top_fir_file_stem: self.file_stem.clone(), + circuit_name: None, + }, + temp_dir, + )) + } + /// handles possibly redirecting the command's output for Rust tests + pub fn run_external_command( + &self, + _acquired_job: &mut AcquiredJob, + mut command: process::Command, + mut captured_output: Option<&mut String>, + ) -> io::Result { + if self.redirect_output_for_rust_test || captured_output.is_some() { + let (reader, writer) = os_pipe::pipe()?; + let mut reader = io::BufReader::new(reader); + command.stderr(writer.try_clone()?); + command.stdout(writer); // must not leave writer around after spawning child + command.stdin(process::Stdio::null()); + let mut child = command.spawn()?; + drop(command); // close writers + Ok(loop { + let status = child.try_wait()?; + streaming_read_utf8(&mut reader, |s| { + if let Some(captured_output) = captured_output.as_deref_mut() { + captured_output.push_str(s); + } + // use print! so output goes to Rust test output capture + print!("{s}"); + io::Result::Ok(()) + })?; + if let Some(status) = status { + break status; + } + }) + } else { + command.status() + } + } +} + +#[derive(Parser, Debug, Clone)] +#[non_exhaustive] +pub struct FirrtlArgs { + #[command(flatten)] + pub base: BaseArgs, + #[command(flatten)] + pub export_options: ExportOptions, +} + +#[derive(Debug)] +#[non_exhaustive] +pub struct FirrtlOutput { + pub file_stem: String, + pub top_module: String, + pub output_dir: PathBuf, + pub temp_dir: Option, +} + +impl FirrtlOutput { + pub fn file_with_ext(&self, ext: &str) -> PathBuf { + let mut retval = self.output_dir.join(&self.file_stem); + retval.set_extension(ext); + retval + } + pub fn firrtl_file(&self) -> PathBuf { + self.file_with_ext("fir") + } +} + +impl FirrtlArgs { + fn run_impl( + &self, + top_module: Module, + _acquired_job: &mut AcquiredJob, + ) -> Result { + let (file_backend, temp_dir) = self.base.make_firrtl_file_backend()?; + let firrtl::FileBackend { + top_fir_file_stem, + circuit_name, + dir_path, + } = firrtl::export(file_backend, &top_module, self.export_options)?; + Ok(FirrtlOutput { + file_stem: top_fir_file_stem.expect( + "export is known to set the file stem from the circuit name if not provided", + ), + top_module: circuit_name.expect("export is known to set the circuit name"), + output_dir: dir_path, + temp_dir, + }) + } +} + +impl RunPhase> for FirrtlArgs { + type Output = FirrtlOutput; + fn run_with_job( + &self, + top_module: Module, + acquired_job: &mut AcquiredJob, + ) -> Result { + self.run_impl(top_module.canonical(), acquired_job) + } +} + +impl RunPhase>> for FirrtlArgs { + type Output = FirrtlOutput; + fn run_with_job( + &self, + top_module: Interned>, + acquired_job: &mut AcquiredJob, + ) -> Result { + self.run_with_job(*top_module, acquired_job) + } +} + +/// based on [LLVM Circt's recommended lowering options +/// ](https://circt.llvm.org/docs/VerilogGeneration/#recommended-loweringoptions-by-target) +#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum VerilogDialect { + Questa, + Spyglass, + Verilator, + Vivado, + Yosys, +} + +impl fmt::Display for VerilogDialect { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +impl VerilogDialect { + pub fn as_str(self) -> &'static str { + match self { + VerilogDialect::Questa => "questa", + VerilogDialect::Spyglass => "spyglass", + VerilogDialect::Verilator => "verilator", + VerilogDialect::Vivado => "vivado", + VerilogDialect::Yosys => "yosys", + } + } + pub fn firtool_extra_args(self) -> &'static [&'static str] { + match self { + VerilogDialect::Questa => &["--lowering-options=emitWireInPorts"], + VerilogDialect::Spyglass => { + &["--lowering-options=explicitBitcast,disallowExpressionInliningInPorts"] + } + VerilogDialect::Verilator => &[ + "--lowering-options=locationInfoStyle=wrapInAtSquareBracket,disallowLocalVariables", + ], + VerilogDialect::Vivado => &["--lowering-options=mitigateVivadoArrayIndexConstPropBug"], + VerilogDialect::Yosys => { + &["--lowering-options=disallowLocalVariables,disallowPackedArrays"] + } + } + } +} + +#[derive(Parser, Debug, Clone)] +#[non_exhaustive] +pub struct VerilogArgs { + #[command(flatten)] + pub firrtl: FirrtlArgs, + #[arg( + long, + default_value = "firtool", + env = "FIRTOOL", + value_hint = ValueHint::CommandName, + value_parser = OsStringValueParser::new().try_map(which::which) + )] + pub firtool: PathBuf, + #[arg(long)] + pub firtool_extra_args: Vec, + /// adapt the generated Verilog for a particular toolchain + #[arg(long)] + pub verilog_dialect: Option, + #[arg(long, short = 'g')] + pub debug: bool, +} + +#[derive(Debug)] +#[non_exhaustive] +pub struct VerilogOutput { + pub firrtl: FirrtlOutput, + pub verilog_files: Vec, + pub contents_hash: Option, +} + +impl VerilogOutput { + pub fn main_verilog_file(&self) -> PathBuf { + self.firrtl.file_with_ext("v") + } + fn unadjusted_verilog_file(&self) -> PathBuf { + self.firrtl.file_with_ext("unadjusted.v") + } +} + +impl VerilogArgs { + fn process_unadjusted_verilog_file(&self, mut output: VerilogOutput) -> Result { + let input = fs::read_to_string(output.unadjusted_verilog_file())?; + let file_separator_prefix = "\n// ----- 8< ----- FILE \""; + let file_separator_suffix = "\" ----- 8< -----\n\n"; + let mut input = &*input; + output.contents_hash = Some(blake3::hash(input.as_bytes())); + let main_verilog_file = output.main_verilog_file(); + let mut file_name: Option<&Path> = Some(&main_verilog_file); + loop { + let (chunk, next_file_name) = if let Some((chunk, rest)) = + input.split_once(file_separator_prefix) + { + let Some((next_file_name, rest)) = rest.split_once(file_separator_suffix) else { + return Err(CliError(eyre!("parsing firtool's output failed: found {file_separator_prefix:?} but no {file_separator_suffix:?}"))); + }; + input = rest; + (chunk, Some(next_file_name.as_ref())) + } else { + (mem::take(&mut input), None) + }; + let Some(file_name) = mem::replace(&mut file_name, next_file_name) else { + break; + }; + let file_name = output.firrtl.output_dir.join(file_name); + fs::write(&file_name, chunk)?; + if let Some(extension) = file_name.extension() { + if extension == "v" || extension == "sv" { + output.verilog_files.push(file_name); + } + } + } + Ok(output) + } + fn run_impl( + &self, + firrtl_output: FirrtlOutput, + acquired_job: &mut AcquiredJob, + ) -> Result { + let Self { + firrtl, + firtool, + firtool_extra_args, + verilog_dialect, + debug, + } = self; + let output = VerilogOutput { + firrtl: firrtl_output, + verilog_files: vec![], + contents_hash: None, + }; + let mut cmd = process::Command::new(firtool); + cmd.arg(output.firrtl.firrtl_file()); + cmd.arg("-o"); + cmd.arg(output.unadjusted_verilog_file()); + if *debug { + cmd.arg("-g"); + cmd.arg("--preserve-values=all"); + } + if let Some(dialect) = verilog_dialect { + cmd.args(dialect.firtool_extra_args()); + } + cmd.args(firtool_extra_args); + cmd.current_dir(&output.firrtl.output_dir); + let status = firrtl.base.run_external_command(acquired_job, cmd, None)?; + if status.success() { + self.process_unadjusted_verilog_file(output) + } else { + Err(CliError(eyre!( + "running {} failed: {status}", + self.firtool.display() + ))) + } + } +} + +impl RunPhase for VerilogArgs +where + FirrtlArgs: RunPhase, +{ + type Output = VerilogOutput; + fn run_with_job(&self, arg: Arg, acquired_job: &mut AcquiredJob) -> Result { + let firrtl_output = self.firrtl.run_with_job(arg, acquired_job)?; + self.run_impl(firrtl_output, acquired_job) + } +} + +#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq, Hash, Default)] +#[non_exhaustive] +pub enum FormalMode { + #[default] + BMC, + Prove, + Live, + Cover, +} + +impl FormalMode { + pub fn as_str(self) -> &'static str { + match self { + FormalMode::BMC => "bmc", + FormalMode::Prove => "prove", + FormalMode::Live => "live", + FormalMode::Cover => "cover", + } + } +} + +impl fmt::Display for FormalMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +#[derive(Clone)] +struct FormalAdjustArgs; + +impl clap::FromArgMatches for FormalAdjustArgs { + fn from_arg_matches(_matches: &clap::ArgMatches) -> Result { + Ok(Self) + } + + fn update_from_arg_matches(&mut self, _matches: &clap::ArgMatches) -> Result<(), clap::Error> { + Ok(()) + } +} + +impl clap::Args for FormalAdjustArgs { + fn augment_args(cmd: clap::Command) -> clap::Command { + cmd.mut_arg("output", |arg| arg.required(false)) + .mut_arg("verilog_dialect", |arg| { + arg.default_value(VerilogDialect::Yosys.to_string()) + .hide(true) + }) + } + + fn augment_args_for_update(cmd: clap::Command) -> clap::Command { + Self::augment_args(cmd) + } +} + +#[derive(Parser, Clone)] +#[non_exhaustive] +pub struct FormalArgs { + #[command(flatten)] + pub verilog: VerilogArgs, + #[arg( + long, + default_value = "sby", + env = "SBY", + value_hint = ValueHint::CommandName, + value_parser = OsStringValueParser::new().try_map(which::which) + )] + pub sby: PathBuf, + #[arg(long)] + pub sby_extra_args: Vec, + #[arg(long, default_value_t)] + pub mode: FormalMode, + #[arg(long, default_value_t = Self::DEFAULT_DEPTH)] + pub depth: u64, + #[arg(long, default_value = "z3")] + pub solver: String, + #[arg(long)] + pub smtbmc_extra_args: Vec, + #[arg(long, default_value_t = true, env = "FAYALITE_CACHE_RESULTS")] + pub cache_results: bool, + #[command(flatten)] + _formal_adjust_args: FormalAdjustArgs, +} + +impl fmt::Debug for FormalArgs { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + verilog, + sby, + sby_extra_args, + mode, + depth, + solver, + smtbmc_extra_args, + cache_results, + _formal_adjust_args: _, + } = self; + f.debug_struct("FormalArgs") + .field("verilog", verilog) + .field("sby", sby) + .field("sby_extra_args", sby_extra_args) + .field("mode", mode) + .field("depth", depth) + .field("solver", solver) + .field("smtbmc_extra_args", smtbmc_extra_args) + .field("cache_results", cache_results) + .finish_non_exhaustive() + } +} + +impl FormalArgs { + pub const DEFAULT_DEPTH: u64 = 20; +} + +#[derive(Debug)] +#[non_exhaustive] +pub struct FormalOutput { + pub verilog: VerilogOutput, +} + +impl FormalOutput { + pub fn sby_file(&self) -> PathBuf { + self.verilog.firrtl.file_with_ext("sby") + } + pub fn cache_file(&self) -> PathBuf { + self.verilog.firrtl.file_with_ext("cache.json") + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[non_exhaustive] +pub struct FormalCacheOutput {} + +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[non_exhaustive] +pub enum FormalCacheVersion { + V1, +} + +impl FormalCacheVersion { + pub const CURRENT: Self = Self::V1; +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[non_exhaustive] +pub struct FormalCache { + pub version: FormalCacheVersion, + pub contents_hash: blake3::Hash, + pub stdout_stderr: String, + pub result: Result, +} + +impl FormalCache { + pub fn new( + version: FormalCacheVersion, + contents_hash: blake3::Hash, + stdout_stderr: String, + result: Result, + ) -> Self { + Self { + version, + contents_hash, + stdout_stderr, + result, + } + } +} + +impl FormalArgs { + fn sby_contents(&self, output: &FormalOutput) -> Result { + let Self { + verilog: _, + sby: _, + sby_extra_args: _, + mode, + depth, + smtbmc_extra_args, + solver, + cache_results: _, + _formal_adjust_args: _, + } = self; + let smtbmc_options = smtbmc_extra_args.join(" "); + let top_module = &output.verilog.firrtl.top_module; + let mut retval = format!( + "[options]\n\ + mode {mode}\n\ + depth {depth}\n\ + wait on\n\ + \n\ + [engines]\n\ + smtbmc {solver} -- -- {smtbmc_options}\n\ + \n\ + [script]\n" + ); + for verilog_file in &output.verilog.verilog_files { + let verilog_file = verilog_file + .to_str() + .ok_or_else(|| CliError(eyre!("verilog file path is not UTF-8")))?; + if verilog_file.contains(|ch: char| { + (ch != ' ' && ch != '\t' && ch.is_ascii_whitespace()) || ch == '"' + }) { + return Err(CliError(eyre!( + "verilog file path contains characters that aren't permitted" + ))); + } + writeln!(retval, "read_verilog -sv -formal \"{verilog_file}\"").unwrap(); + } + // workaround for wires disappearing -- set `keep` on all wires + writeln!(retval, "hierarchy -top {top_module}").unwrap(); + writeln!(retval, "proc").unwrap(); + writeln!(retval, "setattr -set keep 1 w:\\*").unwrap(); + writeln!(retval, "prep").unwrap(); + Ok(retval) + } + fn run_impl( + &self, + verilog_output: VerilogOutput, + acquired_job: &mut AcquiredJob, + ) -> Result { + let output = FormalOutput { + verilog: verilog_output, + }; + let sby_file = output.sby_file(); + let sby_contents = self.sby_contents(&output)?; + let contents_hash = output.verilog.contents_hash.map(|verilog_hash| { + let mut hasher = blake3::Hasher::new(); + hasher.update(verilog_hash.as_bytes()); + hasher.update(sby_contents.as_bytes()); + hasher.update(&(self.sby_extra_args.len() as u64).to_le_bytes()); + for sby_extra_arg in self.sby_extra_args.iter() { + hasher.update(&(sby_extra_arg.len() as u64).to_le_bytes()); + hasher.update(sby_extra_arg.as_bytes()); + } + hasher.finalize() + }); + std::fs::write(&sby_file, sby_contents)?; + let mut cmd = process::Command::new(&self.sby); + cmd.arg("-j1"); // sby seems not to respect job count in parallel mode + cmd.arg("-f"); + cmd.arg(sby_file.file_name().unwrap()); + cmd.args(&self.sby_extra_args); + cmd.current_dir(&output.verilog.firrtl.output_dir); + let mut captured_output = String::new(); + let cache_file = output.cache_file(); + let do_cache = if let Some(contents_hash) = contents_hash.filter(|_| self.cache_results) { + if let Some(FormalCache { + version: FormalCacheVersion::CURRENT, + contents_hash: cache_contents_hash, + stdout_stderr, + result, + }) = fs::read(&cache_file) + .ok() + .and_then(|v| serde_json::from_slice(&v).ok()) + { + if cache_contents_hash == contents_hash { + println!("Using cached formal result:\n{stdout_stderr}"); + return match result { + Ok(FormalCacheOutput {}) => Ok(output), + Err(error) => Err(CliError(eyre::Report::msg(error))), + }; + } + } + true + } else { + false + }; + let _ = fs::remove_file(&cache_file); + let status = self.verilog.firrtl.base.run_external_command( + acquired_job, + cmd, + do_cache.then_some(&mut captured_output), + )?; + let result = if status.success() { + Ok(output) + } else { + Err(CliError(eyre!( + "running {} failed: {status}", + self.sby.display() + ))) + }; + fs::write( + cache_file, + serde_json::to_string_pretty(&FormalCache { + version: FormalCacheVersion::CURRENT, + contents_hash: contents_hash.unwrap(), + stdout_stderr: captured_output, + result: match &result { + Ok(FormalOutput { verilog: _ }) => Ok(FormalCacheOutput {}), + Err(error) => Err(error.to_string()), + }, + }) + .expect("serialization shouldn't ever fail"), + )?; + result + } +} + +impl RunPhase for FormalArgs +where + VerilogArgs: RunPhase, +{ + type Output = FormalOutput; + fn run_with_job(&self, arg: Arg, acquired_job: &mut AcquiredJob) -> Result { + let verilog_output = self.verilog.run_with_job(arg, acquired_job)?; + self.run_impl(verilog_output, acquired_job) + } +} + +#[derive(Subcommand, Debug)] +enum CliCommand { + /// Generate FIRRTL + Firrtl(FirrtlArgs), + /// Generate Verilog + Verilog(VerilogArgs), + /// Run a formal proof + Formal(FormalArgs), +} + +/// a simple CLI +/// +/// Use like: +/// +/// ```no_run +/// # use fayalite::prelude::*; +/// # #[hdl_module] +/// # fn my_module() {} +/// use fayalite::cli; +/// +/// fn main() -> cli::Result { +/// cli::Cli::parse().run(my_module()) +/// } +/// ``` +/// +/// You can also use it with a larger [`clap`]-based CLI like so: +/// +/// ```no_run +/// # use fayalite::prelude::*; +/// # #[hdl_module] +/// # fn my_module() {} +/// use clap::{Subcommand, Parser}; +/// use fayalite::cli; +/// +/// #[derive(Subcommand)] +/// pub enum Cmd { +/// #[command(flatten)] +/// Fayalite(cli::Cli), +/// MySpecialCommand { +/// #[arg(long)] +/// foo: bool, +/// }, +/// } +/// +/// #[derive(Parser)] +/// pub struct Cli { +/// #[command(subcommand)] +/// cmd: Cmd, // or just use cli::Cli directly if you don't need more subcommands +/// } +/// +/// fn main() -> cli::Result { +/// match Cli::parse().cmd { +/// Cmd::Fayalite(v) => v.run(my_module())?, +/// Cmd::MySpecialCommand { foo } => println!("special: foo={foo}"), +/// } +/// Ok(()) +/// } +/// ``` +#[derive(Parser, Debug)] +// clear things that would be crate-specific +#[command(name = "Fayalite Simple CLI", about = None, long_about = None)] +pub struct Cli { + #[command(subcommand)] + subcommand: CliCommand, +} + +impl clap::Subcommand for Cli { + fn augment_subcommands(cmd: clap::Command) -> clap::Command { + CliCommand::augment_subcommands(cmd) + } + + fn augment_subcommands_for_update(cmd: clap::Command) -> clap::Command { + CliCommand::augment_subcommands_for_update(cmd) + } + + fn has_subcommand(name: &str) -> bool { + CliCommand::has_subcommand(name) + } +} + +impl RunPhase for Cli +where + FirrtlArgs: RunPhase, +{ + type Output = (); + fn run_with_job(&self, arg: T, acquired_job: &mut AcquiredJob) -> Result { + match &self.subcommand { + CliCommand::Firrtl(c) => { + c.run_with_job(arg, acquired_job)?; + } + CliCommand::Verilog(c) => { + c.run_with_job(arg, acquired_job)?; + } + CliCommand::Formal(c) => { + c.run_with_job(arg, acquired_job)?; + } + } + Ok(()) + } +} + +impl Cli { + /// forwards to [`clap::Parser::parse()`] so you don't have to import [`clap::Parser`] + pub fn parse() -> Self { + clap::Parser::parse() + } + /// forwards to [`RunPhase::run()`] so you don't have to import [`RunPhase`] + pub fn run(&self, top_module: T) -> Result<()> + where + Self: RunPhase, + { + RunPhase::run(self, top_module) + } +} diff --git a/crates/fayalite/src/clock.rs b/crates/fayalite/src/clock.rs index 909edbd..711432b 100644 --- a/crates/fayalite/src/clock.rs +++ b/crates/fayalite/src/clock.rs @@ -6,12 +6,8 @@ use crate::{ int::Bool, reset::{Reset, ResetType}, source_location::SourceLocation, - ty::{ - CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter, - OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self, - }, + ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, }; -use bitvec::{bits, order::Lsb0}; #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)] pub struct Clock; @@ -19,7 +15,6 @@ pub struct Clock; impl Type for Clock { type BaseType = Clock; type MaskType = Bool; - type SimValue = bool; impl_match_variant_as_self!(); @@ -41,31 +36,6 @@ impl Type for Clock { }; retval } - - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); - opaque.bits()[0] - } - - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ) { - assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); - *value = opaque.bits()[0]; - } - - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> OpaqueSimValueWritten<'w> { - assert_eq!(writer.size(), OpaqueSimValueSize::from_bit_width(1)); - writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice( - [bits![0], bits![1]][*value as usize], - )) - } } impl Clock { @@ -85,7 +55,6 @@ impl StaticType for Clock { is_storable: false, is_castable_from_bits: true, bit_width: 1, - sim_only_values_len: 0, }; const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; } diff --git a/crates/fayalite/src/enum_.rs b/crates/fayalite/src/enum_.rs index 083072b..2ed0b8e 100644 --- a/crates/fayalite/src/enum_.rs +++ b/crates/fayalite/src/enum_.rs @@ -2,31 +2,21 @@ // See Notices.txt for copyright information use crate::{ - expr::{ - Expr, ToExpr, - ops::{ExprPartialEq, VariantAccess}, - }, + expr::{ops::VariantAccess, Expr, ToExpr}, hdl, - int::{Bool, UIntValue}, + int::Bool, intern::{Intern, Interned}, module::{ - EnumMatchVariantAndInactiveScopeImpl, EnumMatchVariantsIterImpl, Scope, connect, - enum_match_variants_helper, incomplete_wire, wire, + connect, enum_match_variants_helper, incomplete_wire, wire, + EnumMatchVariantAndInactiveScopeImpl, EnumMatchVariantsIterImpl, Scope, }, - sim::value::{SimValue, SimValuePartialEq}, source_location::SourceLocation, - ty::{ - CanonicalType, MatchVariantAndInactiveScope, OpaqueSimValue, OpaqueSimValueSize, - OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, StaticType, Type, - TypeProperties, - }, - util::HashMap, + ty::{CanonicalType, MatchVariantAndInactiveScope, StaticType, Type, TypeProperties}, }; -use bitvec::{order::Lsb0, slice::BitSlice, view::BitView}; -use serde::{Deserialize, Serialize}; -use std::{convert::Infallible, fmt, iter::FusedIterator, sync::Arc}; +use hashbrown::HashMap; +use std::{convert::Infallible, fmt, iter::FusedIterator}; -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct EnumVariant { pub name: Interned, pub ty: Option, @@ -121,7 +111,6 @@ impl EnumTypePropertiesBuilder { is_storable: true, is_castable_from_bits: true, bit_width: 0, - sim_only_values_len: 0, }, variant_count: 0, } @@ -140,14 +129,9 @@ impl EnumTypePropertiesBuilder { is_storable, is_castable_from_bits, bit_width, - sim_only_values_len, }) = field_props { assert!(is_passive, "variant type must be a passive type"); - assert!( - sim_only_values_len == 0, - "can't have `SimOnlyValue`s in an Enum" - ); type_properties = TypeProperties { is_passive: true, is_storable: type_properties.is_storable & is_storable, @@ -158,7 +142,6 @@ impl EnumTypePropertiesBuilder { } else { type_properties.bit_width }, - sim_only_values_len: 0, }; } Self { @@ -166,12 +149,6 @@ impl EnumTypePropertiesBuilder { variant_count: variant_count + 1, } } - #[must_use] - pub fn variants(self, variants: impl IntoIterator) -> Self { - variants.into_iter().fold(self, |this, variant| { - this.variant(variant.ty.map(CanonicalType::type_properties)) - }) - } pub const fn finish(self) -> TypeProperties { assert!( self.variant_count != 0, @@ -201,8 +178,7 @@ impl Default for EnumTypePropertiesBuilder { impl Enum { #[track_caller] pub fn new(variants: Interned<[EnumVariant]>) -> Self { - let mut name_indexes = - HashMap::with_capacity_and_hasher(variants.len(), Default::default()); + let mut name_indexes = HashMap::with_capacity(variants.len()); let mut type_props_builder = EnumTypePropertiesBuilder::new(); for (index, EnumVariant { name, ty }) in variants.iter().enumerate() { if let Some(old_index) = name_indexes.insert(*name, index) { @@ -262,14 +238,13 @@ impl Enum { pub trait EnumType: Type< - BaseType = Enum, - MaskType = Bool, - MatchActiveScope = Scope, - MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope, - MatchVariantsIter = EnumMatchVariantsIter, - > + BaseType = Enum, + MaskType = Bool, + MatchActiveScope = Scope, + MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope, + MatchVariantsIter = EnumMatchVariantsIter, +> { - type SimBuilder: From; fn variants(&self) -> Interned<[EnumVariant]>; fn match_activate_scope( v: Self::MatchVariantAndInactiveScope, @@ -332,18 +307,7 @@ impl DoubleEndedIterator for EnumMatchVariantsIter { } } -pub struct NoBuilder { - _ty: Enum, -} - -impl From for NoBuilder { - fn from(_ty: Enum) -> Self { - Self { _ty } - } -} - impl EnumType for Enum { - type SimBuilder = NoBuilder; fn match_activate_scope( v: Self::MatchVariantAndInactiveScope, ) -> (Self::MatchVariant, Self::MatchActiveScope) { @@ -358,7 +322,6 @@ impl EnumType for Enum { impl Type for Enum { type BaseType = Enum; type MaskType = Bool; - type SimValue = OpaqueSimValue; type MatchVariant = Option>; type MatchActiveScope = Scope; type MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope; @@ -389,341 +352,6 @@ impl Type for Enum { fn source_location() -> SourceLocation { SourceLocation::builtin() } - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - assert_eq!(self.type_properties().size(), opaque.size()); - opaque.to_owned() - } - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ) { - assert_eq!(self.type_properties().size(), opaque.size()); - assert_eq!(value.size(), opaque.size()); - value.clone_from_slice(opaque); - } - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> OpaqueSimValueWritten<'w> { - assert_eq!(self.type_properties().size(), writer.size()); - assert_eq!(value.size(), writer.size()); - writer.fill_cloned_from_slice(value.as_slice()) - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)] -pub struct EnumPaddingSimValue { - bits: Option, -} - -impl EnumPaddingSimValue { - pub const fn new() -> Self { - Self { bits: None } - } - pub fn bit_width(&self) -> Option { - self.bits.as_ref().map(UIntValue::width) - } - pub fn bits(&self) -> &Option { - &self.bits - } - pub fn bits_mut(&mut self) -> &mut Option { - &mut self.bits - } - pub fn into_bits(self) -> Option { - self.bits - } - pub fn from_bits(bits: Option) -> Self { - Self { bits } - } - pub fn from_bitslice(v: &BitSlice) -> Self { - Self { - bits: Some(UIntValue::new(Arc::new(v.to_bitvec()))), - } - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct UnknownVariantSimValue { - discriminant: usize, - body_bits: UIntValue, -} - -impl UnknownVariantSimValue { - pub fn discriminant(&self) -> usize { - self.discriminant - } - pub fn body_bits(&self) -> &UIntValue { - &self.body_bits - } - pub fn body_bits_mut(&mut self) -> &mut UIntValue { - &mut self.body_bits - } - pub fn into_body_bits(self) -> UIntValue { - self.body_bits - } - pub fn into_parts(self) -> (usize, UIntValue) { - (self.discriminant, self.body_bits) - } - pub fn new(discriminant: usize, body_bits: UIntValue) -> Self { - Self { - discriminant, - body_bits, - } - } -} - -pub struct EnumSimValueFromOpaque<'a> { - variants: Interned<[EnumVariant]>, - discriminant: usize, - body_bits: &'a BitSlice, -} - -impl<'a> EnumSimValueFromOpaque<'a> { - #[track_caller] - pub fn new(ty: T, opaque: OpaqueSimValueSlice<'a>) -> Self { - let variants = ty.variants(); - let size = EnumTypePropertiesBuilder::new() - .variants(variants) - .finish() - .size(); - assert!(size.only_bit_width().is_some()); - assert_eq!(size, opaque.size()); - let (discriminant_bits, body_bits) = opaque - .bits() - .split_at(discriminant_bit_width_impl(variants.len())); - let mut discriminant = 0usize; - discriminant.view_bits_mut::()[..discriminant_bits.len()] - .copy_from_bitslice(discriminant_bits); - Self { - variants, - discriminant, - body_bits, - } - } - pub fn discriminant(&self) -> usize { - self.discriminant - } - #[track_caller] - #[cold] - fn usage_error(&self, clone: bool) -> ! { - let clone = if clone { "clone_" } else { "" }; - match self.variants.get(self.discriminant) { - None => { - panic!("should have called EnumSimValueFromBits::unknown_variant_{clone}from_bits"); - } - Some(EnumVariant { ty: None, .. }) => { - panic!( - "should have called EnumSimValueFromBits::variant_no_field_{clone}from_bits" - ); - } - Some(EnumVariant { ty: Some(_), .. }) => { - panic!( - "should have called EnumSimValueFromBits::variant_with_field_{clone}from_bits" - ); - } - } - } - #[track_caller] - fn known_variant(&self, clone: bool) -> (Option, &'a BitSlice, &'a BitSlice) { - let Some(EnumVariant { ty, .. }) = self.variants.get(self.discriminant) else { - self.usage_error(clone); - }; - let variant_bit_width = ty.map_or(0, CanonicalType::bit_width); - let (variant_bits, padding_bits) = self.body_bits.split_at(variant_bit_width); - (*ty, variant_bits, padding_bits) - } - #[track_caller] - pub fn unknown_variant_from_opaque(self) -> UnknownVariantSimValue { - let None = self.variants.get(self.discriminant) else { - self.usage_error(false); - }; - UnknownVariantSimValue::new( - self.discriminant, - UIntValue::new(Arc::new(self.body_bits.to_bitvec())), - ) - } - #[track_caller] - pub fn unknown_variant_clone_from_opaque(self, value: &mut UnknownVariantSimValue) { - let None = self.variants.get(self.discriminant) else { - self.usage_error(true); - }; - value.discriminant = self.discriminant; - assert_eq!(value.body_bits.width(), self.body_bits.len()); - value - .body_bits - .bits_mut() - .copy_from_bitslice(self.body_bits); - } - #[track_caller] - pub fn variant_no_field_from_opaque(self) -> EnumPaddingSimValue { - let (None, _variant_bits, padding_bits) = self.known_variant(false) else { - self.usage_error(false); - }; - EnumPaddingSimValue::from_bitslice(padding_bits) - } - #[track_caller] - pub fn variant_with_field_from_opaque(self) -> (SimValue, EnumPaddingSimValue) { - let (Some(variant_ty), variant_bits, padding_bits) = self.known_variant(false) else { - self.usage_error(false); - }; - ( - SimValue::from_bitslice(T::from_canonical(variant_ty), variant_bits), - EnumPaddingSimValue::from_bitslice(padding_bits), - ) - } - #[track_caller] - fn clone_padding_from_bits(padding: &mut EnumPaddingSimValue, padding_bits: &BitSlice) { - match padding.bits_mut() { - None => *padding = EnumPaddingSimValue::from_bitslice(padding_bits), - Some(padding) => { - assert_eq!(padding.width(), padding_bits.len()); - padding.bits_mut().copy_from_bitslice(padding_bits); - } - } - } - #[track_caller] - pub fn variant_no_field_clone_from_opaque(self, padding: &mut EnumPaddingSimValue) { - let (None, _variant_bits, padding_bits) = self.known_variant(true) else { - self.usage_error(true); - }; - Self::clone_padding_from_bits(padding, padding_bits); - } - #[track_caller] - pub fn variant_with_field_clone_from_opaque( - self, - value: &mut SimValue, - padding: &mut EnumPaddingSimValue, - ) { - let (Some(variant_ty), variant_bits, padding_bits) = self.known_variant(true) else { - self.usage_error(true); - }; - assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty)); - SimValue::bits_mut(value) - .bits_mut() - .copy_from_bitslice(variant_bits); - Self::clone_padding_from_bits(padding, padding_bits); - } -} - -pub struct EnumSimValueToOpaque<'a> { - variants: Interned<[EnumVariant]>, - bit_width: usize, - discriminant_bit_width: usize, - writer: OpaqueSimValueWriter<'a>, -} - -impl<'a> EnumSimValueToOpaque<'a> { - #[track_caller] - pub fn new(ty: T, writer: OpaqueSimValueWriter<'a>) -> Self { - let variants = ty.variants(); - let size = EnumTypePropertiesBuilder::new() - .variants(variants) - .finish() - .size(); - assert_eq!(size, writer.size()); - Self { - variants, - bit_width: size - .only_bit_width() - .expect("enums should only contain bits"), - discriminant_bit_width: discriminant_bit_width_impl(variants.len()), - writer, - } - } - #[track_caller] - fn write_discriminant(&mut self, mut discriminant: usize) { - let orig_discriminant = discriminant; - let discriminant_bits = - &mut discriminant.view_bits_mut::()[..self.discriminant_bit_width]; - self.writer.fill_prefix_with( - OpaqueSimValueSize::from_bit_width(self.discriminant_bit_width), - |writer| { - writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(discriminant_bits)) - }, - ); - discriminant_bits.fill(false); - assert!( - discriminant == 0, - "{orig_discriminant:#x} is too big to fit in enum discriminant bits", - ); - } - #[track_caller] - pub fn unknown_variant_to_opaque( - mut self, - value: &UnknownVariantSimValue, - ) -> OpaqueSimValueWritten<'a> { - self.write_discriminant(value.discriminant); - let None = self.variants.get(value.discriminant) else { - panic!("can't use UnknownVariantSimValue to set known discriminant"); - }; - assert_eq!( - self.bit_width - self.discriminant_bit_width, - value.body_bits.width() - ); - self.writer - .fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(value.body_bits.bits())) - } - #[track_caller] - fn known_variant( - mut self, - discriminant: usize, - value: Option<&OpaqueSimValue>, - padding: &EnumPaddingSimValue, - ) -> OpaqueSimValueWritten<'a> { - self.write_discriminant(discriminant); - let variant_ty = self.variants[discriminant].ty; - let variant_size = variant_ty.map_or(OpaqueSimValueSize::empty(), CanonicalType::size); - if let Some(value) = value { - if variant_ty.is_none() { - panic!("expected variant to have no field"); - } - self.writer.fill_prefix_with(variant_size, |writer| { - writer.fill_cloned_from_slice(value.as_slice()) - }); - } else if variant_ty.is_some() { - panic!("expected variant to have a field"); - } - if let Some(padding) = padding.bits() { - assert_eq!(padding.ty().type_properties().size(), self.writer.size()); - self.writer - .fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(padding.bits())) - } else { - self.writer.fill_with_zeros() - } - } - #[track_caller] - pub fn variant_no_field_to_opaque( - self, - discriminant: usize, - padding: &EnumPaddingSimValue, - ) -> OpaqueSimValueWritten<'a> { - self.known_variant(discriminant, None, padding) - } - #[track_caller] - pub fn variant_with_field_to_opaque( - self, - discriminant: usize, - value: &SimValue, - padding: &EnumPaddingSimValue, - ) -> OpaqueSimValueWritten<'a> { - let Some(variant_ty) = self.variants[discriminant].ty else { - panic!("expected variant to have no field"); - }; - assert_eq!(SimValue::ty(value), T::from_canonical(variant_ty)); - self.known_variant(discriminant, Some(SimValue::opaque(value)), padding) - } -} - -#[doc(hidden)] -pub fn assert_is_enum_type(v: T) -> T { - v -} - -#[doc(hidden)] -pub fn enum_type_to_sim_builder(v: T) -> T::SimBuilder { - v.into() } #[hdl] @@ -732,79 +360,6 @@ pub enum HdlOption { HdlSome(T), } -impl, Rhs: Type> ExprPartialEq> for HdlOption { - #[hdl] - fn cmp_eq(lhs: Expr, rhs: Expr>) -> Expr { - #[hdl] - let cmp_eq = wire(); - #[hdl] - match lhs { - HdlSome(lhs) => - { - #[hdl] - match rhs { - HdlSome(rhs) => connect(cmp_eq, ExprPartialEq::cmp_eq(lhs, rhs)), - HdlNone => connect(cmp_eq, false), - } - } - HdlNone => - { - #[hdl] - match rhs { - HdlSome(_) => connect(cmp_eq, false), - HdlNone => connect(cmp_eq, true), - } - } - } - cmp_eq - } - - #[hdl] - fn cmp_ne(lhs: Expr, rhs: Expr>) -> Expr { - #[hdl] - let cmp_ne = wire(); - #[hdl] - match lhs { - HdlSome(lhs) => - { - #[hdl] - match rhs { - HdlSome(rhs) => connect(cmp_ne, ExprPartialEq::cmp_ne(lhs, rhs)), - HdlNone => connect(cmp_ne, true), - } - } - HdlNone => - { - #[hdl] - match rhs { - HdlSome(_) => connect(cmp_ne, true), - HdlNone => connect(cmp_ne, false), - } - } - } - cmp_ne - } -} - -impl, Rhs: Type> SimValuePartialEq> for HdlOption { - fn sim_value_eq(this: &SimValue, other: &SimValue>) -> bool { - type SimValueMatch = ::SimValue; - match (&**this, &**other) { - (SimValueMatch::::HdlNone(_), SimValueMatch::>::HdlNone(_)) => { - true - } - (SimValueMatch::::HdlSome(..), SimValueMatch::>::HdlNone(_)) - | (SimValueMatch::::HdlNone(_), SimValueMatch::>::HdlSome(..)) => { - false - } - ( - SimValueMatch::::HdlSome(l, _), - SimValueMatch::>::HdlSome(r, _), - ) => l == r, - } - } -} - #[allow(non_snake_case)] pub fn HdlNone() -> Expr> { HdlOption[T::TYPE].HdlNone() diff --git a/crates/fayalite/src/expr.rs b/crates/fayalite/src/expr.rs index 89e60cd..f0008f4 100644 --- a/crates/fayalite/src/expr.rs +++ b/crates/fayalite/src/expr.rs @@ -13,10 +13,9 @@ use crate::{ intern::{Intern, Interned}, memory::{DynPortType, MemPort, PortType}, module::{ - Instance, ModuleIO, transform::visit::{Fold, Folder, Visit, Visitor}, + Instance, ModuleIO, }, - phantom_const::PhantomConst, reg::Reg, reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, ty::{CanonicalType, StaticType, Type, TypeWithDeref}, @@ -110,7 +109,6 @@ expr_enum! { UIntLiteral(Interned), SIntLiteral(Interned), BoolLiteral(bool), - PhantomConst(PhantomConst), BundleLiteral(ops::BundleLiteral), ArrayLiteral(ops::ArrayLiteral), EnumLiteral(ops::EnumLiteral), @@ -274,20 +272,6 @@ pub struct Expr { impl fmt::Debug for Expr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[cfg(debug_assertions)] - { - let Self { - __enum, - __ty, - __flow, - } = self; - let expr_ty = __ty.canonical(); - let enum_ty = __enum.to_expr().__ty; - assert_eq!( - expr_ty, enum_ty, - "expr ty mismatch:\nExpr {{\n__enum: {__enum:?},\n__ty: {__ty:?},\n__flow: {__flow:?}\n}}" - ); - } self.__enum.fmt(f) } } @@ -532,7 +516,11 @@ impl Flow { } } pub const fn flip_if(self, flipped: bool) -> Flow { - if flipped { self.flip() } else { self } + if flipped { + self.flip() + } else { + self + } } } @@ -710,7 +698,6 @@ impl CastToBits for T { } pub trait CastBitsTo { - #[track_caller] fn cast_bits_to(&self, ty: T) -> Expr; } @@ -768,27 +755,3 @@ pub fn repeat( ) .to_expr() } - -impl ToExpr for PhantomConst { - type Type = Self; - - fn to_expr(&self) -> Expr { - Expr { - __enum: ExprEnum::PhantomConst(self.canonical_phantom_const()).intern_sized(), - __ty: *self, - __flow: Flow::Source, - } - } -} - -impl GetTarget for PhantomConst { - fn target(&self) -> Option> { - None - } -} - -impl ToLiteralBits for PhantomConst { - fn to_literal_bits(&self) -> Result, NotALiteralExpr> { - Ok(Interned::default()) - } -} diff --git a/crates/fayalite/src/expr/ops.rs b/crates/fayalite/src/expr/ops.rs index b10e3ae..15c195e 100644 --- a/crates/fayalite/src/expr/ops.rs +++ b/crates/fayalite/src/expr/ops.rs @@ -7,19 +7,18 @@ use crate::{ clock::{Clock, ToClock}, enum_::{Enum, EnumType, EnumVariant}, expr::{ - CastBitsTo as _, CastTo, CastToBits as _, Expr, ExprEnum, Flow, HdlPartialEq, - HdlPartialOrd, NotALiteralExpr, ReduceBits, ToExpr, ToLiteralBits, target::{ GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, }, + CastTo, Expr, ExprEnum, Flow, HdlPartialEq, HdlPartialOrd, NotALiteralExpr, ReduceBits, + ToExpr, ToLiteralBits, }, int::{ Bool, BoolOrIntType, DynSize, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue, }, intern::{Intern, Interned}, - phantom_const::{PhantomConst, PhantomConstValue}, reset::{ AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset, ToAsyncReset, ToReset, ToSyncReset, @@ -1893,26 +1892,6 @@ impl ExprCastTo for Clock { } } -impl ExprCastTo<()> for PhantomConst { - fn cast_to(src: Expr, to_type: ()) -> Expr<()> { - src.cast_to_bits().cast_bits_to(to_type) - } -} - -impl ExprCastTo> for () { - fn cast_to(src: Expr, to_type: PhantomConst) -> Expr> { - src.cast_to_bits().cast_bits_to(to_type) - } -} - -impl ExprCastTo> - for PhantomConst -{ - fn cast_to(src: Expr, to_type: PhantomConst) -> Expr> { - src.cast_to_bits().cast_bits_to(to_type) - } -} - #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct FieldAccess { base: Expr, @@ -1937,8 +1916,7 @@ impl FieldAccess { let field = Expr::ty(base).fields()[field_index]; let field_type = FieldType::from_canonical(field.ty); let literal_bits = base.to_literal_bits().map(|bits| { - bits[Expr::ty(base).field_offsets()[field_index].bit_width..][..field.ty.bit_width()] - .intern() + bits[Expr::ty(base).field_offsets()[field_index]..][..field.ty.bit_width()].intern() }); let target = base.target().map(|base| { Intern::intern_sized(base.join(TargetPathElement::intern_sized( @@ -2730,47 +2708,3 @@ impl ToExpr for Uninit { } } } - -pub trait ExprIntoIterator: Type { - type Item: Type; - type ExprIntoIter: Iterator>; - - fn expr_into_iter(e: Expr) -> Self::ExprIntoIter; -} - -impl IntoIterator for Expr { - type Item = Expr; - type IntoIter = T::ExprIntoIter; - - fn into_iter(self) -> Self::IntoIter { - T::expr_into_iter(self) - } -} - -impl IntoIterator for &'_ Expr { - type Item = Expr; - type IntoIter = T::ExprIntoIter; - - fn into_iter(self) -> Self::IntoIter { - T::expr_into_iter(*self) - } -} - -impl IntoIterator for &'_ mut Expr { - type Item = Expr; - type IntoIter = T::ExprIntoIter; - - fn into_iter(self) -> Self::IntoIter { - T::expr_into_iter(*self) - } -} - -pub trait ExprFromIterator: Type { - fn expr_from_iter>(iter: T) -> Expr; -} - -impl, A> FromIterator for Expr { - fn from_iter>(iter: T) -> Self { - This::expr_from_iter(iter) - } -} diff --git a/crates/fayalite/src/firrtl.rs b/crates/fayalite/src/firrtl.rs index cca0d82..ea76cf8 100644 --- a/crates/fayalite/src/firrtl.rs +++ b/crates/fayalite/src/firrtl.rs @@ -4,99 +4,60 @@ use crate::{ annotations::{ Annotation, BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, - DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation, TargetedAnnotation, + DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation, }, array::Array, - build::{ToArgs, WriteArgs}, bundle::{Bundle, BundleField, BundleType}, clock::Clock, enum_::{Enum, EnumType, EnumVariant}, expr::{ - CastBitsTo, Expr, ExprEnum, ops::{self, VariantAccess}, target::{ Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement, }, + Expr, ExprEnum, }, formal::FormalKind, int::{Bool, DynSize, IntType, SIntValue, UInt, UIntValue}, intern::{Intern, Interned}, memory::{Mem, PortKind, PortName, ReadUnderWrite}, module::{ - AnnotatedModuleIO, Block, ExternModuleBody, ExternModuleParameter, - ExternModuleParameterValue, Module, ModuleBody, ModuleIO, NameId, NameOptId, - NormalModuleBody, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, - StmtMatch, StmtReg, StmtWire, transform::{ - simplify_enums::{SimplifyEnumsError, SimplifyEnumsKind, simplify_enums}, + simplify_enums::{simplify_enums, SimplifyEnumsError, SimplifyEnumsKind}, simplify_memories::simplify_memories, }, + AnnotatedModuleIO, Block, ExternModuleBody, ExternModuleParameter, + ExternModuleParameterValue, Module, ModuleBody, NameOptId, NormalModuleBody, Stmt, + StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, + StmtWire, }, reset::{AsyncReset, Reset, ResetType, SyncReset}, source_location::SourceLocation, - ty::{CanonicalType, OpaqueSimValueSize, Type}, + ty::{CanonicalType, Type}, util::{ - BitSliceWriteWithBase, DebugAsRawString, GenericConstBool, HashMap, HashSet, - const_str_array_is_strictly_ascending, + const_str_array_is_strictly_ascending, BitSliceWriteWithBase, DebugAsRawString, + GenericConstBool, }, - vendor::xilinx::XilinxAnnotation, }; use bitvec::slice::BitSlice; use clap::value_parser; +use hashbrown::{HashMap, HashSet}; use num_traits::Signed; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use std::{ cell::{Cell, RefCell}, cmp::Ordering, collections::{BTreeMap, VecDeque}, error::Error, - ffi::OsString, fmt::{self, Write}, fs, hash::Hash, io, - ops::{ControlFlow, Range}, + ops::Range, path::{Path, PathBuf}, rc::Rc, }; -#[derive(Clone, Debug)] -#[non_exhaustive] -enum FirrtlError { - SimOnlyValuesAreNotPermitted, -} - -impl fmt::Display for FirrtlError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - FirrtlError::SimOnlyValuesAreNotPermitted => { - f.write_str("`SimOnlyValue`s are not permitted") - } - } - } -} - -impl std::error::Error for FirrtlError {} - -enum FirrtlOrWrappedError { - FirrtlError(FirrtlError), - WrappedError(WrappedError), -} - -impl From for FirrtlOrWrappedError { - fn from(value: FirrtlError) -> Self { - Self::FirrtlError(value) - } -} - -impl From for FirrtlOrWrappedError { - fn from(value: WrappedError) -> Self { - Self::WrappedError(value) - } -} - -type Result = std::result::Result; - struct EscapedString<'a> { value: &'a str, raw: bool, @@ -360,20 +321,20 @@ impl DefinitionsMap { map: Default::default(), } } - fn get_or_make<'a, E>( + fn get_or_make<'a>( &'a self, key: K, - make: impl FnOnce(&K, &'a RcDefinitions) -> Result<(Ident, V), E>, - ) -> Result<(Ident, V), E> + make: impl FnOnce(&K, &'a RcDefinitions) -> (Ident, V), + ) -> (Ident, V) where K: Hash + Eq, V: Clone, { if let Some(retval) = self.map.borrow().get(&key) { - return Ok(retval.clone()); + return retval.clone(); } - let value = make(&key, &self.definitions)?; - Ok(self.map.borrow_mut().entry(key).or_insert(value).clone()) + let value = make(&key, &self.definitions); + self.map.borrow_mut().entry(key).or_insert(value).clone() } } @@ -407,10 +368,10 @@ impl TypeState { self.next_type_name.set(id + 1); Ident(Intern::intern_owned(format!("Ty{id}"))) } - fn get_bundle_field(&mut self, ty: Bundle, name: Interned) -> Result { - Ok(self.bundle_ns(ty)?.borrow_mut().get(name)) + fn get_bundle_field(&mut self, ty: Bundle, name: Interned) -> Ident { + self.bundle_ns(ty).borrow_mut().get(name) } - fn bundle_def(&self, ty: Bundle) -> Result<(Ident, Rc>), FirrtlError> { + fn bundle_def(&self, ty: Bundle) -> (Ident, Rc>) { self.bundle_defs.get_or_make(ty, |&ty, definitions| { let mut ns = Namespace::default(); let mut body = String::new(); @@ -423,21 +384,21 @@ impl TypeState { body.push_str("flip "); } write!(body, "{}: ", ns.get(name)).unwrap(); - body.push_str(&self.ty(ty)?); + body.push_str(&self.ty(ty)); } body.push('}'); let name = self.make_type_name(); definitions.add_definition_line(format_args!("type {name} = {body}")); - Ok((name, Rc::new(RefCell::new(ns)))) + (name, Rc::new(RefCell::new(ns))) }) } - fn bundle_ty(&self, ty: Bundle) -> Result { - Ok(self.bundle_def(ty)?.0) + fn bundle_ty(&self, ty: Bundle) -> Ident { + self.bundle_def(ty).0 } - fn bundle_ns(&self, ty: Bundle) -> Result>, FirrtlError> { - Ok(self.bundle_def(ty)?.1) + fn bundle_ns(&self, ty: Bundle) -> Rc> { + self.bundle_def(ty).1 } - fn enum_def(&self, ty: Enum) -> Result<(Ident, Rc), FirrtlError> { + fn enum_def(&self, ty: Enum) -> (Ident, Rc) { self.enum_defs.get_or_make(ty, |&ty, definitions| { let mut variants = Namespace::default(); let mut body = String::new(); @@ -449,33 +410,33 @@ impl TypeState { write!(body, "{}", variants.get(name)).unwrap(); if let Some(ty) = ty { body.push_str(": "); - body.push_str(&self.ty(ty)?); + body.push_str(&self.ty(ty)); } } body.push_str("|}"); let name = self.make_type_name(); definitions.add_definition_line(format_args!("type {name} = {body}")); - Ok(( + ( name, Rc::new(EnumDef { variants: RefCell::new(variants), body, }), - )) + ) }) } - fn enum_ty(&self, ty: Enum) -> Result { - Ok(self.enum_def(ty)?.0) + fn enum_ty(&self, ty: Enum) -> Ident { + self.enum_def(ty).0 } - fn get_enum_variant(&mut self, ty: Enum, name: Interned) -> Result { - Ok(self.enum_def(ty)?.1.variants.borrow_mut().get(name)) + fn get_enum_variant(&mut self, ty: Enum, name: Interned) -> Ident { + self.enum_def(ty).1.variants.borrow_mut().get(name) } - fn ty(&self, ty: T) -> Result { - Ok(match ty.canonical() { - CanonicalType::Bundle(ty) => self.bundle_ty(ty)?.to_string(), - CanonicalType::Enum(ty) => self.enum_ty(ty)?.to_string(), + fn ty(&self, ty: T) -> String { + match ty.canonical() { + CanonicalType::Bundle(ty) => self.bundle_ty(ty).to_string(), + CanonicalType::Enum(ty) => self.enum_ty(ty).to_string(), CanonicalType::Array(ty) => { - let mut retval = self.ty(ty.element())?; + let mut retval = self.ty(ty.element()); write!(retval, "[{}]", ty.len()).unwrap(); retval } @@ -486,11 +447,7 @@ impl TypeState { CanonicalType::AsyncReset(AsyncReset {}) => "AsyncReset".into(), CanonicalType::SyncReset(SyncReset {}) => "UInt<1>".into(), CanonicalType::Reset(Reset {}) => "Reset".into(), - CanonicalType::PhantomConst(_) => "{}".into(), - CanonicalType::DynSimOnly(_) => { - return Err(FirrtlError::SimOnlyValuesAreNotPermitted); - } - }) + } } } @@ -526,7 +483,6 @@ trait WrappedFileBackendTrait { contents: String, ) -> Result<(), WrappedError>; fn simplify_enums_error(&mut self, error: SimplifyEnumsError) -> WrappedError; - fn firrtl_error(&mut self, error: FirrtlError) -> WrappedError; } struct WrappedFileBackend { @@ -589,11 +545,6 @@ impl WrappedFileBackendTrait for WrappedFileBackend { self.error = Err(error.into()); WrappedError } - - fn firrtl_error(&mut self, error: FirrtlError) -> WrappedError { - self.error = Err(self.file_backend.custom_error(Box::new(error))); - WrappedError - } } #[derive(Clone)] @@ -796,10 +747,7 @@ impl<'a> Exporter<'a> { } fn run(&mut self, top_module: Interned>) -> Result<(), WrappedError> { let mut contents = self.version(); - let circuit = self.circuit(top_module).map_err(|e| match e { - FirrtlOrWrappedError::FirrtlError(e) => self.file_backend.firrtl_error(e), - FirrtlOrWrappedError::WrappedError(e) => e, - })?; + let circuit = self.circuit(top_module)?; contents.push_str(&circuit); self.file_backend .write_top_fir_file(self.circuit_name.to_string(), contents) @@ -807,7 +755,7 @@ impl<'a> Exporter<'a> { fn version(&mut self) -> String { "FIRRTL version 3.2.0\n".to_string() } - fn circuit(&mut self, top_module: Interned>) -> Result { + fn circuit(&mut self, top_module: Interned>) -> Result { let indent = self.indent; self.add_module(top_module); let circuit_indent = indent.push(); @@ -837,9 +785,9 @@ impl<'a> Exporter<'a> { enum_ty: Enum, variant_name: Interned, variant_expr: Option, - ) -> Result { - let (_, enum_def) = self.type_state.enum_def(enum_ty)?; - let variant_ident = self.type_state.get_enum_variant(enum_ty, variant_name)?; + ) -> String { + let (_, enum_def) = self.type_state.enum_def(enum_ty); + let variant_ident = self.type_state.get_enum_variant(enum_ty, variant_name); let mut retval = enum_def.body.clone(); write!(retval, "({variant_ident}").unwrap(); if let Some(variant_expr) = variant_expr { @@ -847,7 +795,7 @@ impl<'a> Exporter<'a> { retval.push_str(&variant_expr); } retval.push(')'); - Ok(retval) + retval } fn uint_literal(&mut self, value: &UIntValue) -> String { format!( @@ -876,32 +824,32 @@ impl<'a> Exporter<'a> { to_ty: ToTy, definitions: &RcDefinitions, const_ty: bool, - ) -> Result { + ) -> String { let from_ty = Expr::ty(value); - let mut value = self.expr(Expr::canonical(value), definitions, const_ty)?; + let mut value = self.expr(Expr::canonical(value), definitions, const_ty); if from_ty.width().checked_add(1) == Some(to_ty.width()) && !FromTy::Signed::VALUE && ToTy::Signed::VALUE { - Ok(format!("cvt({value})")) + format!("cvt({value})") } else if from_ty.width() <= to_ty.width() { // must pad before changing type to preserve value modulo 2^to_ty.width if from_ty.width() < to_ty.width() { value = format!("pad({value}, {})", to_ty.width()); } if FromTy::Signed::VALUE == ToTy::Signed::VALUE { - Ok(value) + value } else if ToTy::Signed::VALUE { - Ok(format!("asSInt({value})")) + format!("asSInt({value})") } else { - Ok(format!("asUInt({value})")) + format!("asUInt({value})") } } else { value = format!("tail({value}, {})", from_ty.width() - to_ty.width()); if ToTy::Signed::VALUE { - Ok(format!("asSInt({value})")) + format!("asSInt({value})") } else { - Ok(value) + value } } } @@ -911,12 +859,12 @@ impl<'a> Exporter<'a> { value: Expr, definitions: &RcDefinitions, const_ty: bool, - ) -> Result { - let value = self.expr(Expr::canonical(value), definitions, const_ty)?; + ) -> String { + let value = self.expr(Expr::canonical(value), definitions, const_ty); if let Some(firrtl_cast_fn) = firrtl_cast_fn { - Ok(format!("{firrtl_cast_fn}({value})")) + format!("{firrtl_cast_fn}({value})") } else { - Ok(value) + value } } fn slice( @@ -925,17 +873,17 @@ impl<'a> Exporter<'a> { range: Range, definitions: &RcDefinitions, const_ty: bool, - ) -> Result { + ) -> String { let base_width = Expr::ty(base).width(); - let base = self.expr(Expr::canonical(base), definitions, const_ty)?; + let base = self.expr(Expr::canonical(base), definitions, const_ty); if range.is_empty() { - Ok(format!("tail({base}, {base_width})")) + format!("tail({base}, {base_width})") } else { - Ok(format!( + format!( "bits({base}, {hi}, {lo})", hi = range.end - 1, lo = range.start, - )) + ) } } fn array_literal_expr( @@ -943,29 +891,29 @@ impl<'a> Exporter<'a> { expr: ops::ArrayLiteral, definitions: &RcDefinitions, const_ty: bool, - ) -> Result { + ) -> String { let ident = self.module.ns.make_new("_array_literal_expr"); - let ty_str = self.type_state.ty(expr.ty())?; + let ty_str = self.type_state.ty(expr.ty()); let const_ = if const_ty { "const " } else { "" }; definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_str}")); for (index, element) in expr.element_values().into_iter().enumerate() { - let element = self.expr(Expr::canonical(element), definitions, const_ty)?; + let element = self.expr(Expr::canonical(element), definitions, const_ty); definitions.add_definition_line(format_args!("connect {ident}[{index}], {element}")); } if expr.element_values().is_empty() { definitions.add_definition_line(format_args!("invalidate {ident}")); } - Ok(ident.to_string()) + ident.to_string() } fn bundle_literal_expr( &mut self, expr: ops::BundleLiteral, definitions: &RcDefinitions, const_ty: bool, - ) -> Result { + ) -> String { let ident = self.module.ns.make_new("_bundle_literal_expr"); let ty = expr.ty(); - let (ty_ident, bundle_ns) = self.type_state.bundle_def(ty)?; + let (ty_ident, bundle_ns) = self.type_state.bundle_def(ty); let const_ = if const_ty { "const " } else { "" }; definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_ident}")); for ( @@ -977,43 +925,39 @@ impl<'a> Exporter<'a> { }, ) in expr.field_values().into_iter().zip(ty.fields()) { - debug_assert!( - !flipped, - "can't have bundle literal with flipped field -- this should have been caught in BundleLiteral::new_unchecked" - ); + debug_assert!(!flipped, "can't have bundle literal with flipped field -- this should have been caught in BundleLiteral::new_unchecked"); let name = bundle_ns.borrow_mut().get(name); - let field_value = self.expr(Expr::canonical(field_value), definitions, const_ty)?; + let field_value = self.expr(Expr::canonical(field_value), definitions, const_ty); definitions.add_definition_line(format_args!("connect {ident}.{name}, {field_value}")); } if ty.fields().is_empty() { definitions.add_definition_line(format_args!("invalidate {ident}")); } - Ok(ident.to_string()) + ident.to_string() } fn uninit_expr( &mut self, expr: ops::Uninit, definitions: &RcDefinitions, const_ty: bool, - ) -> Result { + ) -> String { let ident = self.module.ns.make_new("_uninit_expr"); let ty = expr.ty(); - let ty_ident = self.type_state.ty(ty)?; + let ty_ident = self.type_state.ty(ty); let const_ = if const_ty { "const " } else { "" }; definitions.add_definition_line(format_args!("wire {ident}: {const_}{ty_ident}")); definitions.add_definition_line(format_args!("invalidate {ident}")); - Ok(ident.to_string()) + ident.to_string() } fn enum_literal_expr( &mut self, expr: ops::EnumLiteral, definitions: &RcDefinitions, const_ty: bool, - ) -> Result { + ) -> String { let variant_expr = expr .variant_value() - .map(|variant_value| self.expr(variant_value, definitions, const_ty)) - .transpose()?; + .map(|variant_value| self.expr(variant_value, definitions, const_ty)); self.enum_expr_impl(expr.ty(), expr.variant_name(), variant_expr) } fn expr_cast_bundle_to_bits( @@ -1022,12 +966,12 @@ impl<'a> Exporter<'a> { ty: Bundle, definitions: &RcDefinitions, extra_indent: Indent<'_>, - ) -> Result { + ) -> String { if ty.fields().is_empty() { - return Ok("UInt<0>(0)".into()); + return "UInt<0>(0)".into(); } if let [field] = *ty.fields() { - let field_ident = self.type_state.get_bundle_field(ty, field.name)?; + let field_ident = self.type_state.get_bundle_field(ty, field.name); return self.expr_cast_to_bits( format!("{value_str}.{field_ident}"), field.ty, @@ -1046,23 +990,23 @@ impl<'a> Exporter<'a> { ty: UInt[field_ty.bit_width()].canonical(), }, ))); - let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty)?; + let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty); let ident = self.module.ns.make_new("_cast_bundle_to_bits_expr"); definitions.add_definition_line(format_args!( "{extra_indent}wire {ident}: {flattened_ty_ident}" )); let mut cat_expr = None; for field in ty.fields() { - let field_ident = self.type_state.get_bundle_field(ty, field.name)?; + let field_ident = self.type_state.get_bundle_field(ty, field.name); let flattened_field_ident = self .type_state - .get_bundle_field(flattened_bundle_ty, field.name)?; + .get_bundle_field(flattened_bundle_ty, field.name); let field_bits = self.expr_cast_to_bits( format!("{value_str}.{field_ident}"), field.ty, definitions, extra_indent, - )?; + ); definitions.add_definition_line(format_args!( "{extra_indent}connect {ident}.{flattened_field_ident}, {field_bits}" )); @@ -1079,7 +1023,7 @@ impl<'a> Exporter<'a> { )); let cat_expr = cat_expr.expect("bundle already checked to have fields"); definitions.add_definition_line(format_args!("{extra_indent}connect {retval}, {cat_expr}")); - Ok(retval.to_string()) + retval.to_string() } fn expr_cast_enum_to_bits( &mut self, @@ -1087,9 +1031,9 @@ impl<'a> Exporter<'a> { ty: Enum, definitions: &RcDefinitions, extra_indent: Indent<'_>, - ) -> Result { + ) -> String { if ty.variants().is_empty() { - return Ok("UInt<0>(0)".into()); + return "UInt<0>(0)".into(); } let retval = self.module.ns.make_new("_cast_enum_to_bits_expr"); definitions.add_definition_line(format_args!( @@ -1106,7 +1050,7 @@ impl<'a> Exporter<'a> { .make_new(&format!("_cast_enum_to_bits_expr_{}", variant.name)); definitions.add_definition_line(format_args!( "{extra_indent}{}({variant_value}):", - self.type_state.get_enum_variant(ty, variant.name)?, + self.type_state.get_enum_variant(ty, variant.name), )); let _match_arm_indent = extra_indent.push(); let variant_bits = self.expr_cast_to_bits( @@ -1114,7 +1058,7 @@ impl<'a> Exporter<'a> { variant_ty, definitions, extra_indent, - )?; + ); definitions.add_definition_line(format_args!( "{extra_indent}connect {retval}, pad(cat({variant_bits}, UInt<{}>({variant_index})), {})", ty.discriminant_bit_width(), @@ -1123,7 +1067,7 @@ impl<'a> Exporter<'a> { } else { definitions.add_definition_line(format_args!( "{extra_indent}{}:", - self.type_state.get_enum_variant(ty, variant.name)?, + self.type_state.get_enum_variant(ty, variant.name), )); let _match_arm_indent = extra_indent.push(); definitions.add_definition_line(format_args!( @@ -1132,7 +1076,7 @@ impl<'a> Exporter<'a> { )); } } - Ok(retval.to_string()) + retval.to_string() } fn expr_cast_array_to_bits( &mut self, @@ -1140,9 +1084,9 @@ impl<'a> Exporter<'a> { ty: Array, definitions: &RcDefinitions, extra_indent: Indent<'_>, - ) -> Result { + ) -> String { if ty.is_empty() { - return Ok("UInt<0>(0)".into()); + return "UInt<0>(0)".into(); } if ty.len() == 1 { return self.expr_cast_to_bits( @@ -1165,7 +1109,7 @@ impl<'a> Exporter<'a> { ty.element(), definitions, extra_indent, - )?; + ); definitions.add_definition_line(format_args!( "{extra_indent}connect {ident}[{index}], {element_bits}" )); @@ -1182,7 +1126,7 @@ impl<'a> Exporter<'a> { )); let cat_expr = cat_expr.expect("array already checked to have elements"); definitions.add_definition_line(format_args!("{extra_indent}connect {retval}, {cat_expr}")); - Ok(retval.to_string()) + retval.to_string() } fn expr_cast_to_bits( &mut self, @@ -1190,7 +1134,7 @@ impl<'a> Exporter<'a> { ty: CanonicalType, definitions: &RcDefinitions, extra_indent: Indent<'_>, - ) -> Result { + ) -> String { match ty { CanonicalType::Bundle(ty) => { self.expr_cast_bundle_to_bits(value_str, ty, definitions, extra_indent) @@ -1202,14 +1146,12 @@ impl<'a> Exporter<'a> { self.expr_cast_array_to_bits(value_str, ty, definitions, extra_indent) } CanonicalType::UInt(_) | CanonicalType::SyncReset(_) | CanonicalType::Bool(_) => { - Ok(value_str) + value_str } CanonicalType::SInt(_) | CanonicalType::Clock(_) | CanonicalType::AsyncReset(_) - | CanonicalType::Reset(_) => Ok(format!("asUInt({value_str})")), - CanonicalType::PhantomConst(_) => Ok("UInt<0>(0)".into()), - CanonicalType::DynSimOnly(_) => Err(FirrtlError::SimOnlyValuesAreNotPermitted.into()), + | CanonicalType::Reset(_) => format!("asUInt({value_str})"), } } fn expr_cast_bits_to_bundle( @@ -1218,13 +1160,13 @@ impl<'a> Exporter<'a> { ty: Bundle, definitions: &RcDefinitions, extra_indent: Indent<'_>, - ) -> Result { - let (ty_ident, _) = self.type_state.bundle_def(ty)?; + ) -> String { + let (ty_ident, _) = self.type_state.bundle_def(ty); let retval = self.module.ns.make_new("_cast_bits_to_bundle_expr"); definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {ty_ident}")); if ty.fields().is_empty() { definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}")); - return Ok(retval.to_string()); + return retval.to_string(); } let flattened_bundle_ty = Bundle::new(Interned::from_iter(ty.fields().iter().map( |&BundleField { @@ -1237,7 +1179,7 @@ impl<'a> Exporter<'a> { ty: UInt[field_ty.bit_width()].canonical(), }, ))); - let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty)?; + let (flattened_ty_ident, _) = self.type_state.bundle_def(flattened_bundle_ty); let flattened_ident = self .module .ns @@ -1245,18 +1187,11 @@ impl<'a> Exporter<'a> { definitions.add_definition_line(format_args!( "{extra_indent}wire {flattened_ident}: {flattened_ty_ident}" )); - for ( - field, - OpaqueSimValueSize { - bit_width: field_offset, - sim_only_values_len: _, - }, - ) in ty.fields().into_iter().zip(ty.field_offsets()) - { + for (field, field_offset) in ty.fields().into_iter().zip(ty.field_offsets()) { let flattened_field_ident = self .type_state - .get_bundle_field(flattened_bundle_ty, field.name)?; - let field_ident = self.type_state.get_bundle_field(ty, field.name)?; + .get_bundle_field(flattened_bundle_ty, field.name); + let field_ident = self.type_state.get_bundle_field(ty, field.name); if let Some(field_bit_width_minus_one) = field.ty.bit_width().checked_sub(1usize) { definitions.add_definition_line(format_args!( "{extra_indent}connect {flattened_ident}.{flattened_field_ident}, bits({value_str}, {}, {field_offset})", @@ -1272,12 +1207,12 @@ impl<'a> Exporter<'a> { field.ty, definitions, extra_indent, - )?; + ); definitions.add_definition_line(format_args!( "{extra_indent}connect {retval}.{field_ident}, {field_value}" )); } - Ok(retval.to_string()) + retval.to_string() } fn expr_cast_bits_to_enum( &mut self, @@ -1285,19 +1220,19 @@ impl<'a> Exporter<'a> { ty: Enum, definitions: &RcDefinitions, extra_indent: Indent<'_>, - ) -> Result { - let (ty_ident, enum_def) = self.type_state.enum_def(ty)?; + ) -> String { + let (ty_ident, enum_def) = self.type_state.enum_def(ty); let retval = self.module.ns.make_new("_cast_bits_to_enum_expr"); definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {ty_ident}")); if ty.variants().is_empty() { definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}")); - return Ok(retval.to_string()); + return retval.to_string(); } if let [variant] = *ty.variants() { - let enum_variant = self.type_state.get_enum_variant(ty, variant.name)?; + let enum_variant = self.type_state.get_enum_variant(ty, variant.name); if let Some(variant_ty) = variant.ty { let variant_value = - self.expr_cast_bits_to(value_str, variant_ty, definitions, extra_indent)?; + self.expr_cast_bits_to(value_str, variant_ty, definitions, extra_indent); definitions.add_definition_line(format_args!( "{extra_indent}connect {retval}, {}({enum_variant}, {variant_value})", enum_def.body @@ -1308,7 +1243,7 @@ impl<'a> Exporter<'a> { enum_def.body )); } - return Ok(retval.to_string()); + return retval.to_string(); } let discriminant_bit_width = ty.discriminant_bit_width(); let body_bit_width = ty.type_properties().bit_width - discriminant_bit_width; @@ -1325,9 +1260,7 @@ impl<'a> Exporter<'a> { "UInt<0>(0)".into() }; for (variant_index, variant) in ty.variants().into_iter().enumerate() { - let when_cond = format!( - "eq(UInt<{discriminant_bit_width}>({variant_index}), tail({value_str}, {body_bit_width}))" - ); + let when_cond = format!("eq(UInt<{discriminant_bit_width}>({variant_index}), tail({value_str}, {body_bit_width}))"); if variant_index == ty.variants().len() - 1 { definitions.add_definition_line(format_args!("{extra_indent}else:")); } else if variant_index == 0 { @@ -1337,14 +1270,14 @@ impl<'a> Exporter<'a> { .add_definition_line(format_args!("{extra_indent}else when {when_cond}:")); } let when_pushed_indent = extra_indent.push(); - let enum_variant = self.type_state.get_enum_variant(ty, variant.name)?; + let enum_variant = self.type_state.get_enum_variant(ty, variant.name); if let Some(variant_ty) = variant.ty { let variant_value = self.expr_cast_bits_to( body_value.clone(), variant_ty, definitions, extra_indent, - )?; + ); definitions.add_definition_line(format_args!( "{extra_indent}connect {retval}, {}({enum_variant}, {variant_value})", enum_def.body @@ -1357,7 +1290,7 @@ impl<'a> Exporter<'a> { } drop(when_pushed_indent); } - Ok(retval.to_string()) + retval.to_string() } fn expr_cast_bits_to_array( &mut self, @@ -1365,14 +1298,14 @@ impl<'a> Exporter<'a> { ty: Array, definitions: &RcDefinitions, extra_indent: Indent<'_>, - ) -> Result { + ) -> String { let retval = self.module.ns.make_new("_cast_bits_to_array_expr"); - let array_ty = self.type_state.ty(ty)?; + let array_ty = self.type_state.ty(ty); definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {array_ty}")); let element_bit_width = ty.element().bit_width(); if ty.is_empty() || element_bit_width == 0 { definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}")); - return Ok(retval.to_string()); + return retval.to_string(); } let flattened_ident = self .module @@ -1393,12 +1326,12 @@ impl<'a> Exporter<'a> { ty.element(), definitions, extra_indent, - )?; + ); definitions.add_definition_line(format_args!( "{extra_indent}connect {retval}[{index}], {element_value}" )); } - Ok(retval.to_string()) + retval.to_string() } fn expr_cast_bits_to( &mut self, @@ -1406,7 +1339,7 @@ impl<'a> Exporter<'a> { ty: CanonicalType, definitions: &RcDefinitions, extra_indent: Indent<'_>, - ) -> Result { + ) -> String { match ty { CanonicalType::Bundle(ty) => { self.expr_cast_bits_to_bundle(value_str, ty, definitions, extra_indent) @@ -1417,20 +1350,13 @@ impl<'a> Exporter<'a> { CanonicalType::Array(ty) => { self.expr_cast_bits_to_array(value_str, ty, definitions, extra_indent) } - CanonicalType::UInt(_) => Ok(value_str), - CanonicalType::SInt(_) => Ok(format!("asSInt({value_str})")), - CanonicalType::Bool(_) => Ok(value_str), - CanonicalType::Clock(_) => Ok(format!("asClock({value_str})")), - CanonicalType::AsyncReset(_) => Ok(format!("asAsyncReset({value_str})")), - CanonicalType::SyncReset(_) => Ok(value_str), + CanonicalType::UInt(_) => value_str, + CanonicalType::SInt(_) => format!("asSInt({value_str})"), + CanonicalType::Bool(_) => value_str, + CanonicalType::Clock(_) => format!("asClock({value_str})"), + CanonicalType::AsyncReset(_) => format!("asAsyncReset({value_str})"), + CanonicalType::SyncReset(_) => value_str, CanonicalType::Reset(_) => unreachable!("Reset is not bit castable to"), - CanonicalType::PhantomConst(_) => { - let retval = self.module.ns.make_new("_cast_bits_to_phantom_const_expr"); - definitions.add_definition_line(format_args!("{extra_indent}wire {retval}: {{}}")); - definitions.add_definition_line(format_args!("{extra_indent}invalidate {retval}")); - return Ok(retval.to_string()); - } - CanonicalType::DynSimOnly(_) => Err(FirrtlError::SimOnlyValuesAreNotPermitted.into()), } } fn expr_unary( @@ -1439,11 +1365,11 @@ impl<'a> Exporter<'a> { arg: Expr, definitions: &RcDefinitions, const_ty: bool, - ) -> Result { - Ok(format!( + ) -> String { + format!( "{func}({arg})", - arg = self.expr(Expr::canonical(arg), definitions, const_ty)?, - )) + arg = self.expr(Expr::canonical(arg), definitions, const_ty) + ) } fn expr_binary( &mut self, @@ -1452,28 +1378,23 @@ impl<'a> Exporter<'a> { rhs: Expr, definitions: &RcDefinitions, const_ty: bool, - ) -> Result { - Ok(format!( + ) -> String { + format!( "{func}({lhs}, {rhs})", - lhs = self.expr(Expr::canonical(lhs), definitions, const_ty)?, - rhs = self.expr(Expr::canonical(rhs), definitions, const_ty)?, - )) + lhs = self.expr(Expr::canonical(lhs), definitions, const_ty), + rhs = self.expr(Expr::canonical(rhs), definitions, const_ty) + ) } fn expr( &mut self, expr: Expr, definitions: &RcDefinitions, const_ty: bool, - ) -> Result { + ) -> String { match *Expr::expr_enum(expr) { - ExprEnum::UIntLiteral(literal) => Ok(self.uint_literal(&literal)), - ExprEnum::SIntLiteral(literal) => Ok(self.sint_literal(&literal)), - ExprEnum::BoolLiteral(literal) => Ok(self.bool_literal(literal)), - ExprEnum::PhantomConst(ty) => self.expr( - UInt[0].zero().cast_bits_to(ty.canonical()), - definitions, - const_ty, - ), + ExprEnum::UIntLiteral(literal) => self.uint_literal(&literal), + ExprEnum::SIntLiteral(literal) => self.sint_literal(&literal), + ExprEnum::BoolLiteral(literal) => self.bool_literal(literal), ExprEnum::ArrayLiteral(array_literal) => { self.array_literal_expr(array_literal, definitions, const_ty) } @@ -1557,26 +1478,34 @@ impl<'a> Exporter<'a> { ExprEnum::DynShrS(expr) => { self.expr_binary("dshr", expr.lhs(), expr.rhs(), definitions, const_ty) } - ExprEnum::FixedShlU(expr) => Ok(format!( - "shl({lhs}, {rhs})", - lhs = self.expr(Expr::canonical(expr.lhs()), definitions, const_ty)?, - rhs = expr.rhs(), - )), - ExprEnum::FixedShlS(expr) => Ok(format!( - "shl({lhs}, {rhs})", - lhs = self.expr(Expr::canonical(expr.lhs()), definitions, const_ty)?, - rhs = expr.rhs(), - )), - ExprEnum::FixedShrU(expr) => Ok(format!( - "shr({lhs}, {rhs})", - lhs = self.expr(Expr::canonical(expr.lhs()), definitions, const_ty)?, - rhs = expr.rhs(), - )), - ExprEnum::FixedShrS(expr) => Ok(format!( - "shr({lhs}, {rhs})", - lhs = self.expr(Expr::canonical(expr.lhs()), definitions, const_ty)?, - rhs = expr.rhs(), - )), + ExprEnum::FixedShlU(expr) => { + format!( + "shl({lhs}, {rhs})", + lhs = self.expr(Expr::canonical(expr.lhs()), definitions, const_ty), + rhs = expr.rhs(), + ) + } + ExprEnum::FixedShlS(expr) => { + format!( + "shl({lhs}, {rhs})", + lhs = self.expr(Expr::canonical(expr.lhs()), definitions, const_ty), + rhs = expr.rhs(), + ) + } + ExprEnum::FixedShrU(expr) => { + format!( + "shr({lhs}, {rhs})", + lhs = self.expr(Expr::canonical(expr.lhs()), definitions, const_ty), + rhs = expr.rhs(), + ) + } + ExprEnum::FixedShrS(expr) => { + format!( + "shr({lhs}, {rhs})", + lhs = self.expr(Expr::canonical(expr.lhs()), definitions, const_ty), + rhs = expr.rhs(), + ) + } ExprEnum::CmpLtU(expr) => { self.expr_binary("lt", expr.lhs(), expr.rhs(), definitions, const_ty) } @@ -1650,7 +1579,7 @@ impl<'a> Exporter<'a> { self.slice(expr.base(), expr.range(), definitions, const_ty) } ExprEnum::CastToBits(expr) => { - let value_str = self.expr(expr.arg(), definitions, const_ty)?; + let value_str = self.expr(expr.arg(), definitions, const_ty); self.expr_cast_to_bits( value_str, Expr::ty(expr.arg()), @@ -1662,7 +1591,7 @@ impl<'a> Exporter<'a> { ) } ExprEnum::CastBitsTo(expr) => { - let value_str = self.expr(Expr::canonical(expr.arg()), definitions, const_ty)?; + let value_str = self.expr(Expr::canonical(expr.arg()), definitions, const_ty); self.expr_cast_bits_to( value_str, expr.ty(), @@ -1773,57 +1702,56 @@ impl<'a> Exporter<'a> { self.expr_unary("xorr", expr.arg(), definitions, const_ty) } ExprEnum::FieldAccess(expr) => { - let mut out = self.expr(Expr::canonical(expr.base()), definitions, const_ty)?; + let mut out = self.expr(Expr::canonical(expr.base()), definitions, const_ty); let name = self .type_state - .get_bundle_field(Expr::ty(expr.base()), expr.field_name())?; + .get_bundle_field(Expr::ty(expr.base()), expr.field_name()); write!(out, ".{name}").unwrap(); - Ok(out) + out } - ExprEnum::VariantAccess(variant_access) => Ok(self + ExprEnum::VariantAccess(variant_access) => self .module .match_arm_values .get(&variant_access) .expect("VariantAccess must be in its corresponding match arm") - .to_string()), + .to_string(), ExprEnum::ArrayIndex(expr) => { - let mut out = self.expr(Expr::canonical(expr.base()), definitions, const_ty)?; + let mut out = self.expr(Expr::canonical(expr.base()), definitions, const_ty); write!(out, "[{}]", expr.element_index()).unwrap(); - Ok(out) + out } ExprEnum::DynArrayIndex(expr) => { - let mut out = self.expr(Expr::canonical(expr.base()), definitions, const_ty)?; - let index = - self.expr(Expr::canonical(expr.element_index()), definitions, const_ty)?; + let mut out = self.expr(Expr::canonical(expr.base()), definitions, const_ty); + let index = self.expr(Expr::canonical(expr.element_index()), definitions, const_ty); write!(out, "[{index}]").unwrap(); - Ok(out) + out } - ExprEnum::ModuleIO(expr) => Ok(self.module.ns.get(expr.name_id()).to_string()), + ExprEnum::ModuleIO(expr) => self.module.ns.get(expr.name_id()).to_string(), ExprEnum::Instance(expr) => { assert!(!const_ty, "not a constant"); - Ok(self.module.ns.get(expr.scoped_name().1).to_string()) + self.module.ns.get(expr.scoped_name().1).to_string() } ExprEnum::Wire(expr) => { assert!(!const_ty, "not a constant"); - Ok(self.module.ns.get(expr.scoped_name().1).to_string()) + self.module.ns.get(expr.scoped_name().1).to_string() } ExprEnum::Reg(expr) => { assert!(!const_ty, "not a constant"); - Ok(self.module.ns.get(expr.scoped_name().1).to_string()) + self.module.ns.get(expr.scoped_name().1).to_string() } ExprEnum::RegSync(expr) => { assert!(!const_ty, "not a constant"); - Ok(self.module.ns.get(expr.scoped_name().1).to_string()) + self.module.ns.get(expr.scoped_name().1).to_string() } ExprEnum::RegAsync(expr) => { assert!(!const_ty, "not a constant"); - Ok(self.module.ns.get(expr.scoped_name().1).to_string()) + self.module.ns.get(expr.scoped_name().1).to_string() } ExprEnum::MemPort(expr) => { assert!(!const_ty, "not a constant"); let mem_name = self.module.ns.get(expr.mem_name().1); let port_name = Ident::from(expr.port_name()); - Ok(format!("{mem_name}.{port_name}")) + format!("{mem_name}.{port_name}") } } } @@ -1833,7 +1761,7 @@ impl<'a> Exporter<'a> { memory_name: Ident, array_type: Array, initial_value: Interned, - ) -> Result<()> { + ) -> Result<(), WrappedError> { assert_eq!( initial_value.len(), array_type.type_properties().bit_width, @@ -1883,11 +1811,7 @@ impl<'a> Exporter<'a> { } fn annotation(&mut self, path: AnnotationTargetPath, annotation: &Annotation) { let data = match annotation { - Annotation::DontTouch(DontTouchAnnotation {}) => { - // TODO: error if the annotated thing was renamed because of a naming conflict, - // unless Target::base() is one of the ports of the top-level module since that's handled by ScalarizedModuleABI - AnnotationData::DontTouch - } + Annotation::DontTouch(DontTouchAnnotation {}) => AnnotationData::DontTouch, Annotation::SVAttribute(SVAttributeAnnotation { text }) => { AnnotationData::AttributeAnnotation { description: *text } } @@ -1910,9 +1834,6 @@ impl<'a> Exporter<'a> { class: str::to_string(class), additional_fields: (*additional_fields).into(), }, - Annotation::Xilinx(XilinxAnnotation::XdcLocation(_)) - | Annotation::Xilinx(XilinxAnnotation::XdcIOStandard(_)) - | Annotation::Xilinx(XilinxAnnotation::XdcCreateClock(_)) => return, }; self.annotations.push(FirrtlAnnotation { data, @@ -1922,7 +1843,7 @@ impl<'a> Exporter<'a> { }, }) } - fn annotation_target_ref(&mut self, target: Interned) -> Result { + fn annotation_target_ref(&mut self, target: Interned) -> AnnotationTargetRef { match *target { Target::Base(base) => { let mut segments = vec![]; @@ -1940,17 +1861,17 @@ impl<'a> Exporter<'a> { TargetBase::Wire(v) => self.module.ns.get(v.name_id()), TargetBase::Instance(v) => self.module.ns.get(v.name_id()), }; - Ok(AnnotationTargetRef { base, segments }) + AnnotationTargetRef { base, segments } } Target::Child(child) => { - let mut retval = self.annotation_target_ref(child.parent())?; + let mut retval = self.annotation_target_ref(child.parent()); match *child.path_element() { TargetPathElement::BundleField(TargetPathBundleField { name }) => { retval.segments.push(AnnotationTargetRefSegment::Field { name: self.type_state.get_bundle_field( Bundle::from_canonical(child.parent().canonical_ty()), name, - )?, + ), }) } TargetPathElement::ArrayElement(TargetPathArrayElement { index, .. }) => retval @@ -1958,7 +1879,7 @@ impl<'a> Exporter<'a> { .push(AnnotationTargetRefSegment::Index { index }), TargetPathElement::DynArrayElement(_) => unreachable!(), } - Ok(retval) + retval } } } @@ -1967,9 +1888,9 @@ impl<'a> Exporter<'a> { base_module: Ident, submodules: Vec, annotations: &[crate::annotations::TargetedAnnotation], - ) -> Result<()> { + ) { for annotation in annotations { - let target_ref = Some(self.annotation_target_ref(annotation.target())?); + let target_ref = Some(self.annotation_target_ref(annotation.target())); self.annotation( AnnotationTargetPath { base_module, @@ -1979,9 +1900,8 @@ impl<'a> Exporter<'a> { annotation.annotation(), ); } - Ok(()) } - fn write_mem(&mut self, module_name: Ident, memory: Mem) -> Result { + fn write_mem(&mut self, module_name: Ident, memory: Mem) -> Result { let indent = self.indent; let name_id = memory.scoped_name().1; let source_location = memory.source_location(); @@ -2005,11 +1925,11 @@ impl<'a> Exporter<'a> { annotation, ); } - self.targeted_annotations(module_name, vec![], &memory.port_annotations())?; + self.targeted_annotations(module_name, vec![], &memory.port_annotations()); if let Some(initial_value) = initial_value { self.write_mem_init(module_name, name, array_type, initial_value)?; } - let data_type = self.type_state.ty(array_type.element())?; + let data_type = self.type_state.ty(array_type.element()); let mut body = String::new(); writeln!( body, @@ -2052,16 +1972,16 @@ impl<'a> Exporter<'a> { module_name: Ident, definitions: &RcDefinitions, body: &mut String, - ) -> Result<()> { + ) { let StmtReg { annotations, reg } = stmt_reg; let indent = self.indent; - self.targeted_annotations(module_name, vec![], &annotations)?; + self.targeted_annotations(module_name, vec![], &annotations); let name = self.module.ns.get(reg.name_id()); - let ty = self.type_state.ty(reg.ty())?; - let clk = self.expr(Expr::canonical(reg.clock_domain().clk), definitions, false)?; + let ty = self.type_state.ty(reg.ty()); + let clk = self.expr(Expr::canonical(reg.clock_domain().clk), definitions, false); if let Some(init) = reg.init() { - let rst = self.expr(Expr::canonical(reg.clock_domain().rst), definitions, false)?; - let init = self.expr(init, definitions, false)?; + let rst = self.expr(Expr::canonical(reg.clock_domain().rst), definitions, false); + let init = self.expr(init, definitions, false); writeln!( body, "{indent}regreset {name}: {ty}, {clk}, {rst}, {init}{}", @@ -2076,7 +1996,6 @@ impl<'a> Exporter<'a> { ) .unwrap(); } - Ok(()) } fn block( &mut self, @@ -2084,7 +2003,7 @@ impl<'a> Exporter<'a> { block: Block, _block_indent: &PushIndent<'_>, definitions: Option, - ) -> Result { + ) -> Result { let indent = self.indent; let definitions = definitions.unwrap_or_default(); let mut body = String::new(); @@ -2110,8 +2029,8 @@ impl<'a> Exporter<'a> { ) .unwrap(); } - let lhs = self.expr(lhs, &definitions, false)?; - let rhs = self.expr(rhs, &definitions, false)?; + let lhs = self.expr(lhs, &definitions, false); + let rhs = self.expr(rhs, &definitions, false); writeln!( body, "{indent}connect {lhs}, {rhs}{}", @@ -2127,9 +2046,9 @@ impl<'a> Exporter<'a> { text, source_location, }) => { - let clk = self.expr(Expr::canonical(clk), &definitions, false)?; - let pred = self.expr(Expr::canonical(pred), &definitions, false)?; - let en = self.expr(Expr::canonical(en), &definitions, false)?; + let clk = self.expr(Expr::canonical(clk), &definitions, false); + let pred = self.expr(Expr::canonical(pred), &definitions, false); + let en = self.expr(Expr::canonical(en), &definitions, false); let kind = match kind { FormalKind::Assert => "assert", FormalKind::Assume => "assume", @@ -2154,7 +2073,7 @@ impl<'a> Exporter<'a> { let mut when = "when"; let mut pushed_indent; loop { - let cond_str = self.expr(Expr::canonical(cond), &definitions, false)?; + let cond_str = self.expr(Expr::canonical(cond), &definitions, false); writeln!( body, "{indent}{when} {cond_str}:{}", @@ -2196,7 +2115,7 @@ impl<'a> Exporter<'a> { writeln!( body, "{indent}match {}:{}", - self.expr(Expr::canonical(expr), &definitions, false)?, + self.expr(Expr::canonical(expr), &definitions, false), FileInfo::new(source_location), ) .unwrap(); @@ -2208,7 +2127,7 @@ impl<'a> Exporter<'a> { write!( body, "{indent}{}", - self.type_state.get_enum_variant(enum_ty, variant.name)?, + self.type_state.get_enum_variant(enum_ty, variant.name), ) .unwrap(); let variant_access = if variant.ty.is_some() { @@ -2238,9 +2157,9 @@ impl<'a> Exporter<'a> { drop(match_arms_indent); } Stmt::Declaration(StmtDeclaration::Wire(StmtWire { annotations, wire })) => { - self.targeted_annotations(module_name, vec![], &annotations)?; + self.targeted_annotations(module_name, vec![], &annotations); let name = self.module.ns.get(wire.name_id()); - let ty = self.type_state.ty(wire.ty())?; + let ty = self.type_state.ty(wire.ty()); writeln!( body, "{indent}wire {name}: {ty}{}", @@ -2249,19 +2168,19 @@ impl<'a> Exporter<'a> { .unwrap(); } Stmt::Declaration(StmtDeclaration::Reg(stmt_reg)) => { - self.stmt_reg(stmt_reg, module_name, &definitions, &mut body)?; + self.stmt_reg(stmt_reg, module_name, &definitions, &mut body); } Stmt::Declaration(StmtDeclaration::RegSync(stmt_reg)) => { - self.stmt_reg(stmt_reg, module_name, &definitions, &mut body)?; + self.stmt_reg(stmt_reg, module_name, &definitions, &mut body); } Stmt::Declaration(StmtDeclaration::RegAsync(stmt_reg)) => { - self.stmt_reg(stmt_reg, module_name, &definitions, &mut body)?; + self.stmt_reg(stmt_reg, module_name, &definitions, &mut body); } Stmt::Declaration(StmtDeclaration::Instance(StmtInstance { annotations, instance, })) => { - self.targeted_annotations(module_name, vec![], &annotations)?; + self.targeted_annotations(module_name, vec![], &annotations); let name = self.module.ns.get(instance.name_id()); let instantiated = instance.instantiated(); self.add_module(instantiated); @@ -2280,7 +2199,7 @@ impl<'a> Exporter<'a> { } Ok(out) } - fn module(&mut self, module: Interned>) -> Result { + fn module(&mut self, module: Interned>) -> Result { self.module = ModuleState::default(); let indent = self.indent; let module_name = self.global_ns.get(module.name_id()); @@ -2301,9 +2220,9 @@ impl<'a> Exporter<'a> { module_io, } in module.module_io().iter() { - self.targeted_annotations(module_name, vec![], annotations)?; + self.targeted_annotations(module_name, vec![], annotations); let name = self.module.ns.get(module_io.name_id()); - let ty = self.type_state.ty(module_io.ty())?; + let ty = self.type_state.ty(module_io.ty()); if module_io.is_input() { writeln!( body, @@ -2326,7 +2245,6 @@ impl<'a> Exporter<'a> { ModuleBody::Extern(ExternModuleBody { verilog_name, parameters, - simulation: _, }) => { let verilog_name = Ident(verilog_name); writeln!(body, "{indent}defname = {verilog_name}").unwrap(); @@ -2378,7 +2296,6 @@ pub trait FileBackendTrait { type Error: From; type Path: AsRef + fmt::Debug + ?Sized; type PathBuf: AsRef + fmt::Debug; - fn custom_error(&self, error: Box) -> Self::Error; fn path_to_string(&mut self, path: &Self::Path) -> Result; fn write_mem_init_file( &mut self, @@ -2398,10 +2315,6 @@ impl FileBackendTrait for Box { type Path = T::Path; type PathBuf = T::PathBuf; - fn custom_error(&self, error: Box) -> Self::Error { - (**self).custom_error(error) - } - fn path_to_string(&mut self, path: &Self::Path) -> Result { (**self).path_to_string(path) } @@ -2429,10 +2342,6 @@ impl FileBackendTrait for &'_ mut T { type Path = T::Path; type PathBuf = T::PathBuf; - fn custom_error(&self, error: Box) -> Self::Error { - (**self).custom_error(error) - } - fn path_to_string(&mut self, path: &Self::Path) -> Result { (**self).path_to_string(path) } @@ -2460,7 +2369,7 @@ impl FileBackendTrait for &'_ mut T { pub struct FileBackend { pub dir_path: PathBuf, pub circuit_name: Option, - pub top_fir_file_stem: Option, + pub top_fir_file_stem: Option, } impl FileBackend { @@ -2478,10 +2387,6 @@ impl FileBackendTrait for FileBackend { type Path = Path; type PathBuf = PathBuf; - fn custom_error(&self, error: Box) -> Self::Error { - io::Error::new(io::ErrorKind::Other, error) - } - fn path_to_string(&mut self, path: &Self::Path) -> Result { path.to_str() .map(String::from) @@ -2509,7 +2414,7 @@ impl FileBackendTrait for FileBackend { ) -> Result<(), Self::Error> { let top_fir_file_stem = self .top_fir_file_stem - .get_or_insert_with(|| circuit_name.clone().into()); + .get_or_insert_with(|| circuit_name.clone()); self.circuit_name = Some(circuit_name); let mut path = self.dir_path.join(top_fir_file_stem); if let Some(parent) = path.parent().filter(|v| !v.as_os_str().is_empty()) { @@ -2648,10 +2553,6 @@ impl FileBackendTrait for TestBackend { type Path = str; type PathBuf = String; - fn custom_error(&self, error: Box) -> Self::Error { - TestBackendError(error.to_string()) - } - fn path_to_string(&mut self, path: &Self::Path) -> Result { self.step_error_after(&path)?; Ok(path.to_owned()) @@ -2683,12 +2584,21 @@ impl FileBackendTrait for TestBackend { fn export_impl( file_backend: &mut dyn WrappedFileBackendTrait, - top_module: Interned>, + mut top_module: Interned>, options: ExportOptions, ) -> Result<(), WrappedError> { - let top_module = options - .prepare_top_module(top_module) - .map_err(|e| file_backend.simplify_enums_error(e))?; + let ExportOptions { + simplify_memories: do_simplify_memories, + simplify_enums: do_simplify_enums, + __private: _, + } = options; + if let Some(kind) = do_simplify_enums { + top_module = + simplify_enums(top_module, kind).map_err(|e| file_backend.simplify_enums_error(e))?; + } + if do_simplify_memories { + top_module = simplify_memories(top_module); + } let indent_depth = Cell::new(0); let mut global_ns = Namespace::default(); let circuit_name = global_ns.get(top_module.name_id()); @@ -2698,7 +2608,7 @@ fn export_impl( indent_depth: &indent_depth, indent: " ", }, - seen_modules: HashSet::default(), + seen_modules: HashSet::new(), unwritten_modules: VecDeque::new(), global_ns, module: ModuleState::default(), @@ -2750,23 +2660,14 @@ impl clap::builder::TypedValueParser for OptionSimplifyEnumsKindValueParser { #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct ExportOptionsPrivate(()); -impl ExportOptionsPrivate { - fn private_new() -> Self { - Self(()) - } -} - -#[derive(clap::Parser, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(clap::Parser, Copy, Clone, PartialEq, Eq, Hash)] pub struct ExportOptions { #[clap(long = "no-simplify-memories", action = clap::ArgAction::SetFalse)] - #[serde(default = "ExportOptions::default_simplify_memories")] pub simplify_memories: bool, #[clap(long, value_parser = OptionSimplifyEnumsKindValueParser, default_value = "replace-with-bundle-of-uints")] - #[serde(default = "ExportOptions::default_simplify_enums")] - pub simplify_enums: std::option::Option, // use std::option::Option instead of Option to avoid clap mis-parsing + pub simplify_enums: std::option::Option, #[doc(hidden)] #[clap(skip = ExportOptionsPrivate(()))] - #[serde(skip, default = "ExportOptionsPrivate::private_new")] /// `#[non_exhaustive]` except allowing struct update syntax pub __private: ExportOptionsPrivate, } @@ -2777,34 +2678,7 @@ impl fmt::Debug for ExportOptions { } } -impl ToArgs for ExportOptions { - fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) { - let Self { - simplify_memories, - simplify_enums, - __private: ExportOptionsPrivate(()), - } = *self; - if !simplify_memories { - args.write_arg("--no-simplify-memories"); - } - let simplify_enums = simplify_enums.map(|v| { - clap::ValueEnum::to_possible_value(&v).expect("there are no skipped variants") - }); - let simplify_enums = match &simplify_enums { - None => OptionSimplifyEnumsKindValueParser::NONE_NAME, - Some(v) => v.get_name(), - }; - args.write_long_option_eq("simplify-enums", simplify_enums); - } -} - impl ExportOptions { - fn default_simplify_memories() -> bool { - true - } - fn default_simplify_enums() -> Option { - Some(SimplifyEnumsKind::ReplaceWithBundleOfUInts) - } fn debug_fmt( &self, f: &mut fmt::Formatter<'_>, @@ -2856,47 +2730,18 @@ impl ExportOptions { if f.alternate() { "\n}" } else { " }" } ) } - fn prepare_top_module_helper( - self, - mut top_module: Interned>, - ) -> Result>, SimplifyEnumsError> { - let Self { - simplify_memories: do_simplify_memories, - simplify_enums: do_simplify_enums, - __private: _, - } = self; - if let Some(kind) = do_simplify_enums { - top_module = simplify_enums(top_module, kind)?; - } - if do_simplify_memories { - top_module = simplify_memories(top_module); - } - Ok(top_module) - } - pub fn prepare_top_module( - self, - top_module: impl AsRef>, - ) -> Result>, SimplifyEnumsError> { - self.prepare_top_module_helper(top_module.as_ref().canonical().intern()) - } } impl Default for ExportOptions { fn default() -> Self { Self { - simplify_memories: Self::default_simplify_memories(), - simplify_enums: Self::default_simplify_enums(), + simplify_memories: true, + simplify_enums: Some(SimplifyEnumsKind::ReplaceWithBundleOfUInts), __private: ExportOptionsPrivate(()), } } } -pub fn get_circuit_name(top_module_name_id: NameId) -> Interned { - let mut global_ns = Namespace::default(); - let circuit_name = global_ns.get(top_module_name_id); - circuit_name.0 -} - pub fn export( file_backend: B, top_module: &Module, @@ -2908,497 +2753,6 @@ pub fn export( }) } -#[derive(Debug)] -#[non_exhaustive] -pub enum ScalarizedModuleABIError { - SimOnlyValuesAreNotPermitted, - SimplifyEnumsError(SimplifyEnumsError), -} - -impl fmt::Display for ScalarizedModuleABIError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ScalarizedModuleABIError::SimOnlyValuesAreNotPermitted => { - FirrtlError::SimOnlyValuesAreNotPermitted.fmt(f) - } - ScalarizedModuleABIError::SimplifyEnumsError(e) => e.fmt(f), - } - } -} - -impl std::error::Error for ScalarizedModuleABIError {} - -impl From for ScalarizedModuleABIError { - fn from(value: SimplifyEnumsError) -> Self { - Self::SimplifyEnumsError(value) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub enum ScalarizedModuleABIPortItem { - Group(ScalarizedModuleABIPortGroup), - Port(ScalarizedModuleABIPort), -} - -impl ScalarizedModuleABIPortItem { - pub fn module_io(self) -> ModuleIO { - *self - .target() - .base() - .module_io() - .expect("known to be ModuleIO") - } - pub fn target(self) -> Interned { - match self { - Self::Group(v) => v.target(), - Self::Port(v) => v.target(), - } - } - fn for_each_port_and_annotations_helper< - F: for<'a> FnMut( - &'a ScalarizedModuleABIPort, - ScalarizedModuleABIAnnotations<'a>, - ) -> ControlFlow, - B, - >( - &self, - parent: Option<&ScalarizedModuleABIAnnotations<'_>>, - f: &mut F, - ) -> ControlFlow { - match self { - Self::Group(v) => v.for_each_port_and_annotations_helper(parent, f), - Self::Port(port) => f( - port, - ScalarizedModuleABIAnnotations::new(parent, port.annotations.iter()), - ), - } - } - pub fn for_each_port_and_annotations< - F: for<'a> FnMut( - &'a ScalarizedModuleABIPort, - ScalarizedModuleABIAnnotations<'a>, - ) -> ControlFlow, - B, - >( - self, - mut f: F, - ) -> ControlFlow { - self.for_each_port_and_annotations_helper(None, &mut f) - } -} - -impl fmt::Debug for ScalarizedModuleABIPortItem { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Group(v) => v.fmt(f), - Self::Port(v) => v.fmt(f), - } - } -} - -#[derive(Debug, Clone)] -pub struct ScalarizedModuleABIAnnotations<'a> { - parent: Option<&'a ScalarizedModuleABIAnnotations<'a>>, - parent_len: usize, - annotations: std::slice::Iter<'a, TargetedAnnotation>, -} - -impl<'a> ScalarizedModuleABIAnnotations<'a> { - fn new( - parent: Option<&'a ScalarizedModuleABIAnnotations<'a>>, - annotations: std::slice::Iter<'a, TargetedAnnotation>, - ) -> Self { - Self { - parent, - parent_len: parent.map_or(0, |parent| parent.len()), - annotations, - } - } -} - -impl<'a> Default for ScalarizedModuleABIAnnotations<'a> { - fn default() -> Self { - Self { - parent: None, - parent_len: 0, - annotations: Default::default(), - } - } -} - -impl<'a> Iterator for ScalarizedModuleABIAnnotations<'a> { - type Item = &'a TargetedAnnotation; - - fn next(&mut self) -> Option { - loop { - if let retval @ Some(_) = self.annotations.next() { - break retval; - } - *self = self.parent?.clone(); - } - } - - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } - - fn fold(mut self, mut init: B, mut f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - loop { - let Self { - parent, - parent_len: _, - annotations, - } = self; - init = annotations.fold(init, &mut f); - let Some(next) = parent else { - break; - }; - self = next.clone(); - } - init - } -} - -impl std::iter::FusedIterator for ScalarizedModuleABIAnnotations<'_> {} - -impl ExactSizeIterator for ScalarizedModuleABIAnnotations<'_> { - fn len(&self) -> usize { - self.parent_len + self.annotations.len() - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct ScalarizedModuleABIPortGroup { - target: Interned, - common_annotations: Interned<[TargetedAnnotation]>, - children: Interned<[ScalarizedModuleABIPortItem]>, -} - -impl ScalarizedModuleABIPortGroup { - pub fn module_io(self) -> ModuleIO { - *self - .target - .base() - .module_io() - .expect("known to be ModuleIO") - } - pub fn target(self) -> Interned { - self.target - } - pub fn common_annotations(self) -> Interned<[TargetedAnnotation]> { - self.common_annotations - } - pub fn children(self) -> Interned<[ScalarizedModuleABIPortItem]> { - self.children - } - fn for_each_port_and_annotations_helper< - F: for<'a> FnMut( - &'a ScalarizedModuleABIPort, - ScalarizedModuleABIAnnotations<'a>, - ) -> ControlFlow, - B, - >( - &self, - parent: Option<&ScalarizedModuleABIAnnotations<'_>>, - f: &mut F, - ) -> ControlFlow { - let parent = ScalarizedModuleABIAnnotations::new(parent, self.common_annotations.iter()); - for item in &self.children { - item.for_each_port_and_annotations_helper(Some(&parent), f)?; - } - ControlFlow::Continue(()) - } - pub fn for_each_port_and_annotations< - F: for<'a> FnMut( - &'a ScalarizedModuleABIPort, - ScalarizedModuleABIAnnotations<'a>, - ) -> ControlFlow, - B, - >( - self, - mut f: F, - ) -> ControlFlow { - self.for_each_port_and_annotations_helper(None, &mut f) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct ScalarizedModuleABIPort { - target: Interned, - annotations: Interned<[TargetedAnnotation]>, - scalarized_name: Interned, -} - -impl ScalarizedModuleABIPort { - pub fn module_io(self) -> ModuleIO { - *self - .target - .base() - .module_io() - .expect("known to be ModuleIO") - } - pub fn target(self) -> Interned { - self.target - } - pub fn annotations(self) -> Interned<[TargetedAnnotation]> { - self.annotations - } - pub fn scalarized_name(self) -> Interned { - self.scalarized_name - } -} - -enum ScalarizeTreeNodeBody { - Leaf { - scalarized_name: Interned, - }, - Bundle { - ty: Bundle, - fields: Vec, - }, - Array { - elements: Vec, - }, -} - -struct ScalarizeTreeNode { - target: Interned, - annotations: Vec, - body: ScalarizeTreeNodeBody, -} - -impl ScalarizeTreeNode { - #[track_caller] - fn find_target(&mut self, annotation_target: Interned) -> &mut Self { - match *annotation_target { - Target::Base(_) => { - assert_eq!( - annotation_target, self.target, - "annotation not on correct ModuleIO", - ); - self - } - Target::Child(target_child) => { - let parent = self.find_target(target_child.parent()); - match *target_child.path_element() { - TargetPathElement::BundleField(TargetPathBundleField { name }) => { - match parent.body { - ScalarizeTreeNodeBody::Leaf { .. } => parent, - ScalarizeTreeNodeBody::Bundle { ty, ref mut fields } => { - &mut fields[ty.name_indexes()[&name]] - } - ScalarizeTreeNodeBody::Array { .. } => { - unreachable!("types are known to match") - } - } - } - TargetPathElement::ArrayElement(TargetPathArrayElement { index }) => { - match parent.body { - ScalarizeTreeNodeBody::Leaf { .. } => parent, - ScalarizeTreeNodeBody::Bundle { .. } => { - unreachable!("types are known to match") - } - ScalarizeTreeNodeBody::Array { ref mut elements } => { - &mut elements[index] - } - } - } - TargetPathElement::DynArrayElement(_) => { - unreachable!("annotations are only on static targets"); - } - } - } - } - } - fn into_scalarized_item(self) -> ScalarizedModuleABIPortItem { - let Self { - target, - annotations, - body, - } = self; - match body { - ScalarizeTreeNodeBody::Leaf { scalarized_name } => { - ScalarizedModuleABIPortItem::Port(ScalarizedModuleABIPort { - target, - annotations: Intern::intern_owned(annotations), - scalarized_name, - }) - } - ScalarizeTreeNodeBody::Bundle { fields: items, .. } - | ScalarizeTreeNodeBody::Array { elements: items } => { - ScalarizedModuleABIPortItem::Group(ScalarizedModuleABIPortGroup { - target, - common_annotations: Intern::intern_owned(annotations), - children: Interned::from_iter( - items.into_iter().map(Self::into_scalarized_item), - ), - }) - } - } - } -} - -#[derive(Default)] -struct ScalarizeTreeBuilder { - scalarized_ns: Namespace, - type_state: TypeState, - name: String, -} - -impl ScalarizeTreeBuilder { - #[track_caller] - fn build_bundle( - &mut self, - target: Interned, - ty: Bundle, - ) -> Result { - let mut fields = Vec::with_capacity(ty.fields().len()); - let original_len = self.name.len(); - for BundleField { name, .. } in ty.fields() { - let firrtl_name = self - .type_state - .get_bundle_field(ty, name) - .map_err(|e| match e { - FirrtlError::SimOnlyValuesAreNotPermitted => { - ScalarizedModuleABIError::SimOnlyValuesAreNotPermitted - } - })? - .0; - write!(self.name, "_{firrtl_name}").expect("writing to String is infallible"); - fields.push( - self.build( - target - .join(TargetPathElement::intern_sized( - TargetPathBundleField { name }.into(), - )) - .intern_sized(), - )?, - ); - self.name.truncate(original_len); - } - Ok(ScalarizeTreeNode { - target, - annotations: Vec::new(), - body: ScalarizeTreeNodeBody::Bundle { ty, fields }, - }) - } - #[track_caller] - fn build( - &mut self, - target: Interned, - ) -> Result { - Ok(match target.canonical_ty() { - CanonicalType::UInt(_) - | CanonicalType::SInt(_) - | CanonicalType::Bool(_) - | CanonicalType::Enum(_) - | CanonicalType::AsyncReset(_) - | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::Clock(_) => { - let scalarized_name = self.scalarized_ns.get(str::intern(&self.name)).0; - ScalarizeTreeNode { - target, - annotations: Vec::new(), - body: ScalarizeTreeNodeBody::Leaf { scalarized_name }, - } - } - CanonicalType::Array(ty) => { - let mut elements = Vec::with_capacity(ty.len()); - let original_len = self.name.len(); - for index in 0..ty.len() { - write!(self.name, "_{index}").expect("writing to String is infallible"); - elements.push( - self.build( - target - .join(TargetPathElement::intern_sized( - TargetPathArrayElement { index }.into(), - )) - .intern_sized(), - )?, - ); - self.name.truncate(original_len); - } - ScalarizeTreeNode { - target, - annotations: Vec::new(), - body: ScalarizeTreeNodeBody::Array { elements }, - } - } - CanonicalType::Bundle(ty) => self.build_bundle(target, ty)?, - CanonicalType::PhantomConst(_) => { - self.build_bundle(target, Bundle::new(Interned::default()))? - } - CanonicalType::DynSimOnly(_) => { - return Err(ScalarizedModuleABIError::SimOnlyValuesAreNotPermitted); - } - }) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct ScalarizedModuleABI { - module_io: Interned<[AnnotatedModuleIO]>, - items: Interned<[ScalarizedModuleABIPortItem]>, -} - -impl ScalarizedModuleABI { - #[track_caller] - fn from_io(module_io: Interned<[AnnotatedModuleIO]>) -> Result { - let mut firrtl_ns = Namespace::default(); - let mut tree_builder = ScalarizeTreeBuilder::default(); - let mut items = Vec::new(); - for module_io in module_io { - let firrtl_name = firrtl_ns.get(module_io.module_io.name_id()); - tree_builder.name.clear(); - tree_builder.name.push_str(&firrtl_name.0); - let mut tree = tree_builder.build(Target::from(module_io.module_io).intern_sized())?; - for annotation in module_io.annotations { - tree.find_target(annotation.target()) - .annotations - .push(annotation); - } - items.push(tree.into_scalarized_item()); - } - Ok(Self { - module_io, - items: Intern::intern_owned(items), - }) - } - #[track_caller] - pub fn new( - module: impl AsRef>, - options: ExportOptions, - ) -> Result { - Self::from_io(options.prepare_top_module(module)?.module_io()) - } - pub fn module_io(&self) -> Interned<[AnnotatedModuleIO]> { - self.module_io - } - pub fn items(&self) -> Interned<[ScalarizedModuleABIPortItem]> { - self.items - } - pub fn for_each_port_and_annotations< - F: for<'a> FnMut( - &'a ScalarizedModuleABIPort, - ScalarizedModuleABIAnnotations<'a>, - ) -> ControlFlow, - B, - >( - self, - mut f: F, - ) -> ControlFlow { - for item in &self.items { - item.for_each_port_and_annotations_helper(None, &mut f)?; - } - ControlFlow::Continue(()) - } -} - #[doc(hidden)] #[track_caller] pub fn assert_export_firrtl_impl(top_module: &Module, expected: TestBackend) { diff --git a/crates/fayalite/src/int.rs b/crates/fayalite/src/int.rs index 7fa77ce..b49ca3f 100644 --- a/crates/fayalite/src/int.rs +++ b/crates/fayalite/src/int.rs @@ -2,55 +2,27 @@ // See Notices.txt for copyright information use crate::{ - array::ArrayType, expr::{ - Expr, NotALiteralExpr, ToExpr, ToLiteralBits, target::{GetTarget, Target}, + Expr, NotALiteralExpr, ToExpr, ToLiteralBits, }, - hdl, intern::{Intern, Interned, Memoize}, - sim::value::{SimValue, ToSimValueWithType}, source_location::SourceLocation, - ty::{ - CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter, - OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self, - }, - util::{ConstBool, ConstUsize, GenericConstBool, GenericConstUsize, interned_bit, slice_range}, + ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, + util::{interned_bit, ConstBool, ConstUsize, GenericConstBool, GenericConstUsize}, }; -use bitvec::{bits, order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView}; +use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec}; use num_bigint::{BigInt, BigUint, Sign}; -use num_traits::{One, Signed, Zero}; -use serde::{ - Deserialize, Deserializer, Serialize, Serializer, - de::{DeserializeOwned, Error, Visitor}, -}; +use num_traits::{Signed, Zero}; use std::{ borrow::{BorrowMut, Cow}, fmt, marker::PhantomData, num::NonZero, - ops::{Index, Not, Range, RangeBounds, RangeInclusive}, - str::FromStr, + ops::{Bound, Index, Not, Range, RangeBounds, RangeInclusive}, sync::Arc, }; -mod uint_in_range; - -#[hdl] -pub type UIntInRangeType = uint_in_range::UIntInRangeType; - -#[hdl] -pub type UIntInRange = - UIntInRangeType, ConstUsize>; - -#[hdl] -pub type UIntInRangeInclusiveType = - uint_in_range::UIntInRangeInclusiveType; - -#[hdl] -pub type UIntInRangeInclusive = - UIntInRangeInclusiveType, ConstUsize>; - mod sealed { pub trait BoolOrIntTypeSealed {} pub trait SizeSealed {} @@ -77,16 +49,6 @@ pub trait KnownSize: + IntoIterator> + TryFrom>> + Into>>; - type ArraySimValue: AsRef<[SimValue]> - + AsMut<[SimValue]> - + BorrowMut<[SimValue]> - + 'static - + Clone - + std::fmt::Debug - + IntoIterator> - + TryFrom>> - + Into>> - + ToSimValueWithType>; } macro_rules! known_widths { @@ -98,7 +60,6 @@ macro_rules! known_widths { }> { const SIZE: Self = Self; type ArrayMatch = [Expr; Self::VALUE]; - type ArraySimValue = [SimValue; Self::VALUE]; } }; ([2 $($rest:tt)*] $($bits:literal)+) => { @@ -111,7 +72,6 @@ macro_rules! known_widths { impl KnownSize for ConstUsize<{2 $(* $rest)*}> { const SIZE: Self = Self; type ArrayMatch = [Expr; Self::VALUE]; - type ArraySimValue = [SimValue; Self::VALUE]; } }; } @@ -119,31 +79,13 @@ macro_rules! known_widths { known_widths!([2 2 2 2 2 2 2 2 2]); pub trait SizeType: - sealed::SizeTypeSealed - + Copy - + Ord - + std::hash::Hash - + std::fmt::Debug - + Send - + Sync - + 'static - + Serialize - + DeserializeOwned + sealed::SizeTypeSealed + Copy + Ord + std::hash::Hash + std::fmt::Debug + Send + Sync + 'static { type Size: Size; } pub trait Size: - sealed::SizeSealed - + Copy - + Ord - + std::hash::Hash - + std::fmt::Debug - + Send - + Sync - + 'static - + Serialize - + DeserializeOwned + sealed::SizeSealed + Copy + Ord + std::hash::Hash + std::fmt::Debug + Send + Sync + 'static { type ArrayMatch: AsRef<[Expr]> + AsMut<[Expr]> @@ -158,16 +100,6 @@ pub trait Size: + IntoIterator> + TryFrom>> + Into>>; - type ArraySimValue: AsRef<[SimValue]> - + AsMut<[SimValue]> - + BorrowMut<[SimValue]> - + 'static - + Clone - + std::fmt::Debug - + IntoIterator> - + TryFrom>> - + Into>> - + ToSimValueWithType>; const KNOWN_VALUE: Option; type SizeType: SizeType + Copy @@ -193,7 +125,6 @@ impl SizeType for usize { impl Size for DynSize { type ArrayMatch = Box<[Expr]>; - type ArraySimValue = Box<[SimValue]>; const KNOWN_VALUE: Option = None; type SizeType = usize; @@ -216,7 +147,6 @@ impl SizeType for T { impl Size for T { type ArrayMatch = ::ArrayMatch; - type ArraySimValue = ::ArraySimValue; const KNOWN_VALUE: Option = Some(T::VALUE); @@ -227,309 +157,14 @@ impl Size for T { } fn try_from_usize(v: usize) -> Option { - if v == T::VALUE { Some(T::SIZE) } else { None } - } -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum ParseIntValueError { - Empty, - InvalidDigit, - MissingDigits, - InvalidRadix, - MissingType, - InvalidType, - TypeMismatch { - parsed_signed: bool, - parsed_width: usize, - expected_signed: bool, - expected_width: usize, - }, - PosOverflow, - NegOverflow, - WidthOverflow, - MissingWidth, -} - -impl std::error::Error for ParseIntValueError {} - -impl fmt::Display for ParseIntValueError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match self { - Self::Empty => "can't parse integer from empty string", - Self::InvalidDigit => "invalid digit", - Self::MissingDigits => "missing digits", - Self::InvalidRadix => "invalid radix", - Self::MissingType => "missing type", - Self::InvalidType => "invalid type", - Self::TypeMismatch { - parsed_signed, - parsed_width, - expected_signed, - expected_width, - } => { - return write!( - f, - "type mismatch: parsed type {parsed_signed_str}{parsed_width}, \ - expected type {expected_signed_str}{expected_width}", - parsed_signed_str = if *parsed_signed { "i" } else { "u" }, - expected_signed_str = if *expected_signed { "i" } else { "u" }, - ); - } - Self::PosOverflow => "value too large to fit in type", - Self::NegOverflow => "value too small to fit in type", - Self::WidthOverflow => "width is too large", - Self::MissingWidth => "missing width", - }) - } -} - -fn parse_int_value( - s: &str, - type_is_signed: bool, - type_width: Option, - parse_type: bool, -) -> Result, ParseIntValueError> { - if !parse_type && type_width.is_none() { - return Err(ParseIntValueError::MissingWidth); - } - let mut s = s.trim(); - if s.is_empty() { - return Err(ParseIntValueError::Empty); - } - let negative = match s.bytes().next() { - Some(ch @ (b'+' | b'-')) => { - s = s[1..].trim_start(); - ch == b'-' - } - _ => false, - }; - let radix = match s.bytes().next() { - Some(b'0') => match s.bytes().nth(1) { - Some(b'x' | b'X') => { - s = &s[2..]; - 16 - } - Some(b'b' | b'B') => { - s = &s[2..]; - 2 - } - Some(b'o' | b'O') => { - s = &s[2..]; - 8 - } - _ => 10, - }, - Some(b'1'..=b'9') => 10, - _ => return Err(ParseIntValueError::InvalidDigit), - }; - let mut any_digits = false; - let digits_end = s - .as_bytes() - .iter() - .position(|&ch| { - if ch == b'_' { - false - } else if (ch as char).to_digit(radix).is_some() { - any_digits = true; - false - } else { - true - } - }) - .unwrap_or(s.len()); - let digits = &s[..digits_end]; - s = &s[digits_end..]; - if !any_digits { - return Err(ParseIntValueError::MissingDigits); - } - let width = if parse_type { - const HDL_PREFIX: &[u8] = b"hdl_"; - let mut missing_type = ParseIntValueError::MissingType; - if s.as_bytes() - .get(..HDL_PREFIX.len()) - .is_some_and(|bytes| bytes.eq_ignore_ascii_case(HDL_PREFIX)) - { - s = &s[HDL_PREFIX.len()..]; - missing_type = ParseIntValueError::InvalidType; - } - let signed = match s.bytes().next() { - Some(b'u' | b'U') => false, - Some(b'i' | b'I') => true, - Some(_) => return Err(ParseIntValueError::InvalidType), - None => return Err(missing_type), - }; - s = &s[1..]; - let mut width = 0usize; - let mut any_digits = false; - for ch in s.bytes() { - let digit = (ch as char) - .to_digit(10) - .ok_or(ParseIntValueError::InvalidDigit)?; - any_digits = true; - width = width - .checked_mul(10) - .and_then(|v| v.checked_add(digit as usize)) - .ok_or(ParseIntValueError::WidthOverflow)?; - } - if !any_digits { - return Err(ParseIntValueError::MissingDigits); - } - if width > ::MAX_BITS { - return Err(ParseIntValueError::WidthOverflow); - } - let expected_width = type_width.unwrap_or(width); - if type_is_signed != signed || expected_width != width { - let expected_width = type_width.unwrap_or(width); - return Err(ParseIntValueError::TypeMismatch { - parsed_signed: signed, - parsed_width: width, - expected_signed: type_is_signed, - expected_width, - }); - } - width - } else { - if !s.is_empty() { - return Err(ParseIntValueError::InvalidDigit); - } - type_width.expect("checked earlier") - }; - if !type_is_signed && negative { - return Err(ParseIntValueError::InvalidDigit); - } - if radix == 10 { - let mut value: BigInt = digits - .replace("_", "") - .parse() - .expect("checked that the digits are valid already"); - if negative { - value = -value; - } - let uint_value: UIntValue = UInt::new(width).from_bigint_wrapping(&value); - if value.is_zero() { - Ok(uint_value.into_bits()) + if v == T::VALUE { + Some(T::SIZE) } else { - for i in 0..width { - value.set_bit(i as u64, type_is_signed && negative); - } - if value.is_zero() { - Ok(uint_value.into_bits()) - } else if type_is_signed && negative { - if value.sign() == Sign::Minus && value.magnitude().is_one() { - Ok(uint_value.into_bits()) - } else { - Err(ParseIntValueError::NegOverflow) - } - } else { - Err(ParseIntValueError::PosOverflow) - } - } - } else { - let mut value = BitVec::repeat(false, width); - let bits_per_digit = match radix { - 2 => 1, - 8 => 3, - 16 => 4, - _ => unreachable!(), - }; - let mut digits = digits - .bytes() - .rev() - .filter_map(|ch| (ch as char).to_digit(radix)); - let overflow_error = if negative { - ParseIntValueError::NegOverflow - } else { - ParseIntValueError::PosOverflow - }; - for chunk in value.chunks_mut(bits_per_digit) { - if let Some(mut digit) = digits.next() { - let digit_bits = &mut digit.view_bits_mut::()[..chunk.len()]; - chunk.clone_from_bitslice(digit_bits); - digit_bits.fill(false); - if digit != 0 { - return Err(overflow_error); - } - } else { - break; - } - } - for digit in digits { - if digit != 0 { - return Err(overflow_error); - } - } - let negative_zero = if negative { - // negating a value happens in three regions: - // * the least-significant zeros, which are left as zeros - // * the least-significant one bit, which is left as a one bit - // * all the most-significant bits, which are inverted - // e.g.: - const { - let inp = 0b1010_1_000_u8; - let out = 0b0101_1_000_u8; - assert!(inp.wrapping_neg() == out); - }; - if let Some(first_one) = value.first_one() { - let most_significant_bits = &mut value[first_one + 1..]; - // modifies in-place despite using `Not::not` - let _ = Not::not(most_significant_bits); - false - } else { - true - } - } else { - false - }; - if !negative_zero && type_is_signed && negative != value[value.len() - 1] { - Err(overflow_error) - } else { - Ok(Arc::new(value)) + None } } } -fn deserialize_int_value<'de, D: Deserializer<'de>>( - deserializer: D, - type_is_signed: bool, - type_width: Option, -) -> Result, D::Error> { - struct IntValueVisitor { - type_is_signed: bool, - type_width: Option, - } - impl<'de> Visitor<'de> for IntValueVisitor { - type Value = Arc; - - fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(if self.type_is_signed { - "SIntValue" - } else { - "UIntValue" - })?; - if let Some(type_width) = self.type_width { - write!(f, "<{type_width}>")?; - } - Ok(()) - } - - fn visit_str(self, v: &str) -> Result { - parse_int_value(v, self.type_is_signed, self.type_width, true).map_err(E::custom) - } - - fn visit_bytes(self, v: &[u8]) -> Result { - match std::str::from_utf8(v) { - Ok(v) => self.visit_str(v), - Err(_) => Err(Error::invalid_value(serde::de::Unexpected::Bytes(v), &self)), - } - } - } - deserializer.deserialize_str(IntValueVisitor { - type_is_signed, - type_width, - }) -} - macro_rules! impl_int { ($pretty_name:ident, $name:ident, $generic_name:ident, $value:ident, $SIGNED:literal) => { #[derive(Copy, Clone, PartialEq, Eq, Hash)] @@ -553,14 +188,19 @@ macro_rules! impl_int { pub const $name: $generic_name = $generic_name; impl $name { - pub const fn new(width: Width::SizeType) -> Self { + pub fn new(width: Width::SizeType) -> Self { Self { width } } pub fn width(self) -> usize { Width::as_usize(self.width) } pub fn type_properties(self) -> TypeProperties { - self.as_dyn_int().type_properties_dyn() + TypeProperties { + is_passive: true, + is_storable: true, + is_castable_from_bits: true, + bit_width: self.width(), + } } pub fn bits_from_bigint_wrapping(self, v: &BigInt) -> BitVec { BoolOrIntType::bits_from_bigint_wrapping(self, v) @@ -623,12 +263,6 @@ macro_rules! impl_int { } Expr::from_dyn_int(MemoizeBitsToExpr.get_cow(bits)) } - fn from_str_without_ty( - self, - s: &str, - ) -> Result::Err> { - parse_int_value(s, $SIGNED, Some(self.width()), false).map(Self::Value::new) - } } impl IntType for $name { @@ -636,21 +270,12 @@ macro_rules! impl_int { } impl $name { - pub const fn new_dyn(width: usize) -> Self { + pub fn new_dyn(width: usize) -> Self { Self { width } } pub fn bits_to_bigint(bits: &BitSlice) -> BigInt { ::bits_to_bigint(bits) } - pub const fn type_properties_dyn(self) -> TypeProperties { - TypeProperties { - is_passive: true, - is_storable: true, - is_castable_from_bits: true, - bit_width: self.width, - sim_only_values_len: 0, - } - } } impl $name { @@ -662,7 +287,6 @@ macro_rules! impl_int { impl Type for $name { type BaseType = $pretty_name; type MaskType = Bool; - type SimValue = $value; impl_match_variant_as_self!(); fn mask_type(&self) -> Self::MaskType { Bool @@ -673,7 +297,7 @@ macro_rules! impl_int { #[track_caller] fn from_canonical(canonical_type: CanonicalType) -> Self { let CanonicalType::$pretty_name(retval) = canonical_type else { - panic!("expected {}", stringify!($pretty_name)); + panic!("expected {}", stringify!($name)); }; $name { width: Width::from_usize(retval.width), @@ -682,95 +306,20 @@ macro_rules! impl_int { fn source_location() -> SourceLocation { SourceLocation::builtin() } - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - assert_eq!( - opaque.size(), - OpaqueSimValueSize::from_bit_width(self.width()) - ); - $value::new(Arc::new(opaque.bits().to_bitvec())) - } - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ) { - assert_eq!( - opaque.size(), - OpaqueSimValueSize::from_bit_width(self.width()) - ); - assert_eq!(value.width(), self.width()); - value.bits_mut().copy_from_bitslice(opaque.bits()); - } - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> OpaqueSimValueWritten<'w> { - assert_eq!( - writer.size(), - OpaqueSimValueSize::from_bit_width(self.width()) - ); - assert_eq!(value.width(), self.width()); - writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice(value.bits())) - } - } - - impl Default for $name { - fn default() -> Self { - Self::TYPE - } } impl StaticType for $name { const TYPE: Self = Self { width: Width::SIZE }; const MASK_TYPE: Self::MaskType = Bool; - const TYPE_PROPERTIES: TypeProperties = $name { - width: Width::VALUE, - } - .type_properties_dyn(); + const TYPE_PROPERTIES: TypeProperties = TypeProperties { + is_passive: true, + is_storable: true, + is_castable_from_bits: true, + bit_width: Width::VALUE, + }; const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; } - impl Serialize for $name { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.canonical().serialize(serializer) - } - } - - impl<'de, Width: Size> Deserialize<'de> for $name { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let name = |width| -> String { - if let Some(width) = width { - format!("a {}<{width}>", stringify!($pretty_name)) - } else { - format!("a {}", stringify!($pretty_name)) - } - }; - match CanonicalType::deserialize(deserializer)? { - CanonicalType::$pretty_name(retval) => { - if let Some(width) = Width::try_from_usize(retval.width()) { - Ok($name { width }) - } else { - Err(Error::invalid_value( - serde::de::Unexpected::Other(&name(Some(retval.width()))), - &&*name(Width::KNOWN_VALUE), - )) - } - } - ty => Err(Error::invalid_value( - serde::de::Unexpected::Other(ty.as_serde_unexpected_str()), - &&*name(Width::KNOWN_VALUE), - )), - } - } - } - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] pub struct $generic_name; @@ -788,7 +337,7 @@ macro_rules! impl_int { _phantom: PhantomData, } - impl fmt::Display for $value { + impl fmt::Debug for $value { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let value = self.to_bigint(); let (sign, magnitude) = value.into_parts(); @@ -802,38 +351,15 @@ macro_rules! impl_int { } } - impl fmt::Debug for $value { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } - } - - impl std::str::FromStr for $value { - type Err = ParseIntValueError; - - fn from_str(s: &str) -> Result { - parse_int_value(s, $SIGNED, Width::KNOWN_VALUE, true).map(Self::new) - } - } - - impl Serialize for $value { - fn serialize(&self, serializer: S) -> Result { - self.to_string().serialize(serializer) - } - } - - impl<'de, Width: Size> Deserialize<'de> for $value { - fn deserialize>(deserializer: D) -> Result { - deserialize_int_value(deserializer, $SIGNED, Width::KNOWN_VALUE).map(Self::new) - } - } - impl PartialOrd for $value { fn partial_cmp(&self, other: &Self) -> Option { - if self.width() != other.width() { - return None; - } - Some(self.to_bigint().cmp(&other.to_bigint())) + Some(self.cmp(other)) + } + } + + impl Ord for $value { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.to_bigint().cmp(&other.to_bigint()) } } @@ -875,9 +401,6 @@ macro_rules! impl_int { pub fn bits(&self) -> &Arc { &self.bits } - pub fn bits_mut(&mut self) -> &mut BitSlice { - Arc::::make_mut(&mut self.bits) - } } impl ToLiteralBits for $value { @@ -919,9 +442,6 @@ macro_rules! impl_int { _phantom: PhantomData, } } - pub fn bitvec_mut(&mut self) -> &mut BitVec { - Arc::make_mut(&mut self.bits) - } } }; } @@ -935,10 +455,6 @@ impl UInt { let v: BigUint = v.into(); Self::new(v.bits().try_into().expect("too big")) } - /// gets the smallest `UInt` that fits `v` losslessly - pub const fn for_value_usize(v: usize) -> Self { - Self::new((usize::BITS - v.leading_zeros()) as usize) - } /// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty #[track_caller] pub fn range(r: Range>) -> Self { @@ -949,12 +465,6 @@ impl UInt { } /// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty #[track_caller] - pub const fn range_usize(r: Range) -> Self { - assert!(r.end != 0, "empty range"); - Self::range_inclusive_usize(r.start..=(r.end - 1)) - } - /// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty - #[track_caller] pub fn range_inclusive(r: RangeInclusive>) -> Self { let (start, end) = r.into_inner(); let start: BigUint = start.into(); @@ -964,16 +474,6 @@ impl UInt { // so must not take more bits than `end` Self::for_value(end) } - /// gets the smallest `UInt` that fits `r` losslessly, panics if `r` is empty - #[track_caller] - pub const fn range_inclusive_usize(r: RangeInclusive) -> Self { - let start = *r.start(); - let end = *r.end(); - assert!(start <= end, "empty range"); - // no need to check `start`` since it's no larger than `end` - // so must not take more bits than `end` - Self::for_value_usize(end) - } } impl SInt { @@ -1067,12 +567,12 @@ impl_prim_int!(i64, SInt<64>); impl_prim_int!(i128, SInt<128>); impl_prim_int!( - /// for portability reasons, [`usize`] always translates to [`UInt<64>`][type@UInt] + /// for portability reasons, [`usize`] always translates to [`UInt<64>`] usize, UInt<64> ); impl_prim_int!( - /// for portability reasons, [`isize`] always translates to [`SInt<64>`][type@SInt] + /// for portability reasons, [`isize`] always translates to [`SInt<64>`] isize, SInt<64> ); @@ -1080,17 +580,14 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed { type Width: Size; type Signed: GenericConstBool; type Value: Clone - + PartialOrd - + Eq + + Ord + std::hash::Hash + fmt::Debug - + fmt::Display + Send + Sync + 'static + ToExpr - + Into - + std::str::FromStr; + + Into; fn width(self) -> usize; fn new(width: ::SizeType) -> Self; fn new_static() -> Self @@ -1124,12 +621,6 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed { let bitslice = &BitSlice::::from_slice(&bytes)[..width]; bits.clone_from_bitslice(bitslice); } - fn bits_equal_bigint_wrapping(v: &BigInt, bits: &BitSlice) -> bool { - bits.iter() - .by_vals() - .enumerate() - .all(|(bit_index, bit): (usize, bool)| v.bit(bit_index as u64) == bit) - } fn bits_to_bigint(bits: &BitSlice) -> BigInt { let sign_byte = if Self::Signed::VALUE && bits.last().as_deref().copied().unwrap_or(false) { 0xFF @@ -1163,12 +654,9 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed { bytes, bit_width, ))) } - fn from_str_without_ty(self, s: &str) -> Result::Err>; } -pub trait IntType: - BoolOrIntType::Dyn, Value: FromStr> -{ +pub trait IntType: BoolOrIntType::Dyn> { type Dyn: IntType; fn as_dyn_int(self) -> Self::Dyn { Self::new_dyn(self.width()) @@ -1184,7 +672,19 @@ pub trait IntType: Self::Dyn::new(width) } fn slice_index_to_range>(self, index: I) -> Range { - slice_range(index, self.width()) + let width = self.width(); + let start = match index.start_bound() { + Bound::Included(start) => *start, + Bound::Excluded(start) => *start + 1, + Bound::Unbounded => 0, + }; + let end = match index.end_bound() { + Bound::Included(end) => *end + 1, + Bound::Excluded(end) => *end, + Bound::Unbounded => width, + }; + assert!(start <= end && end <= width, "slice range out-of-range"); + start..end } fn slice_and_shift>(self, index: I) -> (UInt, usize) { let range = self.slice_index_to_range(index); @@ -1196,7 +696,7 @@ pub trait IntType: } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Bool; impl sealed::BoolOrIntTypeSealed for Bool {} @@ -1228,10 +728,6 @@ impl BoolOrIntType for Bool { assert_eq!(bits.len(), 1); bits[0] } - - fn from_str_without_ty(self, s: &str) -> Result::Err> { - FromStr::from_str(s) - } } impl Bool { @@ -1246,7 +742,6 @@ impl Bool { impl Type for Bool { type BaseType = Bool; type MaskType = Bool; - type SimValue = bool; impl_match_variant_as_self!(); fn mask_type(&self) -> Self::MaskType { Bool @@ -1264,28 +759,6 @@ impl Type for Bool { fn source_location() -> SourceLocation { SourceLocation::builtin() } - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); - opaque.bits()[0] - } - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ) { - assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); - *value = opaque.bits()[0]; - } - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> OpaqueSimValueWritten<'w> { - assert_eq!(writer.size(), OpaqueSimValueSize::from_bit_width(1)); - writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice( - [bits![0], bits![1]][*value as usize], - )) - } } impl StaticType for Bool { @@ -1296,7 +769,6 @@ impl StaticType for Bool { is_storable: true, is_castable_from_bits: true, bit_width: 1, - sim_only_values_len: 0, }; const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; } @@ -1311,13 +783,6 @@ impl ToLiteralBits for bool { mod tests { use super::*; - #[test] - fn test_different_value_widths_compare_ne() { - // interning relies on [SU]IntValue with different `width` comparing not equal - assert_ne!(UInt[3].from_int_wrapping(0), UInt[4].from_int_wrapping(0)); - assert_ne!(SInt[3].from_int_wrapping(0), SInt[4].from_int_wrapping(0)); - } - #[test] fn test_uint_for_value() { assert_eq!(UInt::for_value(0u8).width, 0); @@ -1340,104 +805,4 @@ mod tests { assert_eq!(SInt::for_value(3).width, 3); assert_eq!(SInt::for_value(4).width, 4); } - - #[test] - fn test_serde_round_trip() { - use serde_json::json; - #[track_caller] - fn check( - value: T, - expected: serde_json::Value, - ) { - assert_eq!(serde_json::to_value(&value).unwrap(), expected); - assert_eq!(value, T::deserialize(expected).unwrap()); - } - check(UInt[0], json! { { "UInt": { "width": 0 } } }); - check(UInt::<0>::TYPE, json! { { "UInt": { "width": 0 } } }); - check(UInt::<35>::TYPE, json! { { "UInt": { "width": 35 } } }); - check(SInt[0], json! { { "SInt": { "width": 0 } } }); - check(SInt::<0>::TYPE, json! { { "SInt": { "width": 0 } } }); - check(SInt::<35>::TYPE, json! { { "SInt": { "width": 35 } } }); - check(Bool, json! { "Bool" }); - check(UIntValue::from(0u8), json! { "0x0_u8" }); - check(SIntValue::from(-128i8), json! { "-0x80_i8" }); - check(UInt[3].from_int_wrapping(5), json! { "0x5_u3" }); - check(UInt[12].from_int_wrapping(0x1123), json! { "0x123_u12" }); - check(SInt[12].from_int_wrapping(0xFEE), json! { "-0x12_i12" }); - check(SInt[12].from_int_wrapping(0x7EE), json! { "0x7EE_i12" }); - } - - #[test] - fn test_deserialize() { - use serde_json::json; - #[track_caller] - fn check( - expected: Result, - input: serde_json::Value, - ) { - let mut error = String::new(); - let value = T::deserialize(input).map_err(|e| -> &str { - error = e.to_string(); - &error - }); - assert_eq!(value, expected); - } - check::>( - Err("invalid value: a UInt<2>, expected a UInt<0>"), - json! { { "UInt": { "width": 2 } } }, - ); - check::>( - Err("invalid value: a Bool, expected a UInt<0>"), - json! { "Bool" }, - ); - check::>( - Err("invalid value: a Bool, expected a SInt<0>"), - json! { "Bool" }, - ); - check::( - Err("invalid value: a Bool, expected a UInt"), - json! { "Bool" }, - ); - check::( - Err("invalid value: a Bool, expected a SInt"), - json! { "Bool" }, - ); - check::(Err("value too large to fit in type"), json! { "2_u1" }); - check::(Err("value too large to fit in type"), json! { "10_u1" }); - check::(Err("value too large to fit in type"), json! { "0x2_u1" }); - check::(Err("value too large to fit in type"), json! { "0b10_u1" }); - check::(Err("value too large to fit in type"), json! { "0o2_u1" }); - check::(Err("value too large to fit in type"), json! { "0o377_i8" }); - check::(Err("value too large to fit in type"), json! { "0o200_i8" }); - check(Ok(SInt[8].from_int_wrapping(i8::MAX)), json! { "0o177_i8" }); - check::(Err("value too small to fit in type"), json! { "-0o201_i8" }); - check::(Err("value too small to fit in type"), json! { "-0o377_i8" }); - check::(Err("value too small to fit in type"), json! { "-0o400_i8" }); - check::( - Err("value too small to fit in type"), - json! { "-0o4000_i8" }, - ); - check(Ok(UIntValue::from(0u8)), json! { "0_u8" }); - check(Ok(UIntValue::from(0u8)), json! { "0b0_u8" }); - check(Ok(UIntValue::from(0u8)), json! { "00_u8" }); - check(Ok(UIntValue::from(0u8)), json! { "0x0_u8" }); - check(Ok(UIntValue::from(0u8)), json! { "0o0_u8" }); - check(Ok(SIntValue::from(-128i8)), json! { "-0x000_80_i8" }); - check(Ok(SIntValue::from(-128i8)), json! { "-0o002_00_hdl_i8" }); - check(Ok(SIntValue::from(-128i8)), json! { "-0b1__000_0000_i8" }); - check(Ok(UInt[3].from_int_wrapping(5)), json! { " + 0x5_u3 " }); - check( - Ok(UInt[12].from_int_wrapping(0x1123)), - json! { "0x1_2_3_hdl_u12" }, - ); - check(Ok(SInt[12].from_int_wrapping(0xFEE)), json! { "-0x12_i12" }); - check( - Ok(SInt[12].from_int_wrapping(0x7EE)), - json! { " + \t0x7__E_e_i012\n" }, - ); - check(Ok(SInt[0].from_int_wrapping(0)), json! { "-0i0" }); - check(Ok(SInt[1].from_int_wrapping(0)), json! { "-0i1" }); - check(Ok(SInt[0].from_int_wrapping(0)), json! { "-0x0i0" }); - check(Ok(SInt[1].from_int_wrapping(0)), json! { "-0x0i1" }); - } } diff --git a/crates/fayalite/src/int/uint_in_range.rs b/crates/fayalite/src/int/uint_in_range.rs deleted file mode 100644 index 970a439..0000000 --- a/crates/fayalite/src/int/uint_in_range.rs +++ /dev/null @@ -1,656 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - bundle::{Bundle, BundleField, BundleType, BundleTypePropertiesBuilder, NoBuilder}, - expr::{ - CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, - ops::{ExprCastTo, ExprPartialEq, ExprPartialOrd}, - }, - int::{Bool, DynSize, KnownSize, Size, SizeType, UInt, UIntType}, - intern::{Intern, InternSlice, Interned}, - phantom_const::PhantomConst, - sim::value::{SimValue, SimValuePartialEq, ToSimValueWithType}, - source_location::SourceLocation, - ty::{ - CanonicalType, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, - StaticType, Type, TypeProperties, impl_match_variant_as_self, - }, -}; -use bitvec::{order::Lsb0, view::BitView}; -use serde::{ - Deserialize, Deserializer, Serialize, Serializer, - de::{Error, Visitor, value::UsizeDeserializer}, -}; -use std::{fmt, marker::PhantomData, ops::Index}; - -const UINT_IN_RANGE_TYPE_FIELD_NAMES: [&'static str; 2] = ["value", "range"]; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] -pub struct UIntInRangeMaskType { - value: Bool, - range: PhantomConstRangeMaskType, -} - -impl Type for UIntInRangeMaskType { - type BaseType = Bundle; - type MaskType = Self; - type SimValue = bool; - impl_match_variant_as_self!(); - - fn mask_type(&self) -> Self::MaskType { - *self - } - - fn canonical(&self) -> CanonicalType { - CanonicalType::Bundle(Bundle::new(self.fields())) - } - - fn from_canonical(canonical_type: CanonicalType) -> Self { - let fields = Bundle::from_canonical(canonical_type).fields(); - let [ - BundleField { - name: value_name, - flipped: false, - ty: value, - }, - BundleField { - name: range_name, - flipped: false, - ty: range, - }, - ] = *fields - else { - panic!("expected UIntInRangeMaskType"); - }; - assert_eq!([&*value_name, &*range_name], UINT_IN_RANGE_TYPE_FIELD_NAMES); - let value = Bool::from_canonical(value); - let range = PhantomConstRangeMaskType::from_canonical(range); - Self { value, range } - } - - fn source_location() -> SourceLocation { - SourceLocation::builtin() - } - - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - Bool.sim_value_from_opaque(opaque) - } - - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ) { - Bool.sim_value_clone_from_opaque(value, opaque); - } - - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> OpaqueSimValueWritten<'w> { - Bool.sim_value_to_opaque(value, writer) - } -} - -impl BundleType for UIntInRangeMaskType { - type Builder = NoBuilder; - type FilledBuilder = Expr; - - fn fields(&self) -> Interned<[BundleField]> { - let [value_name, range_name] = UINT_IN_RANGE_TYPE_FIELD_NAMES; - let Self { value, range } = self; - [ - BundleField { - name: value_name.intern(), - flipped: false, - ty: value.canonical(), - }, - BundleField { - name: range_name.intern(), - flipped: false, - ty: range.canonical(), - }, - ] - .intern_slice() - } -} - -impl StaticType for UIntInRangeMaskType { - const TYPE: Self = Self { - value: Bool, - range: PhantomConstRangeMaskType::TYPE, - }; - const MASK_TYPE: Self::MaskType = Self::TYPE; - const TYPE_PROPERTIES: TypeProperties = BundleTypePropertiesBuilder::new() - .field(false, Bool::TYPE_PROPERTIES) - .field(false, PhantomConstRangeMaskType::TYPE_PROPERTIES) - .finish(); - const MASK_TYPE_PROPERTIES: TypeProperties = Self::TYPE_PROPERTIES; -} - -impl ToSimValueWithType for bool { - fn to_sim_value_with_type(&self, ty: UIntInRangeMaskType) -> SimValue { - SimValue::from_value(ty, *self) - } -} - -impl ExprCastTo for UIntInRangeMaskType { - fn cast_to(src: Expr, to_type: Bool) -> Expr { - src.cast_to_bits().cast_to(to_type) - } -} - -impl ExprCastTo for Bool { - fn cast_to(src: Expr, to_type: UIntInRangeMaskType) -> Expr { - src.cast_to_static::>().cast_bits_to(to_type) - } -} - -impl ExprPartialEq for UIntInRangeMaskType { - fn cmp_eq(lhs: Expr, rhs: Expr) -> Expr { - lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) - } - fn cmp_ne(lhs: Expr, rhs: Expr) -> Expr { - lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits()) - } -} - -impl SimValuePartialEq for UIntInRangeMaskType { - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - **this == **other - } -} - -type PhantomConstRangeMaskType = > as Type>::MaskType; - -#[derive(Default, Copy, Clone, Debug)] -struct RangeParseError; - -macro_rules! define_uint_in_range_type { - ( - $UIntInRange:ident, - $UIntInRangeType:ident, - $UIntInRangeTypeWithoutGenerics:ident, - $UIntInRangeTypeWithStart:ident, - $SerdeRange:ident, - $range_operator_str:literal, - |$uint_range_usize_start:ident, $uint_range_usize_end:ident| $uint_range_usize:expr, - ) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - struct $SerdeRange { - start: Start::SizeType, - end: End::SizeType, - } - - impl Default for $SerdeRange { - fn default() -> Self { - Self { - start: Start::SIZE, - end: End::SIZE, - } - } - } - - impl std::str::FromStr for $SerdeRange { - type Err = RangeParseError; - - fn from_str(s: &str) -> Result { - let Some((start, end)) = s.split_once($range_operator_str) else { - return Err(RangeParseError); - }; - if start.is_empty() - || start.bytes().any(|b| !b.is_ascii_digit()) - || end.is_empty() - || end.bytes().any(|b| !b.is_ascii_digit()) - { - return Err(RangeParseError); - } - let start = start.parse().map_err(|_| RangeParseError)?; - let end = end.parse().map_err(|_| RangeParseError)?; - let retval = Self { start, end }; - if retval.is_empty() { - Err(RangeParseError) - } else { - Ok(retval) - } - } - } - - impl fmt::Display for $SerdeRange { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { start, end } = *self; - write!( - f, - "{}{}{}", - Start::as_usize(start), - $range_operator_str, - End::as_usize(end), - ) - } - } - - impl Serialize for $SerdeRange { - fn serialize(&self, serializer: S) -> Result { - serializer.collect_str(self) - } - } - - impl<'de, Start: Size, End: Size> Deserialize<'de> for $SerdeRange { - fn deserialize>(deserializer: D) -> Result { - struct SerdeRangeVisitor(PhantomData<(Start, End)>); - impl<'de, Start: Size, End: Size> Visitor<'de> for SerdeRangeVisitor { - type Value = $SerdeRange; - - fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("a string with format \"")?; - if let Some(start) = Start::KNOWN_VALUE { - write!(f, "{start}")?; - } else { - f.write_str("")?; - }; - f.write_str($range_operator_str)?; - if let Some(end) = End::KNOWN_VALUE { - write!(f, "{end}")?; - } else { - f.write_str("")?; - }; - f.write_str("\" that is a non-empty range") - } - - fn visit_str(self, v: &str) -> Result { - let $SerdeRange:: { start, end } = - v.parse().map_err(|_| { - Error::invalid_value(serde::de::Unexpected::Str(v), &self) - })?; - let start = - Start::SizeType::deserialize(UsizeDeserializer::::new(start))?; - let end = End::SizeType::deserialize(UsizeDeserializer::::new(end))?; - Ok($SerdeRange { start, end }) - } - - fn visit_bytes(self, v: &[u8]) -> Result { - match std::str::from_utf8(v) { - Ok(v) => self.visit_str(v), - Err(_) => { - Err(Error::invalid_value(serde::de::Unexpected::Bytes(v), &self)) - } - } - } - } - deserializer.deserialize_str(SerdeRangeVisitor(PhantomData)) - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash)] - pub struct $UIntInRangeType { - value: UInt, - range: PhantomConst<$SerdeRange>, - } - - impl $UIntInRangeType { - fn from_phantom_const_range(range: PhantomConst<$SerdeRange>) -> Self { - let $SerdeRange { start, end } = *range.get(); - let $uint_range_usize_start = Start::as_usize(start); - let $uint_range_usize_end = End::as_usize(end); - Self { - value: $uint_range_usize, - range, - } - } - pub fn new(start: Start::SizeType, end: End::SizeType) -> Self { - Self::from_phantom_const_range(PhantomConst::new( - $SerdeRange { start, end }.intern_sized(), - )) - } - pub fn bit_width(self) -> usize { - self.value.width() - } - pub fn start(self) -> Start::SizeType { - self.range.get().start - } - pub fn end(self) -> End::SizeType { - self.range.get().end - } - } - - impl fmt::Debug for $UIntInRangeType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { value, range } = self; - let $SerdeRange { start, end } = *range.get(); - f.debug_struct(&format!( - "{}<{}, {}>", - stringify!($UIntInRange), - Start::as_usize(start), - End::as_usize(end), - )) - .field("value", value) - .finish_non_exhaustive() - } - } - - impl Type for $UIntInRangeType { - type BaseType = Bundle; - type MaskType = UIntInRangeMaskType; - type SimValue = usize; - impl_match_variant_as_self!(); - - fn mask_type(&self) -> Self::MaskType { - UIntInRangeMaskType::TYPE - } - - fn canonical(&self) -> CanonicalType { - CanonicalType::Bundle(Bundle::new(self.fields())) - } - - fn from_canonical(canonical_type: CanonicalType) -> Self { - let fields = Bundle::from_canonical(canonical_type).fields(); - let [ - BundleField { - name: value_name, - flipped: false, - ty: value, - }, - BundleField { - name: range_name, - flipped: false, - ty: range, - }, - ] = *fields - else { - panic!("expected {}", stringify!($UIntInRange)); - }; - assert_eq!([&*value_name, &*range_name], UINT_IN_RANGE_TYPE_FIELD_NAMES); - let value = UInt::from_canonical(value); - let range = PhantomConst::<$SerdeRange>::from_canonical(range); - let retval = Self::from_phantom_const_range(range); - assert_eq!(retval, Self { value, range }); - retval - } - - fn source_location() -> SourceLocation { - SourceLocation::builtin() - } - - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - assert_eq!(opaque.size(), self.value.type_properties().size()); - let mut retval = 0usize; - retval.view_bits_mut::()[..opaque.bit_width()] - .clone_from_bitslice(opaque.bits()); - retval - } - - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ) { - *value = self.sim_value_from_opaque(opaque); - } - - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> OpaqueSimValueWritten<'w> { - writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice( - &value.view_bits::()[..self.value.width()], - )) - } - } - - impl BundleType for $UIntInRangeType { - type Builder = NoBuilder; - type FilledBuilder = Expr; - - fn fields(&self) -> Interned<[BundleField]> { - let [value_name, range_name] = UINT_IN_RANGE_TYPE_FIELD_NAMES; - let Self { value, range } = self; - [ - BundleField { - name: value_name.intern(), - flipped: false, - ty: value.canonical(), - }, - BundleField { - name: range_name.intern(), - flipped: false, - ty: range.canonical(), - }, - ] - .intern_slice() - } - } - - impl Default for $UIntInRangeType { - fn default() -> Self { - Self::TYPE - } - } - - impl StaticType for $UIntInRangeType { - const TYPE: Self = { - let $uint_range_usize_start = Start::VALUE; - let $uint_range_usize_end = End::VALUE; - Self { - value: $uint_range_usize, - range: PhantomConst::<$SerdeRange>::TYPE, - } - }; - const MASK_TYPE: Self::MaskType = UIntInRangeMaskType::TYPE; - const TYPE_PROPERTIES: TypeProperties = BundleTypePropertiesBuilder::new() - .field(false, Self::TYPE.value.type_properties_dyn()) - .field( - false, - PhantomConst::<$SerdeRange>::TYPE_PROPERTIES, - ) - .finish(); - const MASK_TYPE_PROPERTIES: TypeProperties = UIntInRangeMaskType::TYPE_PROPERTIES; - } - - impl ToSimValueWithType<$UIntInRangeType> for usize { - fn to_sim_value_with_type( - &self, - ty: $UIntInRangeType, - ) -> SimValue<$UIntInRangeType> { - SimValue::from_value(ty, *self) - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] - pub struct $UIntInRangeTypeWithoutGenerics; - - #[allow(non_upper_case_globals)] - pub const $UIntInRangeType: $UIntInRangeTypeWithoutGenerics = - $UIntInRangeTypeWithoutGenerics; - - impl Index for $UIntInRangeTypeWithoutGenerics { - type Output = $UIntInRangeTypeWithStart; - - fn index(&self, start: StartSize) -> &Self::Output { - Interned::into_inner($UIntInRangeTypeWithStart(start).intern_sized()) - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub struct $UIntInRangeTypeWithStart(Start::SizeType); - - impl, End: Size> - Index for $UIntInRangeTypeWithStart - { - type Output = $UIntInRangeType; - - fn index(&self, end: EndSize) -> &Self::Output { - Interned::into_inner($UIntInRangeType::new(self.0, end).intern_sized()) - } - } - - impl ExprCastTo> - for $UIntInRangeType - { - fn cast_to(src: Expr, to_type: UIntType) -> Expr> { - src.cast_to_bits().cast_to(to_type) - } - } - - impl ExprCastTo<$UIntInRangeType> - for UIntType - { - fn cast_to( - src: Expr, - to_type: $UIntInRangeType, - ) -> Expr<$UIntInRangeType> { - src.cast_to(to_type.value).cast_bits_to(to_type) - } - } - - impl - ExprPartialEq<$UIntInRangeType> - for $UIntInRangeType - { - fn cmp_eq( - lhs: Expr, - rhs: Expr<$UIntInRangeType>, - ) -> Expr { - lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits()) - } - fn cmp_ne( - lhs: Expr, - rhs: Expr<$UIntInRangeType>, - ) -> Expr { - lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits()) - } - } - - impl - ExprPartialOrd<$UIntInRangeType> - for $UIntInRangeType - { - fn cmp_lt( - lhs: Expr, - rhs: Expr<$UIntInRangeType>, - ) -> Expr { - lhs.cast_to_bits().cmp_lt(rhs.cast_to_bits()) - } - fn cmp_le( - lhs: Expr, - rhs: Expr<$UIntInRangeType>, - ) -> Expr { - lhs.cast_to_bits().cmp_le(rhs.cast_to_bits()) - } - fn cmp_gt( - lhs: Expr, - rhs: Expr<$UIntInRangeType>, - ) -> Expr { - lhs.cast_to_bits().cmp_gt(rhs.cast_to_bits()) - } - fn cmp_ge( - lhs: Expr, - rhs: Expr<$UIntInRangeType>, - ) -> Expr { - lhs.cast_to_bits().cmp_ge(rhs.cast_to_bits()) - } - } - - impl - SimValuePartialEq<$UIntInRangeType> - for $UIntInRangeType - { - fn sim_value_eq( - this: &SimValue, - other: &SimValue<$UIntInRangeType>, - ) -> bool { - **this == **other - } - } - - impl ExprPartialEq> - for $UIntInRangeType - { - fn cmp_eq(lhs: Expr, rhs: Expr>) -> Expr { - lhs.cast_to_bits().cmp_eq(rhs) - } - fn cmp_ne(lhs: Expr, rhs: Expr>) -> Expr { - lhs.cast_to_bits().cmp_ne(rhs) - } - } - - impl ExprPartialEq<$UIntInRangeType> - for UIntType - { - fn cmp_eq(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { - lhs.cmp_eq(rhs.cast_to_bits()) - } - fn cmp_ne(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { - lhs.cmp_ne(rhs.cast_to_bits()) - } - } - - impl ExprPartialOrd> - for $UIntInRangeType - { - fn cmp_lt(lhs: Expr, rhs: Expr>) -> Expr { - lhs.cast_to_bits().cmp_lt(rhs) - } - fn cmp_le(lhs: Expr, rhs: Expr>) -> Expr { - lhs.cast_to_bits().cmp_le(rhs) - } - fn cmp_gt(lhs: Expr, rhs: Expr>) -> Expr { - lhs.cast_to_bits().cmp_gt(rhs) - } - fn cmp_ge(lhs: Expr, rhs: Expr>) -> Expr { - lhs.cast_to_bits().cmp_ge(rhs) - } - } - - impl ExprPartialOrd<$UIntInRangeType> - for UIntType - { - fn cmp_lt(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { - lhs.cmp_lt(rhs.cast_to_bits()) - } - fn cmp_le(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { - lhs.cmp_le(rhs.cast_to_bits()) - } - fn cmp_gt(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { - lhs.cmp_gt(rhs.cast_to_bits()) - } - fn cmp_ge(lhs: Expr, rhs: Expr<$UIntInRangeType>) -> Expr { - lhs.cmp_ge(rhs.cast_to_bits()) - } - } - }; -} - -define_uint_in_range_type! { - UIntInRange, - UIntInRangeType, - UIntInRangeTypeWithoutGenerics, - UIntInRangeTypeWithStart, - SerdeRange, - "..", - |start, end| UInt::range_usize(start..end), -} - -define_uint_in_range_type! { - UIntInRangeInclusive, - UIntInRangeInclusiveType, - UIntInRangeInclusiveTypeWithoutGenerics, - UIntInRangeInclusiveTypeWithStart, - SerdeRangeInclusive, - "..=", - |start, end| UInt::range_inclusive_usize(start..=end), -} - -impl SerdeRange { - fn is_empty(self) -> bool { - self.start >= self.end - } -} - -impl SerdeRangeInclusive { - fn is_empty(self) -> bool { - self.start > self.end - } -} diff --git a/crates/fayalite/src/intern.rs b/crates/fayalite/src/intern.rs index b68140b..3780ad3 100644 --- a/crates/fayalite/src/intern.rs +++ b/crates/fayalite/src/intern.rs @@ -1,25 +1,23 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information #![allow(clippy::type_complexity)] -use crate::{intern::type_map::TypeIdMap, util::DefaultBuildHasher}; +use crate::intern::type_map::TypeIdMap; use bitvec::{ptr::BitPtr, slice::BitSlice, vec::BitVec}; -use hashbrown::HashTable; +use hashbrown::{hash_map::RawEntryMut, HashMap, HashTable}; use serde::{Deserialize, Serialize}; use std::{ any::{Any, TypeId}, borrow::{Borrow, Cow}, cmp::Ordering, - ffi::{OsStr, OsString}, fmt, hash::{BuildHasher, Hash, Hasher}, iter::FusedIterator, marker::PhantomData, ops::Deref, - path::{Path, PathBuf}, sync::{Mutex, RwLock}, }; -mod type_map; +pub mod type_map; pub trait LazyInternedTrait: Send + Sync + Any { fn get(&self) -> Interned; @@ -289,266 +287,15 @@ impl InternedCompare for BitSlice { } } -/// Safety: `as_bytes` and `from_bytes_unchecked` must return the same pointer as the input. -/// all values returned by `as_bytes` must be valid to pass to `from_bytes_unchecked`. -/// `into_bytes` must return the exact same thing as `as_bytes`. -/// `Interned` must contain the exact same references as `Interned<[u8]>`, -/// so they can be safely interconverted without needing re-interning. -unsafe trait InternStrLike: ToOwned { - fn as_bytes(this: &Self) -> &[u8]; - fn into_bytes(this: Self::Owned) -> Vec; - /// Safety: `bytes` must be a valid sequence of bytes for this type. All UTF-8 sequences are valid. - unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self; -} - -macro_rules! impl_intern_str_like { - ($ty:ty, owned = $Owned:ty) => { - impl InternedCompare for $ty { - type InternedCompareKey = PtrEqWithMetadata<[u8]>; - fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { - PtrEqWithMetadata(InternStrLike::as_bytes(this)) - } - } - impl Intern for $ty { - fn intern(&self) -> Interned { - Self::intern_cow(Cow::Borrowed(self)) - } - fn intern_cow(this: Cow<'_, Self>) -> Interned { - Interned::cast_unchecked( - <[u8]>::intern_cow(match this { - Cow::Borrowed(v) => Cow::Borrowed(::as_bytes(v)), - Cow::Owned(v) => { - // verify $Owned is correct - let v: $Owned = v; - Cow::Owned(::into_bytes(v)) - } - }), - // Safety: guaranteed safe because we got the bytes from `as_bytes`/`into_bytes` - |v| unsafe { ::from_bytes_unchecked(v) }, - ) - } - } - impl Default for Interned<$ty> { - fn default() -> Self { - // Safety: safe because the empty sequence is valid UTF-8 - unsafe { <$ty as InternStrLike>::from_bytes_unchecked(&[]) }.intern() - } - } - impl<'de> Deserialize<'de> for Interned<$ty> { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - Cow::<'de, $ty>::deserialize(deserializer).map(Intern::intern_cow) - } - } - impl From<$Owned> for Interned<$ty> { - fn from(v: $Owned) -> Self { - v.intern_deref() - } - } - impl From> for $Owned { - fn from(v: Interned<$ty>) -> Self { - Interned::into_inner(v).into() - } - } - impl From> for Box<$ty> { - fn from(v: Interned<$ty>) -> Self { - Interned::into_inner(v).into() - } - } - }; -} - -// Safety: satisfies `InternStrLike`'s requirements where the valid sequences for `from_bytes_unchecked` matches `str` -unsafe impl InternStrLike for str { - fn as_bytes(this: &Self) -> &[u8] { - this.as_bytes() - } - fn into_bytes(this: Self::Owned) -> Vec { - this.into_bytes() - } - unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { - // Safety: `bytes` is guaranteed UTF-8 by the caller - unsafe { str::from_utf8_unchecked(bytes) } - } -} - -impl_intern_str_like!(str, owned = String); - -// Safety: satisfies `InternStrLike`'s requirements where the valid sequences for `from_bytes_unchecked` matches `OsStr` -unsafe impl InternStrLike for OsStr { - fn as_bytes(this: &Self) -> &[u8] { - this.as_encoded_bytes() - } - fn into_bytes(this: Self::Owned) -> Vec { - this.into_encoded_bytes() - } - unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { - // Safety: `bytes` is guaranteed valid for `OsStr` by the caller - unsafe { OsStr::from_encoded_bytes_unchecked(bytes) } - } -} - -impl_intern_str_like!(OsStr, owned = OsString); - -// Safety: satisfies `InternStrLike`'s requirements where the valid sequences for `from_bytes_unchecked` matches `OsStr` -unsafe impl InternStrLike for Path { - fn as_bytes(this: &Self) -> &[u8] { - this.as_os_str().as_encoded_bytes() - } - fn into_bytes(this: Self::Owned) -> Vec { - this.into_os_string().into_encoded_bytes() - } - unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self { - // Safety: `bytes` is guaranteed valid for `OsStr` by the caller - unsafe { Path::new(OsStr::from_encoded_bytes_unchecked(bytes)) } - } -} - -impl_intern_str_like!(Path, owned = PathBuf); - -impl Interned { - pub fn from_utf8(v: Interned<[u8]>) -> Result { - Interned::try_cast_unchecked(v, str::from_utf8) - } - pub fn as_interned_bytes(self) -> Interned<[u8]> { - Interned::cast_unchecked(self, str::as_bytes) - } - pub fn as_interned_os_str(self) -> Interned { - Interned::cast_unchecked(self, AsRef::as_ref) - } - pub fn as_interned_path(self) -> Interned { - Interned::cast_unchecked(self, AsRef::as_ref) - } -} - -impl From> for Interned { - fn from(value: Interned) -> Self { - value.as_interned_os_str() - } -} - -impl From> for Interned { - fn from(value: Interned) -> Self { - value.as_interned_path() - } -} - -impl Interned { - pub fn as_interned_encoded_bytes(self) -> Interned<[u8]> { - Interned::cast_unchecked(self, OsStr::as_encoded_bytes) - } - pub fn to_interned_str(self) -> Option> { - Interned::try_cast_unchecked(self, |v| v.to_str().ok_or(())).ok() - } - pub fn display(self) -> std::ffi::os_str::Display<'static> { - Self::into_inner(self).display() - } - pub fn as_interned_path(self) -> Interned { - Interned::cast_unchecked(self, AsRef::as_ref) - } -} - -impl From> for Interned { - fn from(value: Interned) -> Self { - value.as_interned_path() - } -} - -impl Interned { - pub fn as_interned_os_str(self) -> Interned { - Interned::cast_unchecked(self, AsRef::as_ref) - } - pub fn to_interned_str(self) -> Option> { - Interned::try_cast_unchecked(self, |v| v.to_str().ok_or(())).ok() - } - pub fn display(self) -> std::path::Display<'static> { - Self::into_inner(self).display() - } - pub fn interned_file_name(self) -> Option> { - Some(self.file_name()?.intern()) - } -} - -impl From> for Interned { - fn from(value: Interned) -> Self { - value.as_interned_os_str() - } -} - -pub trait InternSlice: Sized { - type Element: 'static + Send + Sync + Clone + Hash + Eq; - fn intern_slice(self) -> Interned<[Self::Element]>; -} - -impl InternSlice for Box<[T]> { - type Element = T; - fn intern_slice(self) -> Interned<[Self::Element]> { - self.into_vec().intern_slice() - } -} - -impl InternSlice for Vec { - type Element = T; - fn intern_slice(self) -> Interned<[Self::Element]> { - self.intern_deref() - } -} - -impl InternSlice for &'_ [T] { - type Element = T; - fn intern_slice(self) -> Interned<[Self::Element]> { - self.intern() - } -} - -impl InternSlice for &'_ mut [T] { - type Element = T; - fn intern_slice(self) -> Interned<[Self::Element]> { - self.intern() - } -} - -impl InternSlice for [T; N] { - type Element = T; - fn intern_slice(self) -> Interned<[Self::Element]> { - (&self).intern_slice() - } -} - -impl InternSlice for Box<[T; N]> { - type Element = T; - fn intern_slice(self) -> Interned<[Self::Element]> { - let this: Box<[T]> = self; - this.intern_slice() - } -} - -impl InternSlice for &'_ [T; N] { - type Element = T; - fn intern_slice(self) -> Interned<[Self::Element]> { - let this: &[T] = self; - this.intern() - } -} - -impl InternSlice for &'_ mut [T; N] { - type Element = T; - fn intern_slice(self) -> Interned<[Self::Element]> { - let this: &[T] = self; - this.intern() +impl InternedCompare for str { + type InternedCompareKey = PtrEqWithMetadata; + fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { + PtrEqWithMetadata(this) } } pub trait Intern: Any + Send + Sync { fn intern(&self) -> Interned; - fn intern_deref(self) -> Interned - where - Self: Sized + Deref>, - { - Self::Target::intern_owned(self) - } fn intern_sized(self) -> Interned where Self: Clone, @@ -569,37 +316,8 @@ pub trait Intern: Any + Send + Sync { } } -impl From> for Interned { - fn from(value: Cow<'_, T>) -> Self { - Intern::intern_cow(value) - } -} - -impl From<&'_ T> for Interned { - fn from(value: &'_ T) -> Self { - Intern::intern(value) - } -} - -impl From for Interned { - fn from(value: T) -> Self { - Intern::intern_sized(value) - } -} - -impl From> for Cow<'_, T> { - fn from(value: Interned) -> Self { - Cow::Borrowed(Interned::into_inner(value)) - } -} - -struct InternerState { - table: HashTable<&'static T>, - hasher: DefaultBuildHasher, -} - pub struct Interner { - state: Mutex>, + map: Mutex>, } impl Interner { @@ -612,10 +330,7 @@ impl Interner { impl Default for Interner { fn default() -> Self { Self { - state: Mutex::new(InternerState { - table: HashTable::new(), - hasher: Default::default(), - }), + map: Default::default(), } } } @@ -626,16 +341,17 @@ impl Interner { alloc: F, value: Cow<'_, T>, ) -> Interned { - let mut state = self.state.lock().unwrap(); - let InternerState { table, hasher } = &mut *state; - let inner = *table - .entry( - hasher.hash_one(&*value), - |k| **k == *value, - |k| hasher.hash_one(&**k), - ) - .or_insert_with(|| alloc(value)) - .get(); + let mut map = self.map.lock().unwrap(); + let hasher = map.hasher().clone(); + let hash = hasher.hash_one(&*value); + let inner = match map.raw_entry_mut().from_hash(hash, |k| **k == *value) { + RawEntryMut::Occupied(entry) => *entry.key(), + RawEntryMut::Vacant(entry) => { + *entry + .insert_with_hasher(hash, alloc(value), (), |k| hasher.hash_one(&**k)) + .0 + } + }; Interned { inner } } } @@ -658,6 +374,12 @@ impl Interner { } } +impl Interner { + fn intern_str(&self, value: Cow<'_, str>) -> Interned { + self.intern(|value| value.into_owned().leak(), value) + } +} + pub struct Interned { inner: &'static T, } @@ -687,12 +409,6 @@ forward_fmt_trait!(Pointer); forward_fmt_trait!(UpperExp); forward_fmt_trait!(UpperHex); -impl, U: ?Sized> AsRef for Interned { - fn as_ref(&self) -> &U { - T::as_ref(self) - } -} - #[derive(Clone, Debug)] pub struct InternedSliceIter { slice: Interned<[T]>, @@ -762,57 +478,6 @@ where } } -impl FromIterator for Interned -where - String: FromIterator, -{ - fn from_iter>(iter: T) -> Self { - String::from_iter(iter).intern_deref() - } -} - -impl FromIterator for Interned -where - PathBuf: FromIterator, -{ - fn from_iter>(iter: T) -> Self { - PathBuf::from_iter(iter).intern_deref() - } -} - -impl FromIterator for Interned -where - OsString: FromIterator, -{ - fn from_iter>(iter: T) -> Self { - OsString::from_iter(iter).intern_deref() - } -} - -impl From> for clap::builder::Str { - fn from(value: Interned) -> Self { - Interned::into_inner(value).into() - } -} - -impl From> for clap::builder::OsStr { - fn from(value: Interned) -> Self { - Interned::into_inner(value).into() - } -} - -impl From> for clap::builder::StyledStr { - fn from(value: Interned) -> Self { - Interned::into_inner(value).into() - } -} - -impl From> for clap::Id { - fn from(value: Interned) -> Self { - Interned::into_inner(value).into() - } -} - impl From> for Vec { fn from(value: Interned<[T]>) -> Self { Vec::from(&*value) @@ -825,12 +490,24 @@ impl From> for Box<[T]> { } } +impl From> for String { + fn from(value: Interned) -> Self { + String::from(&*value) + } +} + impl Default for Interned<[I]> where [I]: Intern, { fn default() -> Self { - Intern::intern(&[]) + [][..].intern() + } +} + +impl Default for Interned { + fn default() -> Self { + "".intern() } } @@ -961,6 +638,15 @@ impl<'de> Deserialize<'de> for Interned { } } +impl<'de> Deserialize<'de> for Interned { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + String::deserialize(deserializer).map(Intern::intern_owned) + } +} + impl Intern for T { fn intern(&self) -> Interned { Self::intern_cow(Cow::Borrowed(self)) @@ -1021,6 +707,26 @@ impl Intern for BitSlice { } } +impl Intern for str { + fn intern(&self) -> Interned { + Self::intern_cow(Cow::Borrowed(self)) + } + + fn intern_owned(this: ::Owned) -> Interned + where + Self: ToOwned, + { + Self::intern_cow(Cow::Owned(this)) + } + + fn intern_cow(this: Cow<'_, Self>) -> Interned + where + Self: ToOwned, + { + Interner::get().intern_str(this) + } +} + pub trait MemoizeGeneric: 'static + Send + Sync + Hash + Eq + Copy { type InputRef<'a>: 'a + Send + Sync + Hash + Copy; type InputOwned: 'static + Send + Sync; @@ -1036,7 +742,7 @@ pub trait MemoizeGeneric: 'static + Send + Sync + Hash + Eq + Copy { fn get_cow(self, input: Self::InputCow<'_>) -> Self::Output { static TYPE_ID_MAP: TypeIdMap = TypeIdMap::new(); let map: &RwLock<( - DefaultBuildHasher, + hashbrown::hash_map::DefaultHashBuilder, HashTable<(Self, Self::InputOwned, Self::Output)>, )> = TYPE_ID_MAP.get_or_insert_default(); fn hash_eq_key<'a, 'b, T: MemoizeGeneric>( diff --git a/crates/fayalite/src/intern/type_map.rs b/crates/fayalite/src/intern/type_map.rs index 945116b..48433af 100644 --- a/crates/fayalite/src/intern/type_map.rs +++ b/crates/fayalite/src/intern/type_map.rs @@ -1,8 +1,10 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information +use hashbrown::HashMap; use std::{ any::{Any, TypeId}, hash::{BuildHasher, Hasher}, + ptr::NonNull, sync::RwLock, }; @@ -73,36 +75,59 @@ impl BuildHasher for TypeIdBuildHasher { } } -pub(crate) struct TypeIdMap( - RwLock>, -); +struct Value(NonNull); + +impl Value { + unsafe fn get_transmute_lifetime<'b>(&self) -> &'b (dyn Any + Send + Sync) { + unsafe { &*self.0.as_ptr() } + } + fn new(v: Box) -> Self { + unsafe { Self(NonNull::new_unchecked(Box::into_raw(v))) } + } +} + +unsafe impl Send for Value {} +unsafe impl Sync for Value {} + +impl Drop for Value { + fn drop(&mut self) { + unsafe { std::ptr::drop_in_place(self.0.as_ptr()) } + } +} + +pub struct TypeIdMap(RwLock>); impl TypeIdMap { - pub(crate) const fn new() -> Self { - Self(RwLock::new(hashbrown::HashMap::with_hasher( - TypeIdBuildHasher, - ))) + pub const fn new() -> Self { + Self(RwLock::new(HashMap::with_hasher(TypeIdBuildHasher))) } #[cold] - fn insert_slow( + unsafe fn insert_slow( &self, type_id: TypeId, make: fn() -> Box, - ) -> &'static (dyn Any + Sync + Send) { - let value = Box::leak(make()); + ) -> &(dyn Any + Sync + Send) { + let value = Value::new(make()); let mut write_guard = self.0.write().unwrap(); - *write_guard.entry(type_id).or_insert(value) + unsafe { + write_guard + .entry(type_id) + .or_insert(value) + .get_transmute_lifetime() + } } - pub(crate) fn get_or_insert_default(&self) -> &T { + pub fn get_or_insert_default(&self) -> &T { let type_id = TypeId::of::(); let read_guard = self.0.read().unwrap(); - let retval = read_guard.get(&type_id).map(|v| *v); + let retval = read_guard + .get(&type_id) + .map(|v| unsafe { Value::get_transmute_lifetime(v) }); drop(read_guard); let retval = match retval { Some(retval) => retval, - None => self.insert_slow(type_id, move || Box::new(T::default())), + None => unsafe { self.insert_slow(type_id, move || Box::new(T::default())) }, }; - retval.downcast_ref().expect("known to have correct TypeId") + unsafe { &*(retval as *const dyn Any as *const T) } } } diff --git a/crates/fayalite/src/lib.rs b/crates/fayalite/src/lib.rs index 96ee1f7..88fe169 100644 --- a/crates/fayalite/src/lib.rs +++ b/crates/fayalite/src/lib.rs @@ -4,18 +4,6 @@ // TODO: enable: // #![warn(missing_docs)] -#![deny( - rustdoc::bare_urls, - rustdoc::broken_intra_doc_links, - rustdoc::invalid_codeblock_attributes, - rustdoc::invalid_html_tags, - rustdoc::invalid_rust_codeblocks, - rustdoc::private_doc_tests, - rustdoc::private_intra_doc_links, - rustdoc::redundant_explicit_links, - rustdoc::unescaped_backticks -)] - //! [Main Documentation][_docs] extern crate self as fayalite; @@ -86,139 +74,8 @@ macro_rules! __cfg_expansion_helper { pub use fayalite_proc_macros::hdl_module; #[doc(inline)] -/// The `#[hdl]` attribute is supported on several different kinds of [Rust Items](https://doc.rust-lang.org/reference/items.html): -/// -/// # Functions and Methods -/// Enable's the stuff that you can use inside a [module's body](crate::_docs::modules::module_bodies), -/// but without being a module or changing the function's signature. -/// The only exception is that you can't use stuff that requires the automatically-provided `m` variable. -/// -/// # Structs -// TODO: expand on struct docs -/// e.g.: -/// ``` -/// # use fayalite::prelude::*; -/// # #[hdl] -/// # pub struct OtherStruct {} -/// #[hdl] -/// pub struct MyStruct { -/// #[hdl(flip)] -/// pub a: UInt<5>, -/// pub b: Bool, -/// #[hdl(flip)] -/// pub c: OtherStruct, -/// } -/// ``` -/// -/// # Enums -// TODO: expand on enum docs -/// e.g.: -/// ``` -/// # use fayalite::prelude::*; -/// # #[hdl] -/// # pub struct MyStruct {} -/// #[hdl] -/// pub enum MyEnum { -/// A(UInt<3>), -/// B, -/// C(MyStruct), -/// } -/// ``` -/// -/// # Type Aliases -/// -/// There's three different ways you can create a type alias: -/// -/// # Normal Type Alias -/// -/// This works exactly how you'd expect: -/// ``` -/// # use fayalite::prelude::*; -/// # #[hdl] -/// # pub struct MyStruct { -/// # v: T, -/// # } -/// #[hdl] -/// pub type MyType = MyStruct; -/// -/// // you can then use Fayalite's standard syntax for creating dynamic types at runtime: -/// -/// let ty = MyType[UInt[3]]; -/// assert_eq!(ty, MyStruct[UInt[3]]); -/// ``` -/// -/// # Type Alias that gets a [`Type`] from a [`PhantomConst`] -/// -/// This allows you to use some computed property of a [`PhantomConst`] to get a [`Type`] that you can use in other #[hdl] types. -/// -/// ``` -/// # use fayalite::{intern::Intern, prelude::*}; -/// #[derive(Clone, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)] -/// pub struct Config { -/// pub foo: usize, -/// pub bar: Bundle, -/// } -/// -/// // the expression inside `get` is called with `Interned` and returns `Array` -/// #[hdl(get(|config| Array[config.bar][config.foo]))] -/// pub type GetMyArray> = Array; -/// -/// // you can then use it in other types: -/// -/// #[hdl(no_static)] -/// pub struct WrapMyArray> { -/// pub my_array: GetMyArray

, -/// } -/// -/// // you can then use Fayalite's standard syntax for creating dynamic types at runtime: -/// let bar = Bundle::new(Default::default()); -/// let config = PhantomConst::new(Config { foo: 12, bar }.intern_sized()); -/// let ty = WrapMyArray[config]; -/// assert_eq!(ty.my_array, Array[bar][12]); -/// ``` -/// -/// # Type Alias that gets a [`Size`] from a [`PhantomConst`] -/// -/// This allows you to use some computed property of a [`PhantomConst`] to get a [`Size`] that you can use in other #[hdl] types. -/// -/// ``` -/// # use fayalite::{intern::Intern, prelude::*}; -/// # #[derive(Clone, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)] -/// # pub struct ConfigItem {} -/// # impl ConfigItem { -/// # pub fn new() -> Self { -/// # Self {} -/// # } -/// # } -/// #[derive(Clone, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)] -/// pub struct Config { -/// pub items: Vec, -/// } -/// -/// // the expression inside `get` is called with `Interned` and returns `usize` (not DynSize) -/// #[hdl(get(|config| config.items.len()))] -/// pub type GetItemsLen> = DynSize; // must be DynSize -/// -/// // you can then use it in other types: -/// -/// #[hdl(no_static)] -/// pub struct FlagPerItem> { -/// pub flags: ArrayType>, -/// } -/// -/// // you can then use Fayalite's standard syntax for creating dynamic types at runtime: -/// let config = PhantomConst::new(Config { items: vec![ConfigItem::new(); 5] }.intern_sized()); -/// let ty = FlagPerItem[config]; -/// assert_eq!(ty.flags, Array[Bool][5]); -/// ``` -/// -/// [`PhantomConst`]: crate::phantom_const::PhantomConst -/// [`Size`]: crate::int::Size -/// [`Type`]: crate::ty::Type pub use fayalite_proc_macros::hdl; -pub use bitvec; - /// struct used as a placeholder when applying defaults #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct __; @@ -228,8 +85,8 @@ pub mod _docs; pub mod annotations; pub mod array; -pub mod build; pub mod bundle; +pub mod cli; pub mod clock; pub mod enum_; pub mod expr; @@ -239,8 +96,6 @@ pub mod int; pub mod intern; pub mod memory; pub mod module; -pub mod phantom_const; -pub mod platform; pub mod prelude; pub mod reg; pub mod reset; @@ -249,5 +104,4 @@ pub mod source_location; pub mod testing; pub mod ty; pub mod util; -pub mod vendor; pub mod wire; diff --git a/crates/fayalite/src/memory.rs b/crates/fayalite/src/memory.rs index 46eb59b..2f0ec47 100644 --- a/crates/fayalite/src/memory.rs +++ b/crates/fayalite/src/memory.rs @@ -7,7 +7,7 @@ use crate::{ array::{Array, ArrayType}, bundle::{Bundle, BundleType}, clock::Clock, - expr::{Expr, Flow, ToExpr, ToLiteralBits, ops::BundleLiteral, repeat}, + expr::{ops::BundleLiteral, repeat, Expr, Flow, ToExpr, ToLiteralBits}, hdl, int::{Bool, DynSize, Size, UInt, UIntType}, intern::{Intern, Interned}, @@ -470,7 +470,7 @@ pub enum ReadUnderWrite { Undefined, } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] struct MemImpl { scoped_name: ScopedNameId, source_location: SourceLocation, @@ -1066,8 +1066,7 @@ pub fn splat_mask(ty: T, value: Expr) -> Expr> { | CanonicalType::SyncReset(_) | CanonicalType::Reset(_) | CanonicalType::Clock(_) - | CanonicalType::Enum(_) - | CanonicalType::DynSimOnly(_) => Expr::from_canonical(Expr::canonical(value)), + | CanonicalType::Enum(_) => Expr::from_canonical(Expr::canonical(value)), CanonicalType::Array(array) => Expr::from_canonical(Expr::canonical(repeat( splat_mask(array.element(), value), array.len(), @@ -1083,7 +1082,6 @@ pub fn splat_mask(ty: T, value: Expr) -> Expr> { ) .to_expr(), )), - CanonicalType::PhantomConst(_) => Expr::from_canonical(Expr::canonical(().to_expr())), } } diff --git a/crates/fayalite/src/module.rs b/crates/fayalite/src/module.rs index 6527043..5a18ac9 100644 --- a/crates/fayalite/src/module.rs +++ b/crates/fayalite/src/module.rs @@ -8,34 +8,31 @@ use crate::{ clock::{Clock, ClockDomain}, enum_::{Enum, EnumMatchVariantsIter, EnumType}, expr::{ - Expr, Flow, ToExpr, ops::VariantAccess, target::{ GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement, }, + Expr, Flow, ToExpr, }, formal::FormalKind, int::{Bool, DynSize, Size}, intern::{Intern, Interned}, memory::{Mem, MemBuilder, MemBuilderTarget, PortName}, - platform::PlatformIOBuilder, reg::Reg, reset::{AsyncReset, Reset, ResetType, ResetTypeDispatch, SyncReset}, - sim::{ExternModuleSimGenerator, ExternModuleSimulation}, source_location::SourceLocation, ty::{CanonicalType, Type}, - util::{HashMap, HashSet, ScopedRef}, + util::ScopedRef, wire::{IncompleteWire, Wire}, }; -use hashbrown::hash_map::Entry; +use hashbrown::{hash_map::Entry, HashMap, HashSet}; use num_bigint::BigInt; use std::{ cell::RefCell, - collections::{BTreeMap, VecDeque}, + collections::VecDeque, convert::Infallible, fmt, - future::IntoFuture, hash::{Hash, Hasher}, iter::FusedIterator, marker::PhantomData, @@ -834,8 +831,6 @@ pub struct AnnotatedModuleIO { pub module_io: ModuleIO, } -impl Copy for AnnotatedModuleIO {} - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum ModuleKind { Extern, @@ -1086,7 +1081,6 @@ pub struct ExternModuleBody< > { pub verilog_name: Interned, pub parameters: P, - pub simulation: Option, } impl From>> for ExternModuleBody { @@ -1094,13 +1088,11 @@ impl From>> for ExternModuleBody { let ExternModuleBody { verilog_name, parameters, - simulation, } = value; let parameters = Intern::intern_owned(parameters); Self { verilog_name, parameters, - simulation, } } } @@ -1215,12 +1207,6 @@ pub struct Module { module_annotations: Interned<[Annotation]>, } -impl AsRef for Module { - fn as_ref(&self) -> &Self { - self - } -} - #[derive(Default)] struct DebugFmtModulesState { seen: HashSet, @@ -1297,12 +1283,10 @@ impl fmt::Debug for DebugModuleBody { ModuleBody::Extern(ExternModuleBody { verilog_name, parameters, - simulation, }) => { debug_struct .field("verilog_name", verilog_name) - .field("parameters", parameters) - .field("simulation", simulation); + .field("parameters", parameters); } } debug_struct.finish_non_exhaustive() @@ -1468,9 +1452,7 @@ impl TargetState { }) .reduce(TargetWritten::conditional_merge_written) else { - unreachable!( - "merge_conditional_sub_blocks_into_block must be called with at least one sub-block" - ); + unreachable!("merge_conditional_sub_blocks_into_block must be called with at least one sub-block"); }; let mut written_in_blocks = written_in_blocks.borrow_mut(); if target_block >= written_in_blocks.len() { @@ -1508,9 +1490,6 @@ impl TargetState { }) .collect(), }, - CanonicalType::PhantomConst(_) => TargetStateInner::Decomposed { - subtargets: HashMap::default(), - }, CanonicalType::Array(ty) => TargetStateInner::Decomposed { subtargets: (0..ty.len()) .map(|index| { @@ -1533,8 +1512,7 @@ impl TargetState { | CanonicalType::Clock(_) | CanonicalType::AsyncReset(_) | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::DynSimOnly(_) => TargetStateInner::Single { + | CanonicalType::Reset(_) => TargetStateInner::Single { declared_in_block, written_in_blocks: RefCell::default(), }, @@ -1780,7 +1758,6 @@ impl AssertValidityState { ModuleBody::Extern(ExternModuleBody { verilog_name: _, parameters: _, - simulation: _, }) => {} ModuleBody::Normal(NormalModuleBody { body }) => { let body = self.make_block_index(body); @@ -1802,49 +1779,12 @@ impl Module { pub fn new_unchecked( name_id: NameId, source_location: SourceLocation, - mut body: ModuleBody, + body: ModuleBody, module_io: impl IntoIterator, module_annotations: impl IntoAnnotations, ) -> Module { let module_io: Interned<[_]> = module_io.into_iter().collect(); let module_annotations = module_annotations.into_annotations().into_iter().collect(); - match &mut body { - ModuleBody::Normal(_) => {} - ModuleBody::Extern(ExternModuleBody { - simulation: Some(simulation), - .. - }) => { - if module_io.iter().any(|io| { - !simulation - .sim_io_to_generator_map - .contains_key(&io.module_io.intern()) - }) { - let mut sim_io_to_generator_map = - BTreeMap::clone(&simulation.sim_io_to_generator_map); - for io in module_io.iter() { - let io = io.module_io.intern(); - sim_io_to_generator_map.entry(io).or_insert(io); - } - simulation.sim_io_to_generator_map = sim_io_to_generator_map.intern_sized(); - } - if simulation.sim_io_to_generator_map.len() > module_io.len() { - // if sim_io_to_generator_map is bigger, then there must be a key that's not in module_io - let module_io_set = HashSet::from_iter(module_io.iter().map(|v| v.module_io)); - for (sim_io, generator_io) in simulation.sim_io_to_generator_map.iter() { - if !module_io_set.contains(&**sim_io) { - panic!( - "extern module has invalid `sim_io_to_generator_map`: key is not in containing module's `module_io`:\n\ - key={sim_io:?}\nvalue={generator_io:?}\nmodule location: {source_location}" - ); - } - } - unreachable!(); - } - } - ModuleBody::Extern(ExternModuleBody { - simulation: None, .. - }) => {} - } let retval = Module { name: name_id, source_location, @@ -1913,7 +1853,7 @@ impl Module { AssertValidityState { module: self.canonical(), blocks: vec![], - target_states: HashMap::with_capacity_and_hasher(64, Default::default()), + target_states: HashMap::with_capacity(64), } .assert_validity(); } @@ -2120,27 +2060,6 @@ impl ModuleBuilder { self.output_with_loc(implicit_name.0, SourceLocation::caller(), ty) } #[track_caller] - pub fn add_platform_io_with_loc( - &self, - name: &str, - source_location: SourceLocation, - platform_io_builder: PlatformIOBuilder<'_>, - ) -> Expr { - platform_io_builder.add_platform_io(name, source_location, self) - } - #[track_caller] - pub fn add_platform_io( - &self, - implicit_name: ImplicitName<'_>, - platform_io_builder: PlatformIOBuilder<'_>, - ) -> Expr { - self.add_platform_io_with_loc( - implicit_name.0, - SourceLocation::caller(), - platform_io_builder, - ) - } - #[track_caller] pub fn run( name: &str, module_kind: ModuleKind, @@ -2186,7 +2105,6 @@ impl ModuleBuilder { ModuleKind::Extern => ModuleBody::Extern(ExternModuleBody { verilog_name: name.0, parameters: vec![], - simulation: None, }), ModuleKind::Normal => ModuleBody::Normal(NormalModuleBody { body: BuilderModuleBody { @@ -2195,8 +2113,8 @@ impl ModuleBuilder { incomplete_declarations: vec![], stmts: vec![], }], - annotations_map: HashMap::default(), - memory_map: HashMap::default(), + annotations_map: HashMap::new(), + memory_map: HashMap::new(), }, }), }; @@ -2206,7 +2124,7 @@ impl ModuleBuilder { impl_: RefCell::new(ModuleBuilderImpl { body, io: vec![], - io_indexes: HashMap::default(), + io_indexes: HashMap::new(), module_annotations: vec![], }), }; @@ -2253,7 +2171,6 @@ impl ModuleBuilder { .builder_extern_body() .verilog_name = name.intern(); } - #[track_caller] pub fn parameter(&self, name: impl AsRef, value: ExternModuleParameterValue) { let name = name.as_ref(); self.impl_ @@ -2266,7 +2183,6 @@ impl ModuleBuilder { value, }); } - #[track_caller] pub fn parameter_int(&self, name: impl AsRef, value: impl Into) { let name = name.as_ref(); let value = value.into(); @@ -2280,7 +2196,6 @@ impl ModuleBuilder { value: ExternModuleParameterValue::Integer(value), }); } - #[track_caller] pub fn parameter_str(&self, name: impl AsRef, value: impl AsRef) { let name = name.as_ref(); let value = value.as_ref(); @@ -2294,7 +2209,6 @@ impl ModuleBuilder { value: ExternModuleParameterValue::String(value.intern()), }); } - #[track_caller] pub fn parameter_raw_verilog(&self, name: impl AsRef, raw_verilog: impl AsRef) { let name = name.as_ref(); let raw_verilog = raw_verilog.as_ref(); @@ -2308,26 +2222,6 @@ impl ModuleBuilder { value: ExternModuleParameterValue::RawVerilog(raw_verilog.intern()), }); } - #[track_caller] - pub fn extern_module_simulation(&self, generator: G) { - let mut impl_ = self.impl_.borrow_mut(); - let simulation = &mut impl_.body.builder_extern_body().simulation; - if simulation.is_some() { - panic!("already added an extern module simulation"); - } - *simulation = Some(ExternModuleSimulation::new(generator)); - } - #[track_caller] - pub fn extern_module_simulation_fn< - Args: fmt::Debug + Clone + Hash + Eq + Send + Sync + 'static, - Fut: IntoFuture + 'static, - >( - &self, - args: Args, - f: fn(Args, crate::sim::ExternModuleSimulationState) -> Fut, - ) { - self.extern_module_simulation(crate::sim::SimGeneratorFn { args, f }); - } } #[track_caller] @@ -2360,12 +2254,14 @@ pub fn annotate(target: Expr, annotations: impl IntoAnnotations) { } TargetBase::MemPort(v) => { ModuleBuilder::with(|m| { - RefCell::borrow_mut(unwrap!( - unwrap!(m.impl_.borrow_mut().body.builder_normal_body_opt()) - .body - .memory_map - .get_mut(&v.mem_name()) - )) + RefCell::borrow_mut(unwrap!(unwrap!(m + .impl_ + .borrow_mut() + .body + .builder_normal_body_opt()) + .body + .memory_map + .get_mut(&v.mem_name()))) .port_annotations .extend(annotations) }); @@ -2765,22 +2661,6 @@ impl ModuleIO { source_location, } } - pub fn from_canonical(canonical_module_io: ModuleIO) -> Self { - let ModuleIO { - containing_module_name, - bundle_field, - id, - ty, - source_location, - } = canonical_module_io; - Self { - containing_module_name, - bundle_field, - id, - ty: T::from_canonical(ty), - source_location, - } - } pub fn bundle_field(&self) -> BundleField { self.bundle_field } diff --git a/crates/fayalite/src/module/transform/deduce_resets.rs b/crates/fayalite/src/module/transform/deduce_resets.rs index e84d835..fe518a5 100644 --- a/crates/fayalite/src/module/transform/deduce_resets.rs +++ b/crates/fayalite/src/module/transform/deduce_resets.rs @@ -6,32 +6,29 @@ use crate::{ bundle::{BundleField, BundleType}, enum_::{EnumType, EnumVariant}, expr::{ - ExprEnum, ops::{self, ArrayLiteral}, target::{ Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, }, + ExprEnum, }, formal::FormalKind, int::{SIntValue, UIntValue}, intern::{Intern, Interned, Memoize}, memory::{DynPortType, MemPort}, module::{ - AnnotatedModuleIO, Block, ExprInInstantiatedModule, ExternModuleBody, - ExternModuleParameter, InstantiatedModule, ModuleBody, ModuleIO, NameId, NormalModuleBody, - Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, - StmtWire, + AnnotatedModuleIO, Block, ExprInInstantiatedModule, ExternModuleBody, InstantiatedModule, + ModuleBody, ModuleIO, NameId, NormalModuleBody, Stmt, StmtConnect, StmtDeclaration, + StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, }, prelude::*, reset::{ResetType, ResetTypeDispatch}, - sim::ExternModuleSimulation, - util::{HashMap, HashSet}, }; -use hashbrown::hash_map::Entry; +use hashbrown::{hash_map::Entry, HashMap, HashSet}; use num_bigint::BigInt; use petgraph::unionfind::UnionFind; -use std::{collections::BTreeMap, fmt, marker::PhantomData}; +use std::{fmt, marker::PhantomData}; #[derive(Debug)] pub enum DeduceResetsError { @@ -43,16 +40,10 @@ impl fmt::Display for DeduceResetsError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { DeduceResetsError::ResetIsNotDrivenByAsyncOrSync { source_location } => { - write!( - f, - "deduce_reset failed: Reset signal is not driven by any AsyncReset or SyncReset signals: {source_location}" - ) + write!(f, "deduce_reset failed: Reset signal is not driven by any AsyncReset or SyncReset signals: {source_location}") } DeduceResetsError::ResetIsDrivenByBothAsyncAndSync { source_location } => { - write!( - f, - "deduce_reset failed: Reset signal is driven by both AsyncReset and SyncReset signals: {source_location}" - ) + write!(f, "deduce_reset failed: Reset signal is driven by both AsyncReset and SyncReset signals: {source_location}") } } } @@ -164,8 +155,6 @@ impl ResetsLayout { CanonicalType::SyncReset(_) => ResetsLayout::SyncReset, CanonicalType::Reset(_) => ResetsLayout::Reset, CanonicalType::Clock(_) => ResetsLayout::NoResets, - CanonicalType::PhantomConst(_) => ResetsLayout::NoResets, - CanonicalType::DynSimOnly(_) => ResetsLayout::NoResets, } } } @@ -418,9 +407,7 @@ impl Resets { | CanonicalType::Bool(_) | CanonicalType::AsyncReset(_) | CanonicalType::SyncReset(_) - | CanonicalType::Clock(_) - | CanonicalType::PhantomConst(_) - | CanonicalType::DynSimOnly(_) => Ok(self.ty), + | CanonicalType::Clock(_) => Ok(self.ty), CanonicalType::Array(ty) => Ok(CanonicalType::Array(Array::new_dyn( self.array_elements().substituted_type( reset_graph, @@ -1011,9 +998,7 @@ fn cast_bit_op( CanonicalType::Array(_) | CanonicalType::Enum(_) | CanonicalType::Bundle(_) - | CanonicalType::Reset(_) - | CanonicalType::PhantomConst(_) - | CanonicalType::DynSimOnly(_) => unreachable!(), + | CanonicalType::Reset(_) => unreachable!(), $(CanonicalType::$Variant(ty) => Expr::expr_enum($arg.cast_to(ty)),)* } }; @@ -1025,8 +1010,6 @@ fn cast_bit_op( | CanonicalType::Enum(_) | CanonicalType::Bundle(_) | CanonicalType::Reset(_) => unreachable!(), - CanonicalType::PhantomConst(_) | - CanonicalType::DynSimOnly(_) => Expr::expr_enum(arg), $(CanonicalType::$Variant(_) => { let arg = Expr::<$Variant>::from_canonical(arg); match_expr_ty!(arg, UInt, SInt, Bool, AsyncReset, SyncReset, Clock) @@ -1057,7 +1040,6 @@ impl RunPass

for ExprEnum { ExprEnum::UIntLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::SIntLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::BoolLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), - ExprEnum::PhantomConst(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::BundleLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::ArrayLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), ExprEnum::EnumLiteral(expr) => Ok(expr.run_pass(pass_args)?.map(ExprEnum::from)), @@ -1688,9 +1670,7 @@ impl RunPassDispatch for AnyReg { | CanonicalType::Enum(_) | CanonicalType::Bundle(_) | CanonicalType::Reset(_) - | CanonicalType::Clock(_) - | CanonicalType::PhantomConst(_) - | CanonicalType::DynSimOnly(_) => unreachable!(), + | CanonicalType::Clock(_) => unreachable!(), } }) } @@ -1744,33 +1724,6 @@ impl RunPassDispatch for Instance { } } -impl RunPass

for ExternModuleSimulation { - fn run_pass( - &self, - mut pass_args: PassArgs<'_, P>, - ) -> Result, DeduceResetsError> { - let Self { - generator, - sim_io_to_generator_map, - source_location, - } = *self; - let sim_io_to_generator_map = Result::, P>, _>::from_iter( - sim_io_to_generator_map - .iter() - .map(|(sim_io, generator_io)| { - Ok(sim_io - .run_pass(pass_args.as_mut())? - .map(|v| (v, *generator_io))) - }), - )?; - Ok(sim_io_to_generator_map.map(|sim_io_to_generator_map| Self { - generator, - sim_io_to_generator_map: sim_io_to_generator_map.intern_sized(), - source_location, - })) - } -} - macro_rules! impl_run_pass_copy { ([$($generics:tt)*] $ty:ty) => { impl RunPass

for $ty { @@ -1798,17 +1751,16 @@ macro_rules! impl_run_pass_clone { } impl_run_pass_clone!([] BigInt); -impl_run_pass_clone!([] ExternModuleParameter); impl_run_pass_clone!([] SIntValue); impl_run_pass_clone!([] std::ops::Range); impl_run_pass_clone!([] UIntValue); -impl_run_pass_clone!([] crate::vendor::xilinx::XilinxAnnotation); impl_run_pass_copy!([] BlackBoxInlineAnnotation); impl_run_pass_copy!([] BlackBoxPathAnnotation); impl_run_pass_copy!([] bool); impl_run_pass_copy!([] CustomFirrtlAnnotation); impl_run_pass_copy!([] DocStringAnnotation); impl_run_pass_copy!([] DontTouchAnnotation); +impl_run_pass_copy!([] ExternModuleBody); impl_run_pass_copy!([] Interned); impl_run_pass_copy!([] NameId); impl_run_pass_copy!([] SInt); @@ -1817,7 +1769,6 @@ impl_run_pass_copy!([] SVAttributeAnnotation); impl_run_pass_copy!([] UInt); impl_run_pass_copy!([] usize); impl_run_pass_copy!([] FormalKind); -impl_run_pass_copy!([] PhantomConst); macro_rules! impl_run_pass_for_struct { ( @@ -2069,14 +2020,6 @@ impl_run_pass_for_struct! { } } -impl_run_pass_for_struct! { - impl[] RunPass for ExternModuleBody { - verilog_name: _, - parameters: _, - simulation: _, - } -} - impl_run_pass_copy!([] MemPort); // Mem can't contain any `Reset` types impl_run_pass_copy!([] Mem); // Mem can't contain any `Reset` types @@ -2148,7 +2091,7 @@ impl RunPass

for StmtDeclaration { ) -> Result, DeduceResetsError> { let (annotations, reg) = match self { StmtDeclaration::Wire(v) => { - return Ok(v.run_pass(pass_args)?.map(StmtDeclaration::Wire)); + return Ok(v.run_pass(pass_args)?.map(StmtDeclaration::Wire)) } &StmtDeclaration::Reg(StmtReg { annotations, reg }) => (annotations, AnyReg::from(reg)), &StmtDeclaration::RegSync(StmtReg { annotations, reg }) => { @@ -2158,7 +2101,7 @@ impl RunPass

for StmtDeclaration { (annotations, AnyReg::from(reg)) } StmtDeclaration::Instance(v) => { - return Ok(v.run_pass(pass_args)?.map(StmtDeclaration::Instance)); + return Ok(v.run_pass(pass_args)?.map(StmtDeclaration::Instance)) } }; let annotations = annotations.run_pass(pass_args.as_mut())?; @@ -2218,7 +2161,6 @@ impl_run_pass_for_enum! { BlackBoxPath(v), DocString(v), CustomFirrtl(v), - Xilinx(v), } } @@ -2302,9 +2244,9 @@ pub fn deduce_resets( fallback_to_sync_reset: bool, ) -> Result>, DeduceResetsError> { let mut state = State { - modules_added_to_graph: HashSet::default(), - substituted_modules: HashMap::default(), - expr_resets: HashMap::default(), + modules_added_to_graph: HashSet::new(), + substituted_modules: HashMap::new(), + expr_resets: HashMap::new(), reset_graph: ResetGraph::default(), fallback_to_sync_reset, }; diff --git a/crates/fayalite/src/module/transform/simplify_enums.rs b/crates/fayalite/src/module/transform/simplify_enums.rs index bd5f7d5..4eb0d0c 100644 --- a/crates/fayalite/src/module/transform/simplify_enums.rs +++ b/crates/fayalite/src/module/transform/simplify_enums.rs @@ -5,24 +5,23 @@ use crate::{ bundle::{Bundle, BundleField, BundleType}, enum_::{Enum, EnumType, EnumVariant}, expr::{ - CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr, ops::{self, EnumLiteral}, + CastBitsTo, CastTo, CastToBits, Expr, ExprEnum, HdlPartialEq, ToExpr, }, hdl, int::UInt, - intern::{Intern, InternSlice, Interned, Memoize}, + intern::{Intern, Interned, Memoize}, memory::{DynPortType, Mem, MemPort}, module::{ - Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire, transform::visit::{Fold, Folder}, + Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtIf, StmtMatch, StmtWire, }, source_location::SourceLocation, ty::{CanonicalType, Type}, - util::HashMap, wire::Wire, }; use core::fmt; -use serde::{Deserialize, Serialize}; +use hashbrown::HashMap; #[derive(Debug)] pub enum SimplifyEnumsError { @@ -70,9 +69,7 @@ fn contains_any_enum_types(ty: CanonicalType) -> bool { | CanonicalType::AsyncReset(_) | CanonicalType::SyncReset(_) | CanonicalType::Reset(_) - | CanonicalType::Clock(_) - | CanonicalType::PhantomConst(_) - | CanonicalType::DynSimOnly(_) => false, + | CanonicalType::Clock(_) => false, } } } @@ -515,9 +512,7 @@ impl State { | CanonicalType::AsyncReset(_) | CanonicalType::SyncReset(_) | CanonicalType::Reset(_) - | CanonicalType::Clock(_) - | CanonicalType::PhantomConst(_) - | CanonicalType::DynSimOnly(_) => unreachable!(), + | CanonicalType::Clock(_) => unreachable!(), } } } @@ -582,9 +577,7 @@ fn connect_port( | (CanonicalType::Clock(_), _) | (CanonicalType::AsyncReset(_), _) | (CanonicalType::SyncReset(_), _) - | (CanonicalType::Reset(_), _) - | (CanonicalType::PhantomConst(_), _) - | (CanonicalType::DynSimOnly(_), _) => unreachable!( + | (CanonicalType::Reset(_), _) => unreachable!( "trying to connect memory ports:\n{:?}\n{:?}", Expr::ty(lhs), Expr::ty(rhs), @@ -620,7 +613,7 @@ fn match_int_tag( block, Block { memories: Default::default(), - stmts: [Stmt::from(retval)].intern_slice(), + stmts: [Stmt::from(retval)][..].intern(), }, ], }; @@ -672,7 +665,6 @@ impl Folder for State { ExprEnum::UIntLiteral(_) | ExprEnum::SIntLiteral(_) | ExprEnum::BoolLiteral(_) - | ExprEnum::PhantomConst(_) | ExprEnum::BundleLiteral(_) | ExprEnum::ArrayLiteral(_) | ExprEnum::Uninit(_) @@ -814,7 +806,7 @@ impl Folder for State { .unwrap() .gen_name(&format!( "{}_{}", - memory.scoped_name().1.0, + memory.scoped_name().1 .0, port.port_name() )), port.source_location(), @@ -931,9 +923,7 @@ impl Folder for State { | CanonicalType::Clock(_) | CanonicalType::AsyncReset(_) | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::PhantomConst(_) - | CanonicalType::DynSimOnly(_) => canonical_type.default_fold(self), + | CanonicalType::Reset(_) => canonical_type.default_fold(self), } } @@ -956,15 +946,12 @@ impl Folder for State { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, clap::ValueEnum, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, clap::ValueEnum)] pub enum SimplifyEnumsKind { SimplifyToEnumsWithNoBody, #[clap(name = "replace-with-bundle-of-uints")] - #[serde(rename = "replace-with-bundle-of-uints")] ReplaceWithBundleOfUInts, #[clap(name = "replace-with-uint")] - #[serde(rename = "replace-with-uint")] ReplaceWithUInt, } @@ -973,8 +960,8 @@ pub fn simplify_enums( kind: SimplifyEnumsKind, ) -> Result>, SimplifyEnumsError> { module.fold(&mut State { - enum_types: HashMap::default(), - replacement_mem_ports: HashMap::default(), + enum_types: HashMap::new(), + replacement_mem_ports: HashMap::new(), kind, module_state_stack: vec![], }) diff --git a/crates/fayalite/src/module/transform/simplify_memories.rs b/crates/fayalite/src/module/transform/simplify_memories.rs index 35f186d..e8f9cbf 100644 --- a/crates/fayalite/src/module/transform/simplify_memories.rs +++ b/crates/fayalite/src/module/transform/simplify_memories.rs @@ -9,15 +9,16 @@ use crate::{ intern::{Intern, Interned}, memory::{Mem, MemPort, PortType}, module::{ - Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtWire, transform::visit::{Fold, Folder}, + Block, Id, Module, NameId, ScopedNameId, Stmt, StmtConnect, StmtWire, }, source_location::SourceLocation, ty::{CanonicalType, Type}, - util::{HashMap, MakeMutSlice}, + util::MakeMutSlice, wire::Wire, }; use bitvec::{slice::BitSlice, vec::BitVec}; +use hashbrown::HashMap; use std::{ convert::Infallible, fmt::Write, @@ -61,7 +62,6 @@ enum MemSplit { Bundle { fields: Rc<[MemSplit]>, }, - PhantomConst, Single { output_mem: Option, element_type: SingleType, @@ -76,7 +76,6 @@ impl MemSplit { fn mark_changed_element_type(self) -> Self { match self { MemSplit::Bundle { fields: _ } => self, - MemSplit::PhantomConst => self, MemSplit::Single { output_mem, element_type, @@ -98,7 +97,6 @@ impl MemSplit { .map(|field| Self::new(field.ty).mark_changed_element_type()) .collect(), }, - CanonicalType::PhantomConst(_) => MemSplit::PhantomConst, CanonicalType::Array(ty) => { let element = MemSplit::new(ty.element()); if let Self::Single { @@ -194,7 +192,6 @@ impl MemSplit { | CanonicalType::AsyncReset(_) | CanonicalType::SyncReset(_) | CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"), - CanonicalType::DynSimOnly(_) => todo!("memory containing sim-only values"), } } } @@ -324,9 +321,6 @@ impl SplitMemState<'_, '_> { Expr::field(Expr::::from_canonical(e), &field.name) }, |initial_value_element| { - let Some(field_offset) = field_offset.only_bit_width() else { - todo!("memory containing sim-only values"); - }; &initial_value_element[field_offset..][..field_ty_bit_width] }, ); @@ -345,7 +339,6 @@ impl SplitMemState<'_, '_> { self.split_state_stack.pop(); } } - MemSplit::PhantomConst => {} MemSplit::Single { output_mem, element_type: single_type, @@ -545,12 +538,7 @@ impl ModuleState { }; loop { match input_element_type { - CanonicalType::Bundle(_) => { - unreachable!("bundle types are always split") - } - CanonicalType::PhantomConst(_) => { - unreachable!("PhantomConst are always removed") - } + CanonicalType::Bundle(_) => unreachable!("bundle types are always split"), CanonicalType::Enum(_) if input_array_types .first() @@ -624,7 +612,6 @@ impl ModuleState { | CanonicalType::AsyncReset(_) | CanonicalType::SyncReset(_) | CanonicalType::Reset(_) => unreachable!("memory element type is a storable type"), - CanonicalType::DynSimOnly(_) => todo!("memory containing sim-only values"), } break; } @@ -639,7 +626,7 @@ impl ModuleState { split_state: &SplitState<'_>, ) -> Mem { let mem_name = NameId( - Intern::intern_owned(format!("{}{mem_name_path}", input_mem.scoped_name().1.0)), + Intern::intern_owned(format!("{}{mem_name_path}", input_mem.scoped_name().1 .0)), Id::new(), ); let mem_name = ScopedNameId(input_mem.scoped_name().0, mem_name); @@ -756,8 +743,7 @@ impl ModuleState { .. } | MemSplit::Bundle { .. } - | MemSplit::Array { .. } - | MemSplit::PhantomConst => { + | MemSplit::Array { .. } => { let mut replacement_ports = Vec::with_capacity(input_mem.ports().len()); let mut wire_port_rdata = Vec::with_capacity(input_mem.ports().len()); let mut wire_port_wdata = Vec::with_capacity(input_mem.ports().len()); @@ -901,7 +887,7 @@ impl Folder for State { module, ModuleState { output_module: None, - memories: HashMap::default(), + memories: HashMap::new(), }, ); let mut this = PushedState::push_module(self, module); diff --git a/crates/fayalite/src/module/transform/visit.rs b/crates/fayalite/src/module/transform/visit.rs index 2c33a76..97de4fc 100644 --- a/crates/fayalite/src/module/transform/visit.rs +++ b/crates/fayalite/src/module/transform/visit.rs @@ -11,11 +11,12 @@ use crate::{ clock::Clock, enum_::{Enum, EnumType, EnumVariant}, expr::{ - Expr, ExprEnum, ops, + ops, target::{ Target, TargetBase, TargetChild, TargetPathArrayElement, TargetPathBundleField, TargetPathDynArrayElement, TargetPathElement, }, + Expr, ExprEnum, }, formal::FormalKind, int::{Bool, SIntType, SIntValue, Size, UIntType, UIntValue}, @@ -27,15 +28,10 @@ use crate::{ NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, }, - phantom_const::PhantomConst, reg::Reg, reset::{AsyncReset, Reset, ResetType, SyncReset}, - sim::{ExternModuleSimulation, value::DynSimOnly}, source_location::SourceLocation, ty::{CanonicalType, Type}, - vendor::xilinx::{ - XdcCreateClockAnnotation, XdcIOStandardAnnotation, XdcLocationAnnotation, XilinxAnnotation, - }, wire::Wire, }; use num_bigint::{BigInt, BigUint}; diff --git a/crates/fayalite/src/phantom_const.rs b/crates/fayalite/src/phantom_const.rs deleted file mode 100644 index 9f25166..0000000 --- a/crates/fayalite/src/phantom_const.rs +++ /dev/null @@ -1,485 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - expr::{ - Expr, ToExpr, - ops::{ExprPartialEq, ExprPartialOrd}, - }, - int::Bool, - intern::{Intern, Interned, InternedCompare, LazyInterned, LazyInternedTrait, Memoize}, - sim::value::{SimValue, SimValuePartialEq, ToSimValue, ToSimValueWithType}, - source_location::SourceLocation, - ty::{ - CanonicalType, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten, - StaticType, Type, TypeProperties, impl_match_variant_as_self, - serde_impls::{SerdeCanonicalType, SerdePhantomConst}, - }, -}; -use serde::{ - Deserialize, Deserializer, Serialize, Serializer, - de::{DeserializeOwned, Error}, -}; -use std::{ - any::Any, - fmt, - hash::{Hash, Hasher}, - marker::PhantomData, - ops::Index, -}; - -#[derive(Clone)] -pub struct PhantomConstCanonicalValue { - parsed: serde_json::Value, - serialized: Interned, -} - -impl PhantomConstCanonicalValue { - pub fn from_json_value(parsed: serde_json::Value) -> Self { - let serialized = Intern::intern_owned( - serde_json::to_string(&parsed) - .expect("conversion from json value to text shouldn't fail"), - ); - Self { parsed, serialized } - } - pub fn as_json_value(&self) -> &serde_json::Value { - &self.parsed - } - pub fn as_str(&self) -> Interned { - self.serialized - } -} - -impl fmt::Debug for PhantomConstCanonicalValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.serialized) - } -} - -impl fmt::Display for PhantomConstCanonicalValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.serialized) - } -} - -impl PartialEq for PhantomConstCanonicalValue { - fn eq(&self, other: &Self) -> bool { - self.serialized == other.serialized - } -} - -impl Eq for PhantomConstCanonicalValue {} - -impl Hash for PhantomConstCanonicalValue { - fn hash(&self, state: &mut H) { - self.serialized.hash(state); - } -} - -impl Serialize for PhantomConstCanonicalValue { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.parsed.serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for PhantomConstCanonicalValue { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - Ok(Self::from_json_value(serde_json::Value::deserialize( - deserializer, - )?)) - } -} - -pub trait PhantomConstValue: Intern + InternedCompare + Serialize + fmt::Debug { - fn deserialize_value<'de, D>(deserializer: D) -> Result, D::Error> - where - D: serde::Deserializer<'de>; -} - -impl PhantomConstValue for T -where - T: ?Sized + Intern + InternedCompare + Serialize + fmt::Debug, - Interned: DeserializeOwned, -{ - fn deserialize_value<'de, D>(deserializer: D) -> Result, D::Error> - where - D: serde::Deserializer<'de>, - { - as Deserialize<'de>>::deserialize(deserializer) - } -} - -/// Wrapper type that allows any Rust value to be smuggled as a HDL [`Type`]. -/// This only works for values that can be [serialized][Serialize] to and [deserialized][Deserialize] from [JSON][serde_json]. -pub struct PhantomConst { - value: LazyInterned, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] -pub struct PhantomConstWithoutGenerics; - -#[allow(non_upper_case_globals)] -pub const PhantomConst: PhantomConstWithoutGenerics = PhantomConstWithoutGenerics; - -impl Index for PhantomConstWithoutGenerics { - type Output = PhantomConst; - - fn index(&self, value: T) -> &Self::Output { - Interned::into_inner(PhantomConst::new(value.intern()).intern_sized()) - } -} - -impl fmt::Debug for PhantomConst { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("PhantomConst").field(&self.get()).finish() - } -} - -impl Clone for PhantomConst { - fn clone(&self) -> Self { - *self - } -} - -impl Copy for PhantomConst {} - -impl PartialEq for PhantomConst { - fn eq(&self, other: &Self) -> bool { - self.get() == other.get() - } -} - -impl Eq for PhantomConst {} - -impl Hash for PhantomConst { - fn hash(&self, state: &mut H) { - self.get().hash(state); - } -} - -struct PhantomConstCanonicalMemoize(PhantomData); - -impl Copy - for PhantomConstCanonicalMemoize -{ -} - -impl Clone - for PhantomConstCanonicalMemoize -{ - fn clone(&self) -> Self { - *self - } -} - -impl Eq - for PhantomConstCanonicalMemoize -{ -} - -impl PartialEq - for PhantomConstCanonicalMemoize -{ - fn eq(&self, _other: &Self) -> bool { - true - } -} - -impl Hash - for PhantomConstCanonicalMemoize -{ - fn hash(&self, _state: &mut H) {} -} - -impl Memoize for PhantomConstCanonicalMemoize { - type Input = Interned; - type InputOwned = Interned; - type Output = Interned; - - fn inner(self, input: &Self::Input) -> Self::Output { - Intern::intern_sized(PhantomConstCanonicalValue::from_json_value( - serde_json::to_value(input) - .expect("serialization failed when constructing a canonical PhantomConst"), - )) - } -} - -impl Memoize for PhantomConstCanonicalMemoize { - type Input = Interned; - type InputOwned = Interned; - type Output = Interned; - - fn inner(self, input: &Self::Input) -> Self::Output { - PhantomConstValue::deserialize_value(input.as_json_value()) - .expect("deserialization failed ") - } -} - -impl PhantomConst { - pub fn new(value: Interned) -> Self { - Self { - value: LazyInterned::Interned(value), - } - } - pub const fn new_lazy(v: &'static dyn LazyInternedTrait) -> Self { - Self { - value: LazyInterned::new_lazy(v), - } - } - pub fn get(self) -> Interned { - self.value.interned() - } - pub fn type_properties(self) -> TypeProperties { - <()>::TYPE_PROPERTIES - } - pub fn can_connect(self, other: Self) -> bool { - self == other - } - pub fn canonical_phantom_const(self) -> PhantomConst { - if let Some(&retval) = ::downcast_ref::(&self) { - return retval; - } - ::new( - PhantomConstCanonicalMemoize::(PhantomData).get_owned(self.get()), - ) - } - pub fn from_canonical_phantom_const(canonical_type: PhantomConst) -> Self { - if let Some(&retval) = ::downcast_ref::(&canonical_type) { - return retval; - } - Self::new( - PhantomConstCanonicalMemoize::(PhantomData).get_owned(canonical_type.get()), - ) - } -} - -impl Type for PhantomConst { - type BaseType = PhantomConst; - type MaskType = (); - type SimValue = PhantomConst; - impl_match_variant_as_self!(); - - fn mask_type(&self) -> Self::MaskType { - () - } - - fn canonical(&self) -> CanonicalType { - CanonicalType::PhantomConst(self.canonical_phantom_const()) - } - - fn from_canonical(canonical_type: CanonicalType) -> Self { - let CanonicalType::PhantomConst(phantom_const) = canonical_type else { - panic!("expected PhantomConst"); - }; - Self::from_canonical_phantom_const(phantom_const) - } - - fn source_location() -> SourceLocation { - SourceLocation::builtin() - } - - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - assert!(opaque.is_empty()); - *self - } - - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ) { - assert!(opaque.is_empty()); - assert_eq!(*value, *self); - } - - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> OpaqueSimValueWritten<'w> { - assert_eq!(*value, *self); - writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty()) - } -} - -impl Default for PhantomConst -where - Interned: Default, -{ - fn default() -> Self { - Self::TYPE - } -} - -impl StaticType for PhantomConst -where - Interned: Default, -{ - const TYPE: Self = PhantomConst { - value: LazyInterned::new_lazy(&Interned::::default), - }; - const MASK_TYPE: Self::MaskType = (); - const TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES; - const MASK_TYPE_PROPERTIES: TypeProperties = <()>::TYPE_PROPERTIES; -} - -type SerdeType = SerdeCanonicalType>>; - -impl Serialize for PhantomConst { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - SerdeType::::PhantomConst(SerdePhantomConst(self.get())).serialize(serializer) - } -} - -impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for PhantomConst { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - match SerdeType::::deserialize(deserializer)? { - SerdeCanonicalType::PhantomConst(SerdePhantomConst(value)) => Ok(Self::new(value)), - ty => Err(Error::invalid_value( - serde::de::Unexpected::Other(ty.as_serde_unexpected_str()), - &"a PhantomConst", - )), - } - } -} - -impl ExprPartialEq for PhantomConst { - fn cmp_eq(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); - true.to_expr() - } - - fn cmp_ne(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); - false.to_expr() - } -} - -impl ExprPartialOrd for PhantomConst { - fn cmp_lt(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); - false.to_expr() - } - - fn cmp_le(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); - true.to_expr() - } - - fn cmp_gt(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); - false.to_expr() - } - - fn cmp_ge(lhs: Expr, rhs: Expr) -> Expr { - assert_eq!(Expr::ty(lhs), Expr::ty(rhs)); - true.to_expr() - } -} - -impl SimValuePartialEq for PhantomConst { - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - assert_eq!(SimValue::ty(this), SimValue::ty(other)); - true - } -} - -impl ToSimValue for PhantomConst { - type Type = PhantomConst; - - fn to_sim_value(&self) -> SimValue { - SimValue::from_value(*self, *self) - } -} - -impl ToSimValueWithType> for PhantomConst { - fn to_sim_value_with_type(&self, ty: PhantomConst) -> SimValue> { - SimValue::from_value(ty, *self) - } -} - -impl ToSimValueWithType for PhantomConst { - fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue { - SimValue::into_canonical(SimValue::from_value(Self::from_canonical(ty), *self)) - } -} - -mod sealed { - pub trait Sealed {} -} - -pub trait PhantomConstGet: sealed::Sealed { - fn get(&self) -> Interned; -} - -impl>> - sealed::Sealed for This -{ -} - -impl>> - PhantomConstGet for This -{ - fn get(&self) -> Interned { - This::Target::get(&**self) - } -} - -macro_rules! impl_phantom_const_get { - ( - impl PhantomConstGet<$T:ident> for $ty:ty { - fn $get:ident(&$get_self:ident) -> _ $get_body:block - } - ) => { - impl<$T: ?Sized + PhantomConstValue> sealed::Sealed<$T> for $ty {} - - impl<$T: ?Sized + PhantomConstValue> PhantomConstGet<$T> for $ty { - fn $get(&$get_self) -> Interned<$T> $get_body - } - }; -} - -impl_phantom_const_get! { - impl PhantomConstGet for PhantomConst { - fn get(&self) -> _ { - PhantomConst::get(*self) - } - } -} - -impl_phantom_const_get! { - impl PhantomConstGet for Expr> { - fn get(&self) -> _ { - PhantomConst::get(Expr::ty(*self)) - } - } -} - -#[doc(hidden)] -pub trait ReturnSelfUnchanged { - type Type: ?Sized; -} - -impl ReturnSelfUnchanged for This { - type Type = This; -} - -#[doc(hidden)] -pub fn type_alias_phantom_const_get_helper( - param: impl PhantomConstGet, - get: impl FnOnce(Interned) -> R, -) -> &'static R { - Interned::into_inner(get(param.get()).intern_sized()) -} diff --git a/crates/fayalite/src/platform.rs b/crates/fayalite/src/platform.rs deleted file mode 100644 index 194aa6e..0000000 --- a/crates/fayalite/src/platform.rs +++ /dev/null @@ -1,1923 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - bundle::{Bundle, BundleField, BundleType}, - expr::{Expr, ExprEnum}, - intern::{Intern, Interned}, - module::{Module, ModuleBuilder, ModuleIO, connect_with_loc, instance_with_loc, wire_with_loc}, - source_location::SourceLocation, - ty::{CanonicalType, Type}, - util::{HashMap, HashSet, InternedStrCompareAsStr}, -}; -use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error}; -use std::{ - any::{Any, TypeId}, - borrow::Cow, - cmp::Ordering, - collections::{BTreeMap, BTreeSet}, - convert::Infallible, - fmt, - hash::{Hash, Hasher}, - iter::FusedIterator, - marker::PhantomData, - mem, - sync::{Arc, Mutex, MutexGuard, OnceLock, RwLock, RwLockWriteGuard}, -}; - -pub mod peripherals; - -trait DynPlatformTrait: 'static + Send + Sync + fmt::Debug { - fn as_any(&self) -> &dyn Any; - fn eq_dyn(&self, other: &dyn DynPlatformTrait) -> bool; - fn hash_dyn(&self, state: &mut dyn Hasher); - fn name_dyn(&self) -> Interned; - fn new_peripherals_dyn<'builder>( - &self, - builder_factory: PeripheralsBuilderFactory<'builder>, - ) -> (DynPeripherals, PeripheralsBuilderFinished<'builder>); - fn source_location_dyn(&self) -> SourceLocation; - #[track_caller] - fn add_peripherals_in_wrapper_module_dyn(&self, m: &ModuleBuilder, peripherals: DynPeripherals); - fn aspects_dyn(&self) -> PlatformAspectSet; -} - -impl DynPlatformTrait for T { - fn as_any(&self) -> &dyn Any { - self - } - - fn eq_dyn(&self, other: &dyn DynPlatformTrait) -> bool { - other - .as_any() - .downcast_ref::() - .is_some_and(|other| self == other) - } - - fn hash_dyn(&self, mut state: &mut dyn Hasher) { - self.hash(&mut state); - } - - fn name_dyn(&self) -> Interned { - self.name() - } - - fn new_peripherals_dyn<'builder>( - &self, - builder_factory: PeripheralsBuilderFactory<'builder>, - ) -> (DynPeripherals, PeripheralsBuilderFinished<'builder>) { - let (peripherals, finished) = self.new_peripherals(builder_factory); - (DynPeripherals(Box::new(peripherals)), finished) - } - - fn source_location_dyn(&self) -> SourceLocation { - self.source_location() - } - - #[track_caller] - fn add_peripherals_in_wrapper_module_dyn( - &self, - m: &ModuleBuilder, - peripherals: DynPeripherals, - ) { - if DynPeripheralsTrait::type_id(&*peripherals.0) != TypeId::of::() { - panic!( - "wrong DynPeripherals value type, expected type: <{}>::Peripherals, got value:\n{peripherals:?}", - std::any::type_name::() - ); - } - let Ok(peripherals) = peripherals.0.into_box_any().downcast() else { - unreachable!(); - }; - self.add_peripherals_in_wrapper_module(m, *peripherals) - } - - fn aspects_dyn(&self) -> PlatformAspectSet { - self.aspects() - } -} - -#[derive(Clone)] -pub struct DynPlatform(Arc); - -impl PartialEq for DynPlatform { - fn eq(&self, other: &Self) -> bool { - DynPlatformTrait::eq_dyn(&*self.0, &*other.0) - } -} - -impl Eq for DynPlatform {} - -impl Hash for DynPlatform { - fn hash(&self, state: &mut H) { - DynPlatformTrait::hash_dyn(&*self.0, state); - } -} - -impl fmt::Debug for DynPlatform { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl DynPlatform { - pub fn new(platform: T) -> Self { - if let Some(platform) = ::downcast_ref::(&platform) { - platform.clone() - } else { - Self(Arc::new(platform)) - } - } -} - -trait DynPeripheralsTrait: fmt::Debug + 'static + Send + Sync { - fn type_id(&self) -> TypeId; - fn into_box_any(self: Box) -> Box; - fn append_peripherals_dyn<'a>( - &'a self, - peripherals: &mut Vec>, - ); -} - -impl DynPeripheralsTrait for T { - fn type_id(&self) -> TypeId { - TypeId::of::() - } - fn into_box_any(self: Box) -> Box { - self - } - fn append_peripherals_dyn<'a>( - &'a self, - peripherals: &mut Vec>, - ) { - self.append_peripherals(peripherals); - } -} - -pub struct DynPeripherals(Box); - -impl fmt::Debug for DynPeripherals { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl Peripherals for DynPeripherals { - fn append_peripherals<'a>(&'a self, peripherals: &mut Vec>) { - self.0.append_peripherals_dyn(peripherals); - } -} - -impl Platform for DynPlatform { - type Peripherals = DynPeripherals; - fn name(&self) -> Interned { - DynPlatformTrait::name_dyn(&*self.0) - } - fn new_peripherals<'a>( - &self, - builder_factory: PeripheralsBuilderFactory<'a>, - ) -> (Self::Peripherals, PeripheralsBuilderFinished<'a>) { - DynPlatformTrait::new_peripherals_dyn(&*self.0, builder_factory) - } - fn source_location(&self) -> SourceLocation { - DynPlatformTrait::source_location_dyn(&*self.0) - } - #[track_caller] - fn add_peripherals_in_wrapper_module(&self, m: &ModuleBuilder, peripherals: Self::Peripherals) { - DynPlatformTrait::add_peripherals_in_wrapper_module_dyn(&*self.0, m, peripherals); - } - fn aspects(&self) -> PlatformAspectSet { - DynPlatformTrait::aspects_dyn(&*self.0) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct PeripheralId { - pub name: Interned, -} - -impl PartialOrd for PeripheralId { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for PeripheralId { - fn cmp(&self, other: &Self) -> Ordering { - if self == other { - Ordering::Equal - } else { - let Self { name } = self; - str::cmp(name, &other.name) - } - } -} - -struct CollectingPeripherals { - conflicts_graph: BTreeMap>, - on_use_state: PeripheralsOnUseState, -} - -pub trait PeripheralsOnUseSharedState: 'static + Send + fmt::Debug { - fn as_any(&mut self) -> &mut dyn Any; -} - -impl PeripheralsOnUseSharedState for T { - fn as_any(&mut self) -> &mut dyn Any { - self - } -} - -type DynPeripheralsOnUse = dyn FnOnce( - &mut dyn PeripheralsOnUseSharedState, - PeripheralRef<'_, CanonicalType>, - Expr, - ) + Send - + 'static; - -struct PeripheralsOnUseState { - shared_state: Box, - main_module_io_fields: Vec, - main_module_io_wires: Vec>, - on_use_functions: BTreeMap>, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum PeripheralAvailability { - Available, - Used, - ConflictsWithUsed(PeripheralId), -} - -impl PeripheralAvailability { - pub fn is_available(self) -> bool { - matches!(self, Self::Available) - } - pub fn is_used(&self) -> bool { - matches!(self, Self::Used) - } -} - -struct PeripheralsStateBuildingModule { - conflicts_graph: Interned>>>, - availabilities: Mutex>, - on_use_state: Mutex, -} - -impl From for PeripheralsStateBuildingModule { - fn from(value: CollectingPeripherals) -> Self { - let CollectingPeripherals { - conflicts_graph, - on_use_state, - } = value; - let conflicts_graph = BTreeMap::from_iter( - conflicts_graph - .into_iter() - .map(|(k, v)| (k, v.intern_sized())), - ) - .intern_sized(); - Self { - conflicts_graph, - availabilities: Mutex::new( - on_use_state - .on_use_functions - .keys() - .map(|&id| (id, PeripheralAvailability::Available)) - .collect(), - ), - on_use_state: Mutex::new(on_use_state), - } - } -} - -struct PeripheralsStateBuildingWrapperModule { - output_module_io: ModuleIO, - output: Option>, -} - -enum PeripheralsStateEnum { - Initial, - CollectingPeripherals(CollectingPeripherals), - BuildingModule, - BuildingWrapperModule(PeripheralsStateBuildingWrapperModule), -} - -struct PeripheralsState { - will_build_wrapper: bool, - state: Mutex, - building_module: OnceLock, -} - -impl PeripheralsState { - fn finish_collecting_peripherals(&self) { - let mut state = self.state.lock().expect("shouldn't be poison"); - let building_module = match mem::replace(&mut *state, PeripheralsStateEnum::BuildingModule) - { - PeripheralsStateEnum::CollectingPeripherals(v) => v.into(), - PeripheralsStateEnum::Initial - | PeripheralsStateEnum::BuildingModule - | PeripheralsStateEnum::BuildingWrapperModule(_) => unreachable!(), - }; - self.building_module.get_or_init(|| building_module); - } -} - -struct PeripheralCommon { - type_id: TypeId, - id: PeripheralId, - is_input: bool, - peripherals_state: Arc, -} - -#[must_use] -pub struct PeripheralsBuilderFactory<'a> { - peripherals_state: Arc, - _phantom: PhantomData &'a ()>, -} - -impl fmt::Debug for PeripheralsBuilderFactory<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PeripheralsBuilderFactory") - .finish_non_exhaustive() - } -} - -impl PeripheralsBuilderFactory<'_> { - fn new(will_build_wrapper: bool) -> Self { - Self { - peripherals_state: Arc::new(PeripheralsState { - will_build_wrapper, - state: Mutex::new(PeripheralsStateEnum::Initial), - building_module: OnceLock::new(), - }), - _phantom: PhantomData, - } - } -} - -impl<'a> PeripheralsBuilderFactory<'a> { - pub fn builder(self) -> PeripheralsBuilder<'a> { - self.builder_with_default_state() - } - pub fn builder_with_default_state( - self, - ) -> PeripheralsBuilder<'a, S> { - self.builder_with_boxed_state(Box::default()) - } - pub fn builder_with_state( - self, - shared_state: S, - ) -> PeripheralsBuilder<'a, S> { - self.builder_with_boxed_state(Box::new(shared_state)) - } - pub fn builder_with_boxed_state( - self, - shared_state: Box, - ) -> PeripheralsBuilder<'a, S> { - let Self { - peripherals_state, - _phantom: PhantomData, - } = self; - match *peripherals_state.state.lock().expect("shouldn't be poison") { - ref mut state @ PeripheralsStateEnum::Initial => { - *state = PeripheralsStateEnum::CollectingPeripherals(CollectingPeripherals { - conflicts_graph: BTreeMap::new(), - on_use_state: PeripheralsOnUseState { - shared_state, - main_module_io_fields: Vec::new(), - main_module_io_wires: Vec::new(), - on_use_functions: BTreeMap::new(), - }, - }) - } - PeripheralsStateEnum::CollectingPeripherals(_) - | PeripheralsStateEnum::BuildingModule - | PeripheralsStateEnum::BuildingWrapperModule(_) => unreachable!(), - } - PeripheralsBuilder { - peripherals_state, - _phantom: PhantomData, - } - } -} - -#[must_use] -pub struct PeripheralsBuilder<'a, S: PeripheralsOnUseSharedState = ()> { - peripherals_state: Arc, - _phantom: PhantomData<(Arc, fn(&'a ()) -> &'a ())>, -} - -#[must_use] -pub struct PeripheralsBuilderFinished<'a> { - _private: PhantomData &'a ()>, -} - -impl fmt::Debug for PeripheralsBuilderFinished<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PeripheralsBuilderFinished") - .finish_non_exhaustive() - } -} - -impl<'a, S: PeripheralsOnUseSharedState> PeripheralsBuilder<'a, S> { - fn state_enum(&mut self) -> MutexGuard<'_, PeripheralsStateEnum> { - self.peripherals_state - .state - .lock() - .expect("shouldn't be poison") - } - #[track_caller] - pub fn peripheral( - &mut self, - id_name: impl AsRef, - is_input: bool, - ty: T, - ) -> Peripheral { - self.peripheral_with_on_use(id_name, is_input, ty, |_, _, _| {}) - } - #[track_caller] - pub fn peripheral_with_on_use( - &mut self, - id_name: impl AsRef, - is_input: bool, - ty: T, - on_use: impl FnOnce(&mut S, PeripheralRef<'_, T>, Expr) + Send + 'static, - ) -> Peripheral { - let mut state_enum = self.state_enum(); - let PeripheralsStateEnum::CollectingPeripherals(CollectingPeripherals { - conflicts_graph, - on_use_state: - PeripheralsOnUseState { - shared_state: _, - main_module_io_fields: _, - main_module_io_wires: _, - on_use_functions, - }, - }) = &mut *state_enum - else { - unreachable!(); - }; - let id = PeripheralId { - name: id_name.as_ref().intern(), - }; - let std::collections::btree_map::Entry::Vacant(entry) = conflicts_graph.entry(id) else { - drop(state_enum); // don't poison - panic!("duplicate peripheral: {id:?}"); - }; - entry.insert(BTreeSet::new()); - on_use_functions.insert( - id, - Box::new(move |state, peripheral_ref, wire| { - on_use( - ::downcast_mut::(PeripheralsOnUseSharedState::as_any(state)) - .expect("known to be correct type"), - PeripheralRef::from_canonical(peripheral_ref), - Expr::from_canonical(wire), - ) - }), - ); - drop(state_enum); - Peripheral { - ty, - common: PeripheralCommon { - type_id: TypeId::of::(), - id, - is_input, - peripherals_state: self.peripherals_state.clone(), - }, - } - } - #[track_caller] - pub fn input_peripheral_with_on_use( - &mut self, - id_name: impl AsRef, - ty: T, - on_use: impl FnOnce(&mut S, PeripheralRef<'_, T>, Expr) + Send + 'static, - ) -> Peripheral { - self.peripheral_with_on_use(id_name, true, ty, on_use) - } - #[track_caller] - pub fn output_peripheral_with_on_use( - &mut self, - id_name: impl AsRef, - ty: T, - on_use: impl FnOnce(&mut S, PeripheralRef<'_, T>, Expr) + Send + 'static, - ) -> Peripheral { - self.peripheral_with_on_use(id_name, false, ty, on_use) - } - #[track_caller] - pub fn input_peripheral(&mut self, id_name: impl AsRef, ty: T) -> Peripheral { - self.peripheral(id_name, true, ty) - } - #[track_caller] - pub fn output_peripheral(&mut self, id_name: impl AsRef, ty: T) -> Peripheral { - self.peripheral(id_name, false, ty) - } - #[track_caller] - pub fn add_conflicts(&mut self, conflicts: impl AsRef<[PeripheralId]>) { - let mut state_enum = self.state_enum(); - let PeripheralsStateEnum::CollectingPeripherals(collecting_peripherals) = &mut *state_enum - else { - unreachable!(); - }; - let conflicts = conflicts.as_ref(); - for &id in conflicts { - let Some(conflicts_for_id) = collecting_peripherals.conflicts_graph.get_mut(&id) else { - drop(state_enum); // don't poison - panic!("unknown peripheral: {id:?}"); - }; - conflicts_for_id.extend(conflicts.iter().copied().filter(|&v| v != id)); - } - } - pub fn finish(self) -> PeripheralsBuilderFinished<'a> { - self.peripherals_state.finish_collecting_peripherals(); - PeripheralsBuilderFinished { - _private: PhantomData, - } - } -} - -#[must_use] -pub struct Peripheral { - ty: T, - common: PeripheralCommon, -} - -impl Peripheral { - pub fn as_ref<'a>(&'a self) -> PeripheralRef<'a, T> { - let Self { ty, ref common } = *self; - PeripheralRef { ty, common } - } - pub fn ty(&self) -> T { - self.as_ref().ty() - } - pub fn id(&self) -> PeripheralId { - self.as_ref().id() - } - pub fn name(&self) -> Interned { - self.as_ref().name() - } - pub fn is_input(&self) -> bool { - self.as_ref().is_input() - } - pub fn is_output(&self) -> bool { - self.as_ref().is_output() - } - pub fn conflicts_with(&self) -> Interned> { - self.as_ref().conflicts_with() - } - pub fn availability(&self) -> PeripheralAvailability { - self.as_ref().availability() - } - pub fn is_available(&self) -> bool { - self.as_ref().is_available() - } - pub fn is_used(&self) -> bool { - self.as_ref().is_used() - } - pub fn try_into_used(self) -> Result, Self> { - let Some(building_module) = self.common.peripherals_state.building_module.get() else { - return Err(self); - }; - let building_module = building_module - .availabilities - .lock() - .expect("shouldn't be poison"); - match building_module[&self.common.id] { - PeripheralAvailability::Used => {} - PeripheralAvailability::Available | PeripheralAvailability::ConflictsWithUsed(_) => { - drop(building_module); - return Err(self); - } - } - drop(building_module); - let state = self - .common - .peripherals_state - .state - .lock() - .expect("shouldn't be poison"); - let output = match *state { - PeripheralsStateEnum::Initial | PeripheralsStateEnum::CollectingPeripherals(_) => { - unreachable!() - } - PeripheralsStateEnum::BuildingModule => { - drop(state); - return Err(self); - } - PeripheralsStateEnum::BuildingWrapperModule( - PeripheralsStateBuildingWrapperModule { - output: Some(output), - .. - }, - ) => output, - PeripheralsStateEnum::BuildingWrapperModule(_) => unreachable!(), - }; - drop(state); - let Self { ty, common } = self; - let instance_io_field = Expr::field(output, &common.id.name); - assert_eq!(ty, Expr::ty(instance_io_field)); - Ok(UsedPeripheral { - instance_io_field, - common, - }) - } - pub fn into_used(self) -> Option> { - self.try_into_used().ok() - } -} - -impl fmt::Debug for Peripheral { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.as_ref().debug_common_fields("Peripheral", f).finish() - } -} - -pub struct UsedPeripheral { - instance_io_field: Expr, - common: PeripheralCommon, -} - -impl fmt::Debug for UsedPeripheral { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.as_ref() - .debug_common_fields("UsedPeripheral", f) - .field("instance_io_field", &self.instance_io_field()) - .finish() - } -} - -impl UsedPeripheral { - pub fn as_ref<'a>(&'a self) -> PeripheralRef<'a, T> { - let Self { - instance_io_field, - ref common, - } = *self; - PeripheralRef { - ty: Expr::ty(instance_io_field), - common, - } - } - pub fn instance_io_field(&self) -> Expr { - self.instance_io_field - } - pub fn ty(&self) -> T { - self.as_ref().ty() - } - pub fn id(&self) -> PeripheralId { - self.as_ref().id() - } - pub fn name(&self) -> Interned { - self.as_ref().name() - } - pub fn is_input(&self) -> bool { - self.as_ref().is_input() - } - pub fn is_output(&self) -> bool { - self.as_ref().is_output() - } - pub fn conflicts_with(&self) -> Interned> { - self.as_ref().conflicts_with() - } -} - -#[derive(Copy, Clone)] -pub struct PeripheralRef<'a, T: Type> { - ty: T, - common: &'a PeripheralCommon, -} - -impl<'a, T: Type> fmt::Debug for PeripheralRef<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.debug_common_fields("PeripheralRef", f).finish() - } -} - -#[derive(Debug, Clone)] -pub enum PeripheralUnavailableError { - PeripheralAlreadyUsed { - id: PeripheralId, - }, - PeripheralConflict { - id: PeripheralId, - conflicting_id: PeripheralId, - }, - PeripheralsWillNotBeUsedToBuildWrapper, -} - -impl fmt::Display for PeripheralUnavailableError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::PeripheralAlreadyUsed { id } => { - write!(f, "peripherals can only be used once: {id:?}") - } - Self::PeripheralConflict { id, conflicting_id } => { - write!(f, "peripheral {id:?} conflicts with {conflicting_id:?}") - } - Self::PeripheralsWillNotBeUsedToBuildWrapper => { - write!(f, "peripherals will not be used to build wrapper") - } - } - } -} - -impl std::error::Error for PeripheralUnavailableError {} - -impl<'a, T: Type> PeripheralRef<'a, T> { - fn debug_common_fields<'f1, 'f2>( - &self, - struct_name: &str, - f: &'f1 mut fmt::Formatter<'f2>, - ) -> fmt::DebugStruct<'f1, 'f2> { - let Self { - ty, - common: - PeripheralCommon { - type_id: _, - id, - is_input, - peripherals_state: _, - }, - } = self; - let mut retval = f.debug_struct(struct_name); - retval - .field("ty", ty) - .field("id", id) - .field("is_input", is_input) - .field("availability", &self.availability()); - retval - } - pub fn ty(&self) -> T { - self.ty - } - pub fn id(&self) -> PeripheralId { - self.common.id - } - pub fn name(&self) -> Interned { - self.id().name - } - pub fn is_input(&self) -> bool { - self.common.is_input - } - pub fn is_output(&self) -> bool { - !self.common.is_input - } - pub fn conflicts_with(&self) -> Interned> { - match self.common.peripherals_state.building_module.get() { - Some(building_module) => building_module.conflicts_graph[&self.common.id], - None => match &*self - .common - .peripherals_state - .state - .lock() - .expect("shouldn't be poison") - { - PeripheralsStateEnum::CollectingPeripherals(v) => { - v.conflicts_graph[&self.common.id].intern() - } - PeripheralsStateEnum::Initial - | PeripheralsStateEnum::BuildingModule - | PeripheralsStateEnum::BuildingWrapperModule(_) => unreachable!(), - }, - } - } - pub fn availability(&self) -> PeripheralAvailability { - match self.common.peripherals_state.building_module.get() { - None => PeripheralAvailability::Available, - Some(building_module) => building_module - .availabilities - .lock() - .expect("shouldn't be poison")[&self.common.id], - } - } - pub fn is_available(&self) -> bool { - match self.common.peripherals_state.building_module.get() { - None => true, - Some(building_module) => match building_module - .availabilities - .lock() - .expect("shouldn't be poison")[&self.common.id] - { - PeripheralAvailability::Available => true, - PeripheralAvailability::Used | PeripheralAvailability::ConflictsWithUsed(_) => { - false - } - }, - } - } - pub fn is_used(&self) -> bool { - match self.common.peripherals_state.building_module.get() { - None => false, - Some(building_module) => match building_module - .availabilities - .lock() - .expect("shouldn't be poison")[&self.common.id] - { - PeripheralAvailability::Used => true, - PeripheralAvailability::Available - | PeripheralAvailability::ConflictsWithUsed(_) => false, - }, - } - } - pub fn canonical(self) -> PeripheralRef<'a, CanonicalType> { - let Self { ty, common } = self; - PeripheralRef { - ty: ty.canonical(), - common, - } - } - pub fn from_canonical(peripheral_ref: PeripheralRef<'a, CanonicalType>) -> Self { - let PeripheralRef { ty, common } = peripheral_ref; - Self { - ty: T::from_canonical(ty), - common, - } - } - #[track_caller] - pub fn try_use_peripheral(self) -> Result, PeripheralUnavailableError> { - self.try_use_peripheral_with_loc(SourceLocation::caller()) - } - #[track_caller] - pub fn try_use_peripheral_with_loc( - self, - source_location: SourceLocation, - ) -> Result, PeripheralUnavailableError> { - let PeripheralsState { - will_build_wrapper, - ref state, - ref building_module, - } = *self.common.peripherals_state; - if !will_build_wrapper { - return Err(PeripheralUnavailableError::PeripheralsWillNotBeUsedToBuildWrapper); - } - let Some(PeripheralsStateBuildingModule { - conflicts_graph, - availabilities, - on_use_state, - }) = building_module.get() - else { - panic!("can't use peripherals in a module before the PeripheralsBuilder is finished"); - }; - let state = state.lock().expect("shouldn't be poison"); - match *state { - PeripheralsStateEnum::Initial | PeripheralsStateEnum::CollectingPeripherals(_) => { - unreachable!() - } - PeripheralsStateEnum::BuildingModule => {} - PeripheralsStateEnum::BuildingWrapperModule(_) => { - panic!("can't add new peripherals after calling m.add_platform_io()") - } - } - drop(state); - let mut availabilities = availabilities.lock().expect("shouldn't be poison"); - let Some(availability) = availabilities.get_mut(&self.common.id) else { - unreachable!(); - }; - match *availability { - PeripheralAvailability::Available => { - *availability = PeripheralAvailability::Used; - } - PeripheralAvailability::Used => { - return Err(PeripheralUnavailableError::PeripheralAlreadyUsed { - id: self.common.id, - }); - } - PeripheralAvailability::ConflictsWithUsed(conflicting_id) => { - return Err(PeripheralUnavailableError::PeripheralConflict { - id: self.common.id, - conflicting_id, - }); - } - } - for conflict in conflicts_graph[&self.common.id].iter() { - let Some(availability) = availabilities.get_mut(conflict) else { - unreachable!(); - }; - *availability = PeripheralAvailability::ConflictsWithUsed(self.common.id); - } - drop(availabilities); - let wire = wire_with_loc(&self.name(), source_location, self.ty()); - let mut on_use_state = on_use_state.lock().expect("shouldn't be poison"); - let PeripheralsOnUseState { - shared_state, - main_module_io_fields, - main_module_io_wires, - on_use_functions, - } = &mut *on_use_state; - let Some(on_use_function) = on_use_functions.remove(&self.common.id) else { - unreachable!(); - }; - for conflict in conflicts_graph[&self.common.id].iter() { - on_use_functions.remove(conflict); - } - let canonical_wire = Expr::canonical(wire); - main_module_io_wires.push(canonical_wire); - main_module_io_fields.push(BundleField { - name: self.name(), - flipped: self.is_input(), - ty: Expr::ty(canonical_wire), - }); - on_use_function(&mut **shared_state, self.canonical(), canonical_wire); - drop(on_use_state); - Ok(wire) - } - #[track_caller] - pub fn use_peripheral_with_loc(self, source_location: SourceLocation) -> Expr { - match self.try_use_peripheral_with_loc(source_location) { - Ok(wire) => wire, - Err(e) => panic!("{e}"), - } - } - #[track_caller] - pub fn use_peripheral(self) -> Expr { - match self.try_use_peripheral() { - Ok(wire) => wire, - Err(e) => panic!("{e}"), - } - } -} - -pub trait Peripherals: 'static + Send + Sync + fmt::Debug { - fn append_peripherals<'a>(&'a self, peripherals: &mut Vec>); - fn to_peripherals_vec<'a>(&'a self) -> Vec> { - let mut peripherals = Vec::new(); - self.append_peripherals(&mut peripherals); - peripherals - } -} - -impl Peripherals for Peripheral { - fn append_peripherals<'a>(&'a self, peripherals: &mut Vec>) { - peripherals.push(self.as_ref().canonical()); - } -} - -impl Peripherals for Vec { - fn append_peripherals<'a>(&'a self, peripherals: &mut Vec>) { - for v in self { - v.append_peripherals(peripherals); - } - } -} - -impl Peripherals for Box { - fn append_peripherals<'a>(&'a self, peripherals: &mut Vec>) { - T::append_peripherals(self, peripherals); - } -} - -impl Peripherals for [T] { - fn append_peripherals<'a>(&'a self, peripherals: &mut Vec>) { - for v in self { - v.append_peripherals(peripherals); - } - } -} - -impl Peripherals for [T; N] { - fn append_peripherals<'a>(&'a self, peripherals: &mut Vec>) { - for v in self { - v.append_peripherals(peripherals); - } - } -} - -macro_rules! impl_peripherals { - (@impl $(($v:ident: $T:ident),)*) => { - impl<$($T: Peripherals),*> Peripherals for ($($T,)*) { - fn append_peripherals<'a>(&'a self, peripherals: &mut Vec>) { - #![allow(unused_variables)] - let ($($v,)*) = self; - $(Peripherals::append_peripherals($v, peripherals);)* - } - } - }; - ($($first:tt, $($rest:tt,)*)?) => { - impl_peripherals!(@impl $($first, $($rest,)*)?); - $(impl_peripherals!($($rest,)*);)? - }; -} - -impl_peripherals! { - (v0: T0), - (v1: T1), - (v2: T2), - (v3: T3), - (v4: T4), - (v5: T5), - (v6: T6), - (v7: T7), - (v8: T8), - (v9: T9), - (v10: T10), - (v11: T11), -} - -pub struct PlatformIOBuilder<'a> { - peripherals: Vec>, - peripherals_by_type_id: HashMap>>, - peripherals_by_id: BTreeMap>, - peripherals_state: &'a PeripheralsState, -} - -impl<'a> PlatformIOBuilder<'a> { - pub fn peripherals(&self) -> &[PeripheralRef<'a, CanonicalType>] { - &self.peripherals - } - pub fn peripherals_with_type(&self) -> Vec> { - let Some(peripherals) = self.peripherals_by_type_id.get(&TypeId::of::()) else { - return Vec::new(); - }; - peripherals - .iter() - .map(|&peripheral_ref| PeripheralRef::from_canonical(peripheral_ref)) - .collect() - } - pub fn peripherals_by_id(&self) -> &BTreeMap> { - &self.peripherals_by_id - } - #[track_caller] - pub(crate) fn add_platform_io( - self, - name: &str, - source_location: SourceLocation, - m: &ModuleBuilder, - ) -> Expr { - if !ModuleBuilder::with(|m2| std::ptr::eq(m, m2)) { - panic!("m.add_platform_io() must be called in the same module as m"); - } - let PeripheralsState { - will_build_wrapper: _, - state, - building_module, - } = self.peripherals_state; - let building_module = building_module.get().expect("shouldn't be None"); - let mut on_use_state = building_module - .on_use_state - .lock() - .expect("shouldn't be poison"); - let output_ty = - Bundle::new(mem::take(&mut on_use_state.main_module_io_fields).intern_deref()); - let main_module_wires = mem::take(&mut on_use_state.main_module_io_wires); - drop(on_use_state); - let output = m.output_with_loc(name, source_location, output_ty); - for (field, wire_expr) in output_ty.fields().iter().zip(main_module_wires) { - let ExprEnum::Wire(wire) = *Expr::expr_enum(wire_expr) else { - unreachable!(); - }; - let field_expr = Expr::field(output, &field.name); - if field.flipped { - connect_with_loc(wire, field_expr, wire.source_location()); - } else { - connect_with_loc(field_expr, wire, wire.source_location()); - } - } - let ExprEnum::ModuleIO(output_module_io) = *Expr::expr_enum(output) else { - unreachable!(); - }; - *state.lock().expect("shouldn't be poison") = - PeripheralsStateEnum::BuildingWrapperModule(PeripheralsStateBuildingWrapperModule { - output_module_io, - output: None, - }); - output - } -} - -impl<'a> fmt::Debug for PlatformIOBuilder<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - peripherals, - peripherals_by_type_id: _, - peripherals_by_id: _, - peripherals_state: _, - } = self; - f.debug_struct("PlatformIOBuilder") - .field("peripherals", peripherals) - .finish_non_exhaustive() - } -} - -trait PlatformAspectTrait: 'static + Send + Sync + fmt::Debug { - fn any_ref(&self) -> &dyn Any; - fn any_arc(self: Arc) -> Arc; - fn eq_dyn(&self, other: &dyn PlatformAspectTrait) -> bool; - fn hash_dyn(&self, state: &mut dyn Hasher); -} - -impl PlatformAspectTrait for T { - fn any_ref(&self) -> &dyn Any { - self - } - - fn any_arc(self: Arc) -> Arc { - self - } - - fn eq_dyn(&self, other: &dyn PlatformAspectTrait) -> bool { - other - .any_ref() - .downcast_ref::() - .is_some_and(|other| self == other) - } - - fn hash_dyn(&self, mut state: &mut dyn Hasher) { - self.hash(&mut state); - } -} - -#[derive(Clone)] -pub struct PlatformAspect { - type_id: TypeId, - type_name: &'static str, - value: Arc, -} - -impl Hash for PlatformAspect { - fn hash(&self, state: &mut H) { - PlatformAspectTrait::hash_dyn(&*self.value, state); - } -} - -impl Eq for PlatformAspect {} - -impl PartialEq for PlatformAspect { - fn eq(&self, other: &Self) -> bool { - self.type_id == other.type_id && PlatformAspectTrait::eq_dyn(&*self.value, &*other.value) - } -} - -impl fmt::Debug for PlatformAspect { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - type_id: _, - type_name, - value, - } = self; - write!(f, "PlatformAspect<{type_name}>")?; - f.debug_tuple("").field(value).finish() - } -} - -impl PlatformAspect { - pub fn new_arc(value: Arc) -> Self { - Self { - type_id: TypeId::of::(), - type_name: std::any::type_name::(), - value, - } - } - pub fn new(value: T) -> Self { - Self::new_arc(Arc::new(value)) - } - pub fn type_id(&self) -> TypeId { - self.type_id - } - pub fn downcast_arc(self) -> Result, Self> { - if self.type_id == TypeId::of::() { - let Ok(retval) = self.value.any_arc().downcast() else { - unreachable!(); - }; - Ok(retval) - } else { - Err(self) - } - } - pub fn downcast_unwrap_or_clone( - self, - ) -> Result { - Ok(Arc::unwrap_or_clone(self.downcast_arc()?)) - } - pub fn downcast_ref(&self) -> Option<&T> { - PlatformAspectTrait::any_ref(&*self.value).downcast_ref() - } -} - -#[derive(Clone, Default)] -pub struct PlatformAspectSet { - aspects_by_type_id: Arc>>, - aspects: Arc>, -} - -impl PlatformAspectSet { - pub fn new() -> Self { - Self::default() - } - pub fn insert_new( - &mut self, - value: T, - ) -> bool { - self.insert(PlatformAspect::new(value)) - } - pub fn insert_new_arc( - &mut self, - value: Arc, - ) -> bool { - self.insert(PlatformAspect::new_arc(value)) - } - fn insert_inner( - aspects_by_type_id: &mut HashMap>, - aspects: &mut Vec, - value: PlatformAspect, - ) -> bool { - if aspects_by_type_id - .entry(value.type_id) - .or_default() - .insert(value.clone()) - { - aspects.push(value); - true - } else { - false - } - } - pub fn insert(&mut self, value: PlatformAspect) -> bool { - Self::insert_inner( - Arc::make_mut(&mut self.aspects_by_type_id), - Arc::make_mut(&mut self.aspects), - value, - ) - } - pub fn contains(&self, value: &PlatformAspect) -> bool { - self.aspects_by_type_id - .get(&value.type_id) - .is_some_and(|aspects| aspects.contains(value)) - } - pub fn get_aspects_by_type<'a, T: 'static + Send + Sync + fmt::Debug + Hash + Eq>( - &'a self, - ) -> impl Clone + Iterator + FusedIterator + ExactSizeIterator + 'a - { - self.aspects_by_type_id - .get(&TypeId::of::()) - .map(|aspects| aspects.iter()) - .unwrap_or_default() - } - pub fn get_by_type<'a, T: 'static + Send + Sync + fmt::Debug + Hash + Eq>( - &'a self, - ) -> impl Clone + Iterator + FusedIterator + ExactSizeIterator + 'a { - self.get_aspects_by_type::() - .map(|aspect| aspect.downcast_ref().expect("already checked type")) - } - pub fn get_single_by_type<'a, T: 'static + Send + Sync + fmt::Debug + Hash + Eq>( - &'a self, - ) -> Option<&'a T> { - let mut aspects = self.get_by_type::(); - if aspects.len() == 1 { - aspects.next() - } else { - None - } - } - pub fn get_arcs_by_type<'a, T: 'static + Send + Sync + fmt::Debug + Hash + Eq>( - &'a self, - ) -> impl Clone + Iterator> + FusedIterator + ExactSizeIterator + 'a { - self.get_aspects_by_type::().map(|aspect| { - aspect - .clone() - .downcast_arc() - .ok() - .expect("already checked type") - }) - } -} - -impl<'a> Extend<&'a PlatformAspect> for PlatformAspectSet { - fn extend>(&mut self, iter: T) { - self.extend(iter.into_iter().cloned()); - } -} - -impl Extend for PlatformAspectSet { - fn extend>(&mut self, iter: T) { - let Self { - aspects_by_type_id, - aspects, - } = self; - let aspects_by_type_id = Arc::make_mut(aspects_by_type_id); - let aspects = Arc::make_mut(aspects); - iter.into_iter().for_each(|value| { - Self::insert_inner(aspects_by_type_id, aspects, value); - }); - } -} - -impl<'a> FromIterator<&'a PlatformAspect> for PlatformAspectSet { - fn from_iter>(iter: T) -> Self { - let mut retval = Self::default(); - retval.extend(iter); - retval - } -} - -impl FromIterator for PlatformAspectSet { - fn from_iter>(iter: T) -> Self { - let mut retval = Self::default(); - retval.extend(iter); - retval - } -} - -impl std::ops::Deref for PlatformAspectSet { - type Target = [PlatformAspect]; - - fn deref(&self) -> &Self::Target { - &self.aspects - } -} - -impl fmt::Debug for PlatformAspectSet { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_set().entries(self).finish() - } -} - -impl IntoIterator for PlatformAspectSet { - type Item = PlatformAspect; - type IntoIter = PlatformAspectsIntoIter; - - fn into_iter(self) -> Self::IntoIter { - PlatformAspectsIntoIter { - indexes: 0..self.aspects.len(), - aspects: self.aspects, - } - } -} - -impl<'a> IntoIterator for &'a PlatformAspectSet { - type Item = &'a PlatformAspect; - type IntoIter = std::slice::Iter<'a, PlatformAspect>; - - fn into_iter(self) -> Self::IntoIter { - self.aspects.iter() - } -} - -#[derive(Clone, Debug)] -pub struct PlatformAspectsIntoIter { - aspects: Arc>, - indexes: std::ops::Range, -} - -impl Iterator for PlatformAspectsIntoIter { - type Item = PlatformAspect; - - fn next(&mut self) -> Option { - self.indexes.next().map(|index| self.aspects[index].clone()) - } - - fn size_hint(&self) -> (usize, Option) { - self.indexes.size_hint() - } - - fn count(self) -> usize { - self.indexes.len() - } - - fn last(mut self) -> Option { - self.next_back() - } - - fn nth(&mut self, n: usize) -> Option { - self.indexes.nth(n).map(|index| self.aspects[index].clone()) - } - - fn fold(self, init: B, mut f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.indexes - .fold(init, |v, index| f(v, self.aspects[index].clone())) - } -} - -impl FusedIterator for PlatformAspectsIntoIter {} - -impl ExactSizeIterator for PlatformAspectsIntoIter {} - -impl DoubleEndedIterator for PlatformAspectsIntoIter { - fn next_back(&mut self) -> Option { - self.indexes - .next_back() - .map(|index| self.aspects[index].clone()) - } - - fn nth_back(&mut self, n: usize) -> Option { - self.indexes - .nth_back(n) - .map(|index| self.aspects[index].clone()) - } - - fn rfold(self, init: B, mut f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.indexes - .rfold(init, |v, index| f(v, self.aspects[index].clone())) - } -} - -pub trait Platform: Clone + 'static + Send + Sync + fmt::Debug + Hash + Eq { - type Peripherals: Peripherals; - fn name(&self) -> Interned; - fn new_peripherals<'builder>( - &self, - builder_factory: PeripheralsBuilderFactory<'builder>, - ) -> (Self::Peripherals, PeripheralsBuilderFinished<'builder>); - /// gets peripherals that can be used for inspecting them, but not for building a main module - fn get_peripherals(&self) -> Self::Peripherals { - let ( - retval, - PeripheralsBuilderFinished { - _private: PhantomData, - }, - ) = self.new_peripherals(PeripheralsBuilderFactory::new(false)); - retval - } - fn source_location(&self) -> SourceLocation; - fn add_peripherals_in_wrapper_module(&self, m: &ModuleBuilder, peripherals: Self::Peripherals); - #[track_caller] - fn try_wrap_main_module< - T: BundleType, - E, - M: AsRef>, - F: for<'a> FnOnce(PlatformIOBuilder<'a>) -> Result, - >( - &self, - make_main_module: F, - ) -> Result>, E> { - let builder_factory = PeripheralsBuilderFactory::new(true); - let peripherals_state = builder_factory.peripherals_state.clone(); - let ( - peripherals, - PeripheralsBuilderFinished { - _private: PhantomData, - }, - ) = self.new_peripherals(builder_factory); - let peripherals_vec = peripherals.to_peripherals_vec(); - let mut peripherals_by_id = BTreeMap::new(); - let mut peripherals_by_type_id = HashMap::<_, Vec<_>>::default(); - for &peripheral in &peripherals_vec { - peripherals_by_id.insert(peripheral.id(), peripheral); - peripherals_by_type_id - .entry(peripheral.common.type_id) - .or_default() - .push(peripheral); - } - let main_module = Module::canonical( - *make_main_module(PlatformIOBuilder { - peripherals: peripherals_vec, - peripherals_by_type_id, - peripherals_by_id, - peripherals_state: &peripherals_state, - })? - .as_ref(), - ); - let state = peripherals_state.state.lock().expect("shouldn't be poison"); - let PeripheralsStateEnum::BuildingWrapperModule(PeripheralsStateBuildingWrapperModule { - output_module_io, - output: _, - }) = *state - else { - drop(state); - panic!( - "you need to call m.add_platform_io() inside the main module you're trying to use peripherals in.\nat: {}", - main_module.source_location() - ); - }; - drop(state); - for module_io in main_module.module_io() { - if module_io.module_io != output_module_io { - panic!( - "when you're using m.add_platform_io(), you can't have any other inputs/outputs.\nat: {}", - module_io.module_io.source_location() - ); - } - } - Ok(ModuleBuilder::run_with_loc( - &main_module.name(), - self.source_location(), - crate::module::ModuleKind::Normal, - |m| { - let instance = - instance_with_loc("main", main_module.intern(), self.source_location()); - let output_expr = Expr::field(instance, &output_module_io.bundle_field().name); - let mut state = peripherals_state.state.lock().expect("shouldn't be poison"); - let PeripheralsStateEnum::BuildingWrapperModule( - PeripheralsStateBuildingWrapperModule { - output_module_io: _, - output, - }, - ) = &mut *state - else { - unreachable!(); - }; - *output = Some(output_expr); - drop(state); - self.add_peripherals_in_wrapper_module(m, peripherals) - }, - )) - } - #[track_caller] - fn wrap_main_module< - T: BundleType, - M: AsRef>, - F: for<'a> FnOnce(PlatformIOBuilder<'a>) -> M, - >( - &self, - make_main_module: F, - ) -> Interned> { - self.try_wrap_main_module(|p| Ok(make_main_module(p))) - .unwrap_or_else(|e: Infallible| match e {}) - } - fn aspects(&self) -> PlatformAspectSet; -} - -impl DynPlatform { - pub fn registry() -> PlatformRegistrySnapshot { - PlatformRegistrySnapshot(PlatformRegistry::get()) - } - #[track_caller] - pub fn register(self) { - PlatformRegistry::register(PlatformRegistry::lock(), self); - } -} - -#[derive(Clone, Debug)] -struct PlatformRegistry { - platforms: BTreeMap, -} - -enum PlatformRegisterError { - SameName { - name: InternedStrCompareAsStr, - old_platform: DynPlatform, - new_platform: DynPlatform, - }, -} - -impl fmt::Display for PlatformRegisterError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::SameName { - name, - old_platform, - new_platform, - } => write!( - f, - "two different `Platform` can't share the same name:\n\ - {name:?}\n\ - old platform:\n\ - {old_platform:?}\n\ - new platform:\n\ - {new_platform:?}", - ), - } - } -} - -trait PlatformRegistryRegisterLock { - type Locked; - fn lock(self) -> Self::Locked; - fn make_mut(locked: &mut Self::Locked) -> &mut PlatformRegistry; -} - -impl PlatformRegistryRegisterLock for &'static RwLock> { - type Locked = RwLockWriteGuard<'static, Arc>; - fn lock(self) -> Self::Locked { - self.write().expect("shouldn't be poisoned") - } - fn make_mut(locked: &mut Self::Locked) -> &mut PlatformRegistry { - Arc::make_mut(locked) - } -} - -impl PlatformRegistryRegisterLock for &'_ mut PlatformRegistry { - type Locked = Self; - - fn lock(self) -> Self::Locked { - self - } - - fn make_mut(locked: &mut Self::Locked) -> &mut PlatformRegistry { - locked - } -} - -impl PlatformRegistry { - fn lock() -> &'static RwLock> { - static REGISTRY: OnceLock>> = OnceLock::new(); - REGISTRY.get_or_init(Default::default) - } - fn try_register( - lock: L, - platform: DynPlatform, - ) -> Result<(), PlatformRegisterError> { - use std::collections::btree_map::Entry; - let name = InternedStrCompareAsStr(platform.name()); - // run user code only outside of lock - let mut locked = lock.lock(); - let this = L::make_mut(&mut locked); - let result = match this.platforms.entry(name) { - Entry::Occupied(entry) => Err(PlatformRegisterError::SameName { - name, - old_platform: entry.get().clone(), - new_platform: platform, - }), - Entry::Vacant(entry) => { - entry.insert(platform); - Ok(()) - } - }; - drop(locked); - // outside of lock now, so we can test if it's the same DynPlatform - match result { - Err(PlatformRegisterError::SameName { - name: _, - old_platform, - new_platform, - }) if old_platform == new_platform => Ok(()), - result => result, - } - } - #[track_caller] - fn register(lock: L, platform: DynPlatform) { - match Self::try_register(lock, platform) { - Err(e) => panic!("{e}"), - Ok(()) => {} - } - } - fn get() -> Arc { - Self::lock().read().expect("shouldn't be poisoned").clone() - } -} - -impl Default for PlatformRegistry { - fn default() -> Self { - let mut retval = Self { - platforms: BTreeMap::new(), - }; - for platform in built_in_platforms() { - Self::register(&mut retval, platform); - } - retval - } -} - -#[derive(Clone, Debug)] -pub struct PlatformRegistrySnapshot(Arc); - -impl PlatformRegistrySnapshot { - pub fn get() -> Self { - PlatformRegistrySnapshot(PlatformRegistry::get()) - } - pub fn get_by_name<'a>(&'a self, name: &str) -> Option<&'a DynPlatform> { - self.0.platforms.get(name) - } - pub fn iter_with_names(&self) -> PlatformRegistryIterWithNames<'_> { - PlatformRegistryIterWithNames(self.0.platforms.iter()) - } - pub fn iter(&self) -> PlatformRegistryIter<'_> { - PlatformRegistryIter(self.0.platforms.values()) - } -} - -impl<'a> IntoIterator for &'a PlatformRegistrySnapshot { - type Item = &'a DynPlatform; - type IntoIter = PlatformRegistryIter<'a>; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl<'a> IntoIterator for &'a mut PlatformRegistrySnapshot { - type Item = &'a DynPlatform; - type IntoIter = PlatformRegistryIter<'a>; - - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -#[derive(Clone, Debug)] -pub struct PlatformRegistryIter<'a>( - std::collections::btree_map::Values<'a, InternedStrCompareAsStr, DynPlatform>, -); - -impl<'a> Iterator for PlatformRegistryIter<'a> { - type Item = &'a DynPlatform; - - fn next(&mut self) -> Option { - self.0.next() - } - - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - - fn count(self) -> usize - where - Self: Sized, - { - self.0.count() - } - - fn last(self) -> Option { - self.0.last() - } - - fn nth(&mut self, n: usize) -> Option { - self.0.nth(n) - } - - fn fold(self, init: B, f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.0.fold(init, f) - } -} - -impl<'a> std::iter::FusedIterator for PlatformRegistryIter<'a> {} - -impl<'a> ExactSizeIterator for PlatformRegistryIter<'a> {} - -impl<'a> DoubleEndedIterator for PlatformRegistryIter<'a> { - fn next_back(&mut self) -> Option { - self.0.next_back() - } - - fn nth_back(&mut self, n: usize) -> Option { - self.0.nth_back(n) - } - - fn rfold(self, init: B, f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.0.rfold(init, f) - } -} - -#[derive(Clone, Debug)] -pub struct PlatformRegistryIterWithNames<'a>( - std::collections::btree_map::Iter<'a, InternedStrCompareAsStr, DynPlatform>, -); - -impl<'a> Iterator for PlatformRegistryIterWithNames<'a> { - type Item = (Interned, &'a DynPlatform); - - fn next(&mut self) -> Option { - self.0.next().map(|(name, platform)| (name.0, platform)) - } - - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - - fn count(self) -> usize - where - Self: Sized, - { - self.0.count() - } - - fn last(self) -> Option { - self.0.last().map(|(name, platform)| (name.0, platform)) - } - - fn nth(&mut self, n: usize) -> Option { - self.0.nth(n).map(|(name, platform)| (name.0, platform)) - } - - fn fold(self, init: B, f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.0 - .map(|(name, platform)| (name.0, platform)) - .fold(init, f) - } -} - -impl<'a> std::iter::FusedIterator for PlatformRegistryIterWithNames<'a> {} - -impl<'a> ExactSizeIterator for PlatformRegistryIterWithNames<'a> {} - -impl<'a> DoubleEndedIterator for PlatformRegistryIterWithNames<'a> { - fn next_back(&mut self) -> Option { - self.0 - .next_back() - .map(|(name, platform)| (name.0, platform)) - } - - fn nth_back(&mut self, n: usize) -> Option { - self.0 - .nth_back(n) - .map(|(name, platform)| (name.0, platform)) - } - - fn rfold(self, init: B, f: F) -> B - where - F: FnMut(B, Self::Item) -> B, - { - self.0 - .map(|(name, platform)| (name.0, platform)) - .rfold(init, f) - } -} - -#[track_caller] -pub fn register_platform(kind: K) { - DynPlatform::new(kind).register(); -} - -impl Serialize for DynPlatform { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.name().serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for DynPlatform { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let name = Cow::::deserialize(deserializer)?; - match Self::registry().get_by_name(&name) { - Some(retval) => Ok(retval.clone()), - None => Err(D::Error::custom(format_args!( - "unknown platform: name not found in registry: {name:?}" - ))), - } - } -} - -#[derive(Copy, Clone, Debug, Default)] -pub struct DynPlatformValueParser; - -#[derive(Clone, PartialEq, Eq, Hash)] -struct DynPlatformValueEnum { - name: Interned, - platform: DynPlatform, -} - -impl clap::ValueEnum for DynPlatformValueEnum { - fn value_variants<'a>() -> &'a [Self] { - Interned::into_inner( - PlatformRegistrySnapshot::get() - .iter_with_names() - .map(|(name, platform)| Self { - name, - platform: platform.clone(), - }) - .collect(), - ) - } - - fn to_possible_value(&self) -> Option { - Some(clap::builder::PossibleValue::new(Interned::into_inner( - self.name, - ))) - } -} - -impl clap::builder::TypedValueParser for DynPlatformValueParser { - type Value = DynPlatform; - - fn parse_ref( - &self, - cmd: &clap::Command, - arg: Option<&clap::Arg>, - value: &std::ffi::OsStr, - ) -> clap::error::Result { - clap::builder::EnumValueParser::::new() - .parse_ref(cmd, arg, value) - .map(|v| v.platform) - } - - fn possible_values( - &self, - ) -> Option + '_>> { - static ENUM_VALUE_PARSER: OnceLock> = - OnceLock::new(); - ENUM_VALUE_PARSER - .get_or_init(clap::builder::EnumValueParser::::new) - .possible_values() - } -} - -impl clap::builder::ValueParserFactory for DynPlatform { - type Parser = DynPlatformValueParser; - - fn value_parser() -> Self::Parser { - DynPlatformValueParser::default() - } -} - -pub(crate) fn built_in_platforms() -> impl IntoIterator { - crate::vendor::built_in_platforms() -} diff --git a/crates/fayalite/src/platform/peripherals.rs b/crates/fayalite/src/platform/peripherals.rs deleted file mode 100644 index 90c6640..0000000 --- a/crates/fayalite/src/platform/peripherals.rs +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{intern::Intern, prelude::*}; -use ordered_float::NotNan; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -#[non_exhaustive] -pub struct ClockInputProperties { - pub frequency: NotNan, -} - -#[hdl(no_runtime_generics, no_static)] -pub struct ClockInput { - pub clk: Clock, - pub properties: PhantomConst, -} - -impl ClockInput { - #[track_caller] - pub fn new(frequency: f64) -> Self { - assert!( - frequency > 0.0 && frequency.is_finite(), - "invalid clock frequency: {frequency}" - ); - Self { - clk: Clock, - properties: PhantomConst::new( - ClockInputProperties { - frequency: NotNan::new(frequency).expect("just checked"), - } - .intern_sized(), - ), - } - } - pub fn frequency(self) -> f64 { - self.properties.get().frequency.into_inner() - } -} - -#[hdl] -pub struct Led { - pub on: Bool, -} - -#[hdl] -pub struct RgbLed { - pub r: Bool, - pub g: Bool, - pub b: Bool, -} - -#[hdl] -/// UART, used as an output from the FPGA -pub struct Uart { - /// transmit from the FPGA's perspective - pub tx: Bool, - /// receive from the FPGA's perspective - #[hdl(flip)] - pub rx: Bool, -} diff --git a/crates/fayalite/src/prelude.rs b/crates/fayalite/src/prelude.rs index 4cc173e..9e7a85e 100644 --- a/crates/fayalite/src/prelude.rs +++ b/crates/fayalite/src/prelude.rs @@ -1,45 +1,36 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information pub use crate::{ - __, annotations::{ BlackBoxInlineAnnotation, BlackBoxPathAnnotation, CustomFirrtlAnnotation, DocStringAnnotation, DontTouchAnnotation, SVAttributeAnnotation, }, array::{Array, ArrayType}, - build::{BuildCli, JobParams, RunBuild}, bundle::Bundle, + cli::Cli, clock::{Clock, ClockDomain, ToClock}, enum_::{Enum, HdlNone, HdlOption, HdlSome}, expr::{ - CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, MakeUninitExpr, - ReduceBits, ToExpr, repeat, + repeat, CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, MakeUninitExpr, + ReduceBits, ToExpr, }, formal::{ - MakeFormalExpr, all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset, - hdl_assert, hdl_assert_with_enable, hdl_assume, hdl_assume_with_enable, hdl_cover, - hdl_cover_with_enable, + all_const, all_seq, any_const, any_seq, formal_global_clock, formal_reset, hdl_assert, + hdl_assert_with_enable, hdl_assume, hdl_assume_with_enable, hdl_cover, + hdl_cover_with_enable, MakeFormalExpr, }, hdl, hdl_module, - int::{Bool, DynSize, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue}, + int::{Bool, DynSize, KnownSize, SInt, SIntType, Size, UInt, UIntType}, memory::{Mem, MemBuilder, ReadUnderWrite}, module::{ - Instance, Module, ModuleBuilder, annotate, connect, connect_any, incomplete_wire, instance, - memory, memory_array, memory_with_init, reg_builder, wire, + annotate, connect, connect_any, incomplete_wire, instance, memory, memory_array, + memory_with_init, reg_builder, wire, Instance, Module, ModuleBuilder, }, - phantom_const::{PhantomConst, PhantomConstGet}, - platform::{DynPlatform, Platform, PlatformIOBuilder, peripherals}, reg::Reg, reset::{AsyncReset, Reset, SyncReset, ToAsyncReset, ToReset, ToSyncReset}, - sim::{ - ExternModuleSimulationState, Simulation, - time::{SimDuration, SimInstant}, - value::{SimOnly, SimOnlyValue, SimValue, ToSimValue, ToSimValueWithType}, - }, source_location::SourceLocation, - testing::{FormalMode, assert_formal}, ty::{AsMask, CanonicalType, Type}, util::{ConstUsize, GenericConstUsize}, wire::Wire, + __, }; -pub use bitvec::{slice::BitSlice, vec::BitVec}; diff --git a/crates/fayalite/src/reset.rs b/crates/fayalite/src/reset.rs index 5dff278..9328365 100644 --- a/crates/fayalite/src/reset.rs +++ b/crates/fayalite/src/reset.rs @@ -2,15 +2,11 @@ // See Notices.txt for copyright information use crate::{ clock::Clock, - expr::{Expr, ToExpr, ops}, + expr::{ops, Expr, ToExpr}, int::{Bool, SInt, UInt}, source_location::SourceLocation, - ty::{ - CanonicalType, OpaqueSimValueSize, OpaqueSimValueSlice, OpaqueSimValueWriter, - OpaqueSimValueWritten, StaticType, Type, TypeProperties, impl_match_variant_as_self, - }, + ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties}, }; -use bitvec::{bits, order::Lsb0}; mod sealed { pub trait ResetTypeSealed {} @@ -49,7 +45,6 @@ macro_rules! reset_type { impl Type for $name { type BaseType = $name; type MaskType = Bool; - type SimValue = bool; impl_match_variant_as_self!(); @@ -71,31 +66,6 @@ macro_rules! reset_type { }; retval } - - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); - opaque.bits()[0] - } - - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ) { - assert_eq!(opaque.size(), OpaqueSimValueSize::from_bit_width(1)); - *value = opaque.bits()[0]; - } - - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> OpaqueSimValueWritten<'w> { - assert_eq!(writer.size(), OpaqueSimValueSize::from_bit_width(1)); - writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_bitslice( - [bits![0], bits![1]][*value as usize], - )) - } } impl $name { @@ -115,7 +85,6 @@ macro_rules! reset_type { is_storable: false, is_castable_from_bits: $is_castable_from_bits, bit_width: 1, - sim_only_values_len: 0, }; const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; } diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index 44030c1..cb6228d 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -5,68 +5,5007 @@ use crate::{ bundle::{BundleField, BundleType}, + enum_::{EnumType, EnumVariant}, expr::{ - Flow, ToLiteralBits, + ops, target::{ - GetTarget, Target, TargetPathArrayElement, TargetPathBundleField, TargetPathElement, + GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, + TargetPathElement, }, + ExprEnum, Flow, ToLiteralBits, }, - int::BoolOrIntType, - intern::{ - Intern, InternSlice, Interned, InternedCompare, PtrEqWithTypeId, SupportsPtrEqWithTypeId, - }, + int::{BoolOrIntType, IntType, SIntValue, UIntValue}, + intern::{Intern, Interned, Memoize}, + memory::PortKind, module::{ - ModuleIO, - transform::visit::{Fold, Folder, Visit, Visitor}, + transform::deduce_resets::deduce_resets, AnnotatedModuleIO, Block, Id, InstantiatedModule, + ModuleBody, NameId, NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, + StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, TargetInInstantiatedModule, }, prelude::*, - reset::ResetType, + reset::{ResetType, ResetTypeDispatch}, sim::{ - compiler::{ - Compiled, CompiledBundleField, CompiledExternModule, CompiledTypeLayoutBody, - CompiledValue, - }, interpreter::{ - BreakAction, BreakpointsSet, RunResult, SmallUInt, State, - parts::{ - StatePartIndex, StatePartKindBigSlots, StatePartKindMemories, - StatePartKindSimOnlySlots, StatePartKindSmallSlots, TypeIndexRange, TypeLenSingle, - }, + BreakAction, BreakpointsSet, Insn, InsnField, InsnFieldKind, InsnFieldType, + InsnOrLabel, Insns, InsnsBuilding, InsnsBuildingDone, InsnsBuildingKind, Label, + MemoryData, RunResult, SlotDebugData, SmallUInt, State, StatePartArrayIndex, + StatePartArrayIndexed, StatePartIndex, StatePartIndexRange, StatePartKind, + StatePartKindBigSlots, StatePartKindMemories, StatePartKindSmallSlots, StatePartLayout, + StatePartLen, StatePartsValue, TypeArrayIndex, TypeArrayIndexes, TypeIndex, + TypeIndexRange, TypeLayout, TypeLen, TypeParts, }, time::{SimDuration, SimInstant}, - value::{DynSimOnly, DynSimOnlyValue, SimValue}, }, - ty::{ - OpaqueSimValue, OpaqueSimValueSize, OpaqueSimValueSizeRange, OpaqueSimValueSlice, - OpaqueSimValueWriter, - }, - util::{BitSliceWriteWithBase, DebugAsDisplay, HashMap, HashSet}, + ty::StaticType, + util::{BitSliceWriteWithBase, DebugAsDisplay}, }; use bitvec::{bits, order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView}; +use hashbrown::{HashMap, HashSet}; use num_bigint::BigInt; use num_traits::{Signed, Zero}; +use petgraph::{ + data::FromElements, + visit::{ + EdgeRef, GraphBase, IntoEdgeReferences, IntoNeighbors, IntoNeighborsDirected, + IntoNodeIdentifiers, IntoNodeReferences, NodeRef, VisitMap, Visitable, + }, +}; use std::{ - any::Any, - borrow::Cow, - cell::RefCell, - collections::BTreeMap, - fmt, - future::{Future, IntoFuture}, - hash::Hash, - mem, - pin::Pin, - ptr, - rc::Rc, - sync::Arc, - task::Poll, + borrow::Cow, collections::BTreeSet, fmt, marker::PhantomData, mem, ops::IndexMut, sync::Arc, }; -pub mod compiler; mod interpreter; pub mod time; -pub mod value; pub mod vcd; +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +enum CondBody { + IfTrue { + cond: CompiledValue, + }, + IfFalse { + cond: CompiledValue, + }, + MatchArm { + discriminant: StatePartIndex, + variant_index: usize, + }, +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +struct Cond { + body: CondBody, + source_location: SourceLocation, +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +struct CompiledBundleField { + offset: TypeIndex, + ty: CompiledTypeLayout, +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +enum CompiledTypeLayoutBody { + Scalar, + Array { + /// debug names are ignored, use parent's layout instead + element: Interned>, + }, + Bundle { + /// debug names are ignored, use parent's layout instead + fields: Interned<[CompiledBundleField]>, + }, +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +struct CompiledTypeLayout { + ty: T, + layout: TypeLayout, + body: CompiledTypeLayoutBody, +} + +impl CompiledTypeLayout { + fn with_prefixed_debug_names(self, prefix: &str) -> Self { + let Self { ty, layout, body } = self; + Self { + ty, + layout: layout.with_prefixed_debug_names(prefix), + body, + } + } + fn with_anonymized_debug_info(self) -> Self { + let Self { ty, layout, body } = self; + Self { + ty, + layout: layout.with_anonymized_debug_info(), + body, + } + } + fn get(ty: T) -> Self { + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] + struct MyMemoize; + impl Memoize for MyMemoize { + type Input = CanonicalType; + type InputOwned = CanonicalType; + type Output = CompiledTypeLayout; + + fn inner(self, input: &Self::Input) -> Self::Output { + match input { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::Enum(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) => { + let mut layout = TypeLayout::empty(); + let debug_data = SlotDebugData { + name: Interned::default(), + ty: *input, + }; + layout.big_slots = StatePartLayout::scalar(debug_data, ()); + CompiledTypeLayout { + ty: *input, + layout: layout.into(), + body: CompiledTypeLayoutBody::Scalar, + } + } + CanonicalType::Array(array) => { + let mut layout = TypeLayout::empty(); + let element = CompiledTypeLayout::get(array.element()).intern_sized(); + for index in 0..array.len() { + layout.allocate( + &element + .layout + .with_prefixed_debug_names(&format!("[{index}]")), + ); + } + CompiledTypeLayout { + ty: *input, + layout: layout.into(), + body: CompiledTypeLayoutBody::Array { element }, + } + } + CanonicalType::Bundle(bundle) => { + let mut layout = TypeLayout::empty(); + let fields = bundle + .fields() + .iter() + .map( + |BundleField { + name, + flipped: _, + ty, + }| { + let ty = CompiledTypeLayout::get(*ty); + let offset = layout + .allocate( + &ty.layout + .with_prefixed_debug_names(&format!(".{name}")), + ) + .start(); + CompiledBundleField { offset, ty } + }, + ) + .collect(); + CompiledTypeLayout { + ty: *input, + layout: layout.into(), + body: CompiledTypeLayoutBody::Bundle { fields }, + } + } + } + } + } + let CompiledTypeLayout { + ty: _, + layout, + body, + } = MyMemoize.get_owned(ty.canonical()); + Self { ty, layout, body } + } +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +struct CompiledValue { + layout: CompiledTypeLayout, + range: TypeIndexRange, + write: Option<(CompiledTypeLayout, TypeIndexRange)>, +} + +impl CompiledValue { + fn write(self) -> (CompiledTypeLayout, TypeIndexRange) { + self.write.unwrap_or((self.layout, self.range)) + } + fn write_value(self) -> Self { + let (layout, range) = self.write(); + Self { + layout, + range, + write: None, + } + } + fn map( + self, + mut f: impl FnMut( + CompiledTypeLayout, + TypeIndexRange, + ) -> (CompiledTypeLayout, TypeIndexRange), + ) -> CompiledValue { + let (layout, range) = f(self.layout, self.range); + CompiledValue { + layout, + range, + write: self.write.map(|(layout, range)| f(layout, range)), + } + } + fn map_ty(self, mut f: impl FnMut(T) -> U) -> CompiledValue { + self.map(|CompiledTypeLayout { ty, layout, body }, range| { + ( + CompiledTypeLayout { + ty: f(ty), + layout, + body, + }, + range, + ) + }) + } +} + +impl CompiledValue { + fn field_by_index(self, field_index: usize) -> CompiledValue { + self.map(|layout, range| { + let CompiledTypeLayout { + ty: _, + layout: _, + body: CompiledTypeLayoutBody::Bundle { fields }, + } = layout + else { + unreachable!(); + }; + ( + fields[field_index].ty, + range.slice(TypeIndexRange::new( + fields[field_index].offset, + fields[field_index].ty.layout.len(), + )), + ) + }) + } + fn field_by_name(self, name: Interned) -> CompiledValue { + self.field_by_index(self.layout.ty.name_indexes()[&name]) + } +} + +impl CompiledValue { + fn element(self, index: usize) -> CompiledValue { + self.map(|layout, range| { + let CompiledTypeLayoutBody::Array { element } = layout.body else { + unreachable!(); + }; + (*element, range.index_array(element.layout.len(), index)) + }) + } + fn element_dyn( + self, + index_slot: StatePartIndex, + ) -> CompiledExpr { + CompiledExpr::from(self).element_dyn(index_slot) + } +} + +#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] +struct CompiledExpr { + static_part: CompiledValue, + indexes: TypeArrayIndexes, +} + +impl From> for CompiledExpr { + fn from(static_part: CompiledValue) -> Self { + Self { + static_part, + indexes: TypeArrayIndexes::default(), + } + } +} + +impl CompiledExpr { + fn map_ty(self, f: impl FnMut(T) -> U) -> CompiledExpr { + let Self { + static_part, + indexes, + } = self; + CompiledExpr { + static_part: static_part.map_ty(f), + indexes, + } + } + fn add_target_without_indexes_to_set(self, inputs: &mut SlotSet) { + let Self { + static_part, + indexes, + } = self; + indexes.as_ref().for_each_offset(|offset| { + inputs.extend([static_part.range.offset(offset)]); + }); + } + fn add_target_and_indexes_to_set(self, inputs: &mut SlotSet) { + let Self { + static_part: _, + indexes, + } = self; + self.add_target_without_indexes_to_set(inputs); + inputs.extend(indexes.as_ref().iter()); + } +} + +impl CompiledExpr { + fn field_by_index(self, field_index: usize) -> CompiledExpr { + CompiledExpr { + static_part: self.static_part.field_by_index(field_index), + indexes: self.indexes, + } + } + fn field_by_name(self, name: Interned) -> CompiledExpr { + CompiledExpr { + static_part: self.static_part.field_by_name(name), + indexes: self.indexes, + } + } +} + +impl CompiledExpr { + fn element(self, index: usize) -> CompiledExpr { + CompiledExpr { + static_part: self.static_part.element(index), + indexes: self.indexes, + } + } + fn element_dyn( + self, + index_slot: StatePartIndex, + ) -> CompiledExpr { + let CompiledTypeLayoutBody::Array { element } = self.static_part.layout.body else { + unreachable!(); + }; + let stride = element.layout.len(); + let indexes = self.indexes.join(TypeArrayIndex::from_parts( + index_slot, + self.static_part.layout.ty.len(), + stride, + )); + CompiledExpr { + static_part: self.static_part.map(|layout, range| { + let CompiledTypeLayoutBody::Array { element } = layout.body else { + unreachable!(); + }; + (*element, range.index_array(stride, 0)) + }), + indexes, + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +enum AssignmentOrSlotIndex { + AssignmentIndex(usize), + SmallSlot(StatePartIndex), + BigSlot(StatePartIndex), +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +enum AssignmentIO { + BigInput { + assignment_index: usize, + slot: StatePartIndex, + }, + SmallInput { + assignment_index: usize, + slot: StatePartIndex, + }, + BigOutput { + assignment_index: usize, + slot: StatePartIndex, + }, + SmallOutput { + assignment_index: usize, + slot: StatePartIndex, + }, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +enum AssignmentsEdge { + IO(AssignmentIO), + AssignmentImmediatePredecessor { + predecessor_assignment_index: usize, + assignment_index: usize, + }, +} + +#[derive(Debug)] +enum Assignments { + Accumulating { + assignments: Vec, + }, + Finalized { + assignments: Box<[Assignment]>, + slots_layout: TypeLayout, + slot_readers: SlotToAssignmentIndexFullMap, + slot_writers: SlotToAssignmentIndexFullMap, + assignment_immediate_predecessors: Box<[Box<[usize]>]>, + assignment_immediate_successors: Box<[Box<[usize]>]>, + }, +} + +impl Default for Assignments { + fn default() -> Self { + Self::Accumulating { + assignments: Vec::new(), + } + } +} + +impl Assignments { + fn finalize(&mut self, slots_layout: TypeLayout) { + let Self::Accumulating { assignments } = self else { + unreachable!("already finalized"); + }; + let assignments = mem::take(assignments).into_boxed_slice(); + let mut slot_readers = SlotToAssignmentIndexFullMap::new(slots_layout.len()); + let mut slot_writers = SlotToAssignmentIndexFullMap::new(slots_layout.len()); + let mut assignment_immediate_predecessors = vec![BTreeSet::new(); assignments.len()]; + let mut assignment_immediate_successors = vec![BTreeSet::new(); assignments.len()]; + for (assignment_index, assignment) in assignments.iter().enumerate() { + slot_readers + .keys_for_assignment(assignment_index) + .extend([&assignment.inputs]); + slot_readers + .keys_for_assignment(assignment_index) + .extend(&assignment.conditions); + let SlotSet(TypeParts { + small_slots, + big_slots, + }) = &assignment.outputs; + for &slot in small_slots { + if let Some(&pred) = slot_writers[slot].last() { + assignment_immediate_predecessors[assignment_index].insert(pred); + assignment_immediate_successors[pred].insert(assignment_index); + } + slot_writers[slot].push(assignment_index); + } + for &slot in big_slots { + if let Some(&pred) = slot_writers[slot].last() { + assignment_immediate_predecessors[assignment_index].insert(pred); + assignment_immediate_successors[pred].insert(assignment_index); + } + slot_writers[slot].push(assignment_index); + } + } + *self = Self::Finalized { + assignments, + slots_layout, + slot_readers, + slot_writers, + assignment_immediate_predecessors: assignment_immediate_predecessors + .into_iter() + .map(Box::from_iter) + .collect(), + assignment_immediate_successors: assignment_immediate_successors + .into_iter() + .map(Box::from_iter) + .collect(), + }; + } + fn push(&mut self, v: Assignment) { + let Self::Accumulating { assignments } = self else { + unreachable!("already finalized"); + }; + assignments.push(v); + } + fn assignments(&self) -> &[Assignment] { + let Self::Finalized { assignments, .. } = self else { + unreachable!("Assignments::finalize should have been called"); + }; + assignments + } + fn slots_layout(&self) -> TypeLayout { + let Self::Finalized { slots_layout, .. } = self else { + unreachable!("Assignments::finalize should have been called"); + }; + *slots_layout + } + fn slot_readers(&self) -> &SlotToAssignmentIndexFullMap { + let Self::Finalized { slot_readers, .. } = self else { + unreachable!("Assignments::finalize should have been called"); + }; + slot_readers + } + fn slot_writers(&self) -> &SlotToAssignmentIndexFullMap { + let Self::Finalized { slot_writers, .. } = self else { + unreachable!("Assignments::finalize should have been called"); + }; + slot_writers + } + fn assignment_immediate_predecessors(&self) -> &[Box<[usize]>] { + let Self::Finalized { + assignment_immediate_predecessors, + .. + } = self + else { + unreachable!("Assignments::finalize should have been called"); + }; + assignment_immediate_predecessors + } + fn assignment_immediate_successors(&self) -> &[Box<[usize]>] { + let Self::Finalized { + assignment_immediate_successors, + .. + } = self + else { + unreachable!("Assignments::finalize should have been called"); + }; + assignment_immediate_successors + } + fn elements(&self) -> AssignmentsElements<'_> { + let SlotToAssignmentIndexFullMap(TypeParts { + small_slots, + big_slots, + }) = self.slot_readers(); + AssignmentsElements { + node_indexes: HashMap::with_capacity( + self.assignments().len() + small_slots.len() + big_slots.len(), + ), + nodes: self.node_references(), + edges: self.edge_references(), + } + } +} + +impl GraphBase for Assignments { + type EdgeId = AssignmentsEdge; + type NodeId = AssignmentOrSlotIndex; +} + +#[derive(Debug, Clone, Copy)] +enum AssignmentsNodeRef<'a> { + Assignment { + index: usize, + assignment: &'a Assignment, + }, + SmallSlot(StatePartIndex, SlotDebugData), + BigSlot(StatePartIndex, SlotDebugData), +} + +impl<'a> NodeRef for AssignmentsNodeRef<'a> { + type NodeId = AssignmentOrSlotIndex; + type Weight = AssignmentsNodeRef<'a>; + + fn id(&self) -> Self::NodeId { + match *self { + AssignmentsNodeRef::Assignment { + index, + assignment: _, + } => AssignmentOrSlotIndex::AssignmentIndex(index), + AssignmentsNodeRef::SmallSlot(slot, _) => AssignmentOrSlotIndex::SmallSlot(slot), + AssignmentsNodeRef::BigSlot(slot, _) => AssignmentOrSlotIndex::BigSlot(slot), + } + } + + fn weight(&self) -> &Self::Weight { + self + } +} + +impl<'a> petgraph::visit::Data for &'a Assignments { + type NodeWeight = AssignmentsNodeRef<'a>; + type EdgeWeight = AssignmentsEdge; +} + +struct AssignmentsElements<'a> { + node_indexes: HashMap, + nodes: AssignmentsNodes<'a>, + edges: AssignmentsEdges<'a>, +} + +impl<'a> Iterator for AssignmentsElements<'a> { + type Item = petgraph::data::Element< + <&'a Assignments as petgraph::visit::Data>::NodeWeight, + <&'a Assignments as petgraph::visit::Data>::EdgeWeight, + >; + + fn next(&mut self) -> Option { + let Self { + node_indexes, + nodes, + edges, + } = self; + if let Some(node) = nodes.next() { + node_indexes.insert(node.id(), node_indexes.len()); + return Some(petgraph::data::Element::Node { weight: node }); + } + let edge = edges.next()?; + Some(petgraph::data::Element::Edge { + source: node_indexes[&edge.source()], + target: node_indexes[&edge.target()], + weight: *edge.weight(), + }) + } +} + +#[derive(Clone)] +struct AssignmentsNodeIdentifiers { + assignment_indexes: std::ops::Range, + small_slots: std::ops::Range, + big_slots: std::ops::Range, +} + +impl AssignmentsNodeIdentifiers { + fn internal_iter<'a>(&'a mut self) -> impl Iterator + 'a { + let Self { + assignment_indexes, + small_slots, + big_slots, + } = self; + assignment_indexes + .map(AssignmentOrSlotIndex::AssignmentIndex) + .chain(small_slots.map(|value| { + AssignmentOrSlotIndex::SmallSlot(StatePartIndex { + value, + _phantom: PhantomData, + }) + })) + .chain(big_slots.map(|value| { + AssignmentOrSlotIndex::BigSlot(StatePartIndex { + value, + _phantom: PhantomData, + }) + })) + } +} + +impl Iterator for AssignmentsNodeIdentifiers { + type Item = AssignmentOrSlotIndex; + fn next(&mut self) -> Option { + self.internal_iter().next() + } + + fn nth(&mut self, n: usize) -> Option { + self.internal_iter().nth(n) + } +} + +impl<'a> IntoNodeIdentifiers for &'a Assignments { + type NodeIdentifiers = AssignmentsNodeIdentifiers; + + fn node_identifiers(self) -> Self::NodeIdentifiers { + let TypeLen { + small_slots, + big_slots, + } = self.slot_readers().len(); + AssignmentsNodeIdentifiers { + assignment_indexes: 0..self.assignments().len(), + small_slots: 0..small_slots.value, + big_slots: 0..big_slots.value, + } + } +} + +struct AssignmentsNodes<'a> { + assignments: &'a Assignments, + nodes: AssignmentsNodeIdentifiers, +} + +impl<'a> Iterator for AssignmentsNodes<'a> { + type Item = AssignmentsNodeRef<'a>; + + fn next(&mut self) -> Option { + self.nodes.next().map(|node| match node { + AssignmentOrSlotIndex::AssignmentIndex(index) => AssignmentsNodeRef::Assignment { + index, + assignment: &self.assignments.assignments()[index], + }, + AssignmentOrSlotIndex::SmallSlot(slot) => AssignmentsNodeRef::SmallSlot( + slot, + *self.assignments.slots_layout().small_slots.debug_data(slot), + ), + AssignmentOrSlotIndex::BigSlot(slot) => AssignmentsNodeRef::BigSlot( + slot, + *self.assignments.slots_layout().big_slots.debug_data(slot), + ), + }) + } +} + +impl<'a> IntoNodeReferences for &'a Assignments { + type NodeRef = AssignmentsNodeRef<'a>; + type NodeReferences = AssignmentsNodes<'a>; + + fn node_references(self) -> Self::NodeReferences { + AssignmentsNodes { + assignments: self, + nodes: self.node_identifiers(), + } + } +} + +struct AssignmentsNeighborsDirected<'a> { + assignment_indexes: std::slice::Iter<'a, usize>, + small_slots: std::collections::btree_set::Iter<'a, StatePartIndex>, + big_slots: std::collections::btree_set::Iter<'a, StatePartIndex>, +} + +impl Iterator for AssignmentsNeighborsDirected<'_> { + type Item = AssignmentOrSlotIndex; + fn next(&mut self) -> Option { + let Self { + assignment_indexes, + small_slots, + big_slots, + } = self; + if let retval @ Some(_) = assignment_indexes + .next() + .copied() + .map(AssignmentOrSlotIndex::AssignmentIndex) + { + retval + } else if let retval @ Some(_) = small_slots + .next() + .copied() + .map(AssignmentOrSlotIndex::SmallSlot) + { + retval + } else if let retval @ Some(_) = big_slots + .next() + .copied() + .map(AssignmentOrSlotIndex::BigSlot) + { + retval + } else { + None + } + } +} + +impl<'a> IntoNeighbors for &'a Assignments { + type Neighbors = AssignmentsNeighborsDirected<'a>; + + fn neighbors(self, n: Self::NodeId) -> Self::Neighbors { + self.neighbors_directed(n, petgraph::Direction::Outgoing) + } +} + +impl<'a> IntoNeighborsDirected for &'a Assignments { + type NeighborsDirected = AssignmentsNeighborsDirected<'a>; + + fn neighbors_directed( + self, + n: Self::NodeId, + d: petgraph::Direction, + ) -> Self::NeighborsDirected { + use petgraph::Direction::*; + let slot_map = match d { + Outgoing => self.slot_readers(), + Incoming => self.slot_writers(), + }; + match n { + AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { + let assignment = &self.assignments()[assignment_index]; + let ( + assignment_indexes, + SlotSet(TypeParts { + small_slots, + big_slots, + }), + ) = match d { + Outgoing => ( + &self.assignment_immediate_successors()[assignment_index], + &assignment.outputs, + ), + Incoming => ( + &self.assignment_immediate_predecessors()[assignment_index], + &assignment.inputs, + ), + }; + AssignmentsNeighborsDirected { + assignment_indexes: assignment_indexes.iter(), + small_slots: small_slots.iter(), + big_slots: big_slots.iter(), + } + } + AssignmentOrSlotIndex::SmallSlot(slot) => AssignmentsNeighborsDirected { + assignment_indexes: slot_map[slot].iter(), + small_slots: Default::default(), + big_slots: Default::default(), + }, + AssignmentOrSlotIndex::BigSlot(slot) => AssignmentsNeighborsDirected { + assignment_indexes: slot_map[slot].iter(), + small_slots: Default::default(), + big_slots: Default::default(), + }, + } + } +} + +impl EdgeRef for AssignmentsEdge { + type NodeId = AssignmentOrSlotIndex; + type EdgeId = AssignmentsEdge; + type Weight = AssignmentsEdge; + + fn source(&self) -> Self::NodeId { + match *self { + AssignmentsEdge::IO(AssignmentIO::BigInput { + assignment_index: _, + slot, + }) => AssignmentOrSlotIndex::BigSlot(slot), + AssignmentsEdge::IO(AssignmentIO::SmallInput { + assignment_index: _, + slot, + }) => AssignmentOrSlotIndex::SmallSlot(slot), + AssignmentsEdge::IO(AssignmentIO::BigOutput { + assignment_index, + slot: _, + }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + AssignmentsEdge::IO(AssignmentIO::SmallOutput { + assignment_index, + slot: _, + }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + AssignmentsEdge::AssignmentImmediatePredecessor { + predecessor_assignment_index, + assignment_index: _, + } => AssignmentOrSlotIndex::AssignmentIndex(predecessor_assignment_index), + } + } + + fn target(&self) -> Self::NodeId { + match *self { + AssignmentsEdge::IO(AssignmentIO::BigInput { + assignment_index, + slot: _, + }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + AssignmentsEdge::IO(AssignmentIO::SmallInput { + assignment_index, + slot: _, + }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + AssignmentsEdge::IO(AssignmentIO::BigOutput { + assignment_index: _, + slot, + }) => AssignmentOrSlotIndex::BigSlot(slot), + AssignmentsEdge::IO(AssignmentIO::SmallOutput { + assignment_index: _, + slot, + }) => AssignmentOrSlotIndex::SmallSlot(slot), + AssignmentsEdge::AssignmentImmediatePredecessor { + predecessor_assignment_index: _, + assignment_index, + } => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + } + } + + fn weight(&self) -> &Self::Weight { + self + } + + fn id(&self) -> Self::EdgeId { + *self + } +} + +struct AssignmentsEdges<'a> { + assignments: &'a Assignments, + nodes: AssignmentsNodeIdentifiers, + outgoing_neighbors: Option<(AssignmentOrSlotIndex, AssignmentsNeighborsDirected<'a>)>, +} + +impl Iterator for AssignmentsEdges<'_> { + type Item = AssignmentsEdge; + + fn next(&mut self) -> Option { + loop { + if let Some((node, outgoing_neighbors)) = &mut self.outgoing_neighbors { + if let Some(outgoing_neighbor) = outgoing_neighbors.next() { + return Some(match (*node, outgoing_neighbor) { + ( + AssignmentOrSlotIndex::SmallSlot(_) | AssignmentOrSlotIndex::BigSlot(_), + AssignmentOrSlotIndex::SmallSlot(_) | AssignmentOrSlotIndex::BigSlot(_), + ) => unreachable!(), + ( + AssignmentOrSlotIndex::AssignmentIndex(predecessor_assignment_index), + AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + ) => AssignmentsEdge::AssignmentImmediatePredecessor { + predecessor_assignment_index, + assignment_index, + }, + ( + AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + AssignmentOrSlotIndex::SmallSlot(slot), + ) => AssignmentsEdge::IO(AssignmentIO::SmallOutput { + assignment_index, + slot, + }), + ( + AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + AssignmentOrSlotIndex::BigSlot(slot), + ) => AssignmentsEdge::IO(AssignmentIO::BigOutput { + assignment_index, + slot, + }), + ( + AssignmentOrSlotIndex::SmallSlot(slot), + AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + ) => AssignmentsEdge::IO(AssignmentIO::SmallInput { + assignment_index, + slot, + }), + ( + AssignmentOrSlotIndex::BigSlot(slot), + AssignmentOrSlotIndex::AssignmentIndex(assignment_index), + ) => AssignmentsEdge::IO(AssignmentIO::BigInput { + assignment_index, + slot, + }), + }); + } + } + let node = self.nodes.next()?; + self.outgoing_neighbors = Some(( + node, + self.assignments + .neighbors_directed(node, petgraph::Direction::Outgoing), + )); + } + } +} + +impl<'a> IntoEdgeReferences for &'a Assignments { + type EdgeRef = AssignmentsEdge; + type EdgeReferences = AssignmentsEdges<'a>; + + fn edge_references(self) -> Self::EdgeReferences { + AssignmentsEdges { + assignments: self, + nodes: self.node_identifiers(), + outgoing_neighbors: None, + } + } +} + +struct AssignmentsVisitMap { + assignments: Vec, + slots: DenseSlotSet, +} + +impl VisitMap for AssignmentsVisitMap { + fn visit(&mut self, n: AssignmentOrSlotIndex) -> bool { + match n { + AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { + !mem::replace(&mut self.assignments[assignment_index], true) + } + AssignmentOrSlotIndex::SmallSlot(slot) => self.slots.insert(slot), + AssignmentOrSlotIndex::BigSlot(slot) => self.slots.insert(slot), + } + } + + fn is_visited(&self, n: &AssignmentOrSlotIndex) -> bool { + match *n { + AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { + self.assignments[assignment_index] + } + AssignmentOrSlotIndex::SmallSlot(slot) => self.slots.contains(slot), + AssignmentOrSlotIndex::BigSlot(slot) => self.slots.contains(slot), + } + } +} + +impl Visitable for Assignments { + type Map = AssignmentsVisitMap; + + fn visit_map(self: &Self) -> Self::Map { + AssignmentsVisitMap { + assignments: vec![false; self.assignments().len()], + slots: DenseSlotSet::new(self.slot_readers().len()), + } + } + + fn reset_map(self: &Self, map: &mut Self::Map) { + let AssignmentsVisitMap { assignments, slots } = map; + assignments.clear(); + assignments.resize(self.assignments().len(), false); + if slots.len() != self.slot_readers().len() { + *slots = DenseSlotSet::new(self.slot_readers().len()); + } else { + slots.clear(); + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +struct DenseSlotSet(TypeParts); + +impl DenseSlotSet { + fn new(len: TypeLen) -> Self { + let TypeLen { + small_slots, + big_slots, + } = len; + Self(TypeParts { + small_slots: vec![false; small_slots.value.try_into().expect("length too big")] + .into_boxed_slice(), + big_slots: vec![false; big_slots.value.try_into().expect("length too big")] + .into_boxed_slice(), + }) + } + fn len(&self) -> TypeLen { + TypeLen { + small_slots: StatePartLen { + value: self.0.small_slots.len() as _, + _phantom: PhantomData, + }, + big_slots: StatePartLen { + value: self.0.big_slots.len() as _, + _phantom: PhantomData, + }, + } + } + fn clear(&mut self) { + let Self(TypeParts { + small_slots, + big_slots, + }) = self; + small_slots.fill(false); + big_slots.fill(false); + } +} + +impl StatePartsValue for DenseSlotSet { + type Value = Box<[bool]>; +} + +trait DenseSlotSetMethods: Extend> { + fn contains(&self, k: StatePartIndex) -> bool; + fn remove(&mut self, k: StatePartIndex) -> bool { + self.take(k).is_some() + } + fn take(&mut self, k: StatePartIndex) -> Option>; + fn replace(&mut self, k: StatePartIndex) -> Option>; + fn insert(&mut self, k: StatePartIndex) -> bool { + self.replace(k).is_none() + } +} + +impl Extend> for DenseSlotSet +where + Self: DenseSlotSetMethods, +{ + fn extend>>(&mut self, iter: T) { + iter.into_iter().for_each(|v| { + self.insert(v); + }); + } +} + +impl DenseSlotSetMethods for DenseSlotSet { + fn contains(&self, k: StatePartIndex) -> bool { + self.0.small_slots[k.as_usize()] + } + + fn take( + &mut self, + k: StatePartIndex, + ) -> Option> { + mem::replace(self.0.small_slots.get_mut(k.as_usize())?, false).then_some(k) + } + + fn replace( + &mut self, + k: StatePartIndex, + ) -> Option> { + mem::replace(&mut self.0.small_slots[k.as_usize()], true).then_some(k) + } +} + +impl DenseSlotSetMethods for DenseSlotSet { + fn contains(&self, k: StatePartIndex) -> bool { + self.0.big_slots[k.as_usize()] + } + + fn take( + &mut self, + k: StatePartIndex, + ) -> Option> { + mem::replace(self.0.big_slots.get_mut(k.as_usize())?, false).then_some(k) + } + + fn replace( + &mut self, + k: StatePartIndex, + ) -> Option> { + mem::replace(&mut self.0.big_slots[k.as_usize()], true).then_some(k) + } +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +struct SlotVec(TypeParts); + +impl SlotVec { + fn is_empty(&self) -> bool { + let Self(TypeParts { + small_slots, + big_slots, + }) = self; + small_slots.is_empty() && big_slots.is_empty() + } +} + +impl StatePartsValue for SlotVec { + type Value = Vec>; +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +struct SlotSet(TypeParts); + +impl SlotSet { + fn is_empty(&self) -> bool { + let Self(TypeParts { + small_slots, + big_slots, + }) = self; + small_slots.is_empty() && big_slots.is_empty() + } + fn for_each( + &self, + small_slots_fn: impl FnMut(StatePartIndex), + big_slots_fn: impl FnMut(StatePartIndex), + ) { + let Self(TypeParts { + small_slots, + big_slots, + }) = self; + small_slots.iter().copied().for_each(small_slots_fn); + big_slots.iter().copied().for_each(big_slots_fn); + } + fn all( + &self, + small_slots_fn: impl FnMut(StatePartIndex) -> bool, + big_slots_fn: impl FnMut(StatePartIndex) -> bool, + ) -> bool { + let Self(TypeParts { + small_slots, + big_slots, + }) = self; + small_slots.iter().copied().all(small_slots_fn) + && big_slots.iter().copied().all(big_slots_fn) + } +} + +impl StatePartsValue for SlotSet { + type Value = BTreeSet>; +} + +impl Extend> for SlotSet { + fn extend>>(&mut self, iter: T) { + self.0.small_slots.extend(iter); + } +} + +impl Extend> for SlotSet { + fn extend>>(&mut self, iter: T) { + self.0.big_slots.extend(iter); + } +} + +impl Extend> for SlotSet +where + Self: Extend>, +{ + fn extend>>(&mut self, iter: T) { + self.extend(iter.into_iter().flat_map(|v| v.iter())); + } +} + +impl Extend for SlotSet { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each( + |TypeIndexRange { + small_slots, + big_slots, + }| { + self.extend(small_slots.iter()); + self.extend(big_slots.iter()); + }, + ) + } +} + +impl Extend for SlotSet { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each( + |TypeArrayIndex { + small_slots, + big_slots, + }| { + self.extend([small_slots]); + self.extend([big_slots]); + }, + ) + } +} + +impl Extend> for SlotSet { + fn extend>>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|v| v.index)); + } +} + +impl Extend for SlotSet { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|cond_body| match cond_body { + CondBody::IfTrue { cond } | CondBody::IfFalse { cond } => { + self.extend([cond.range]); + } + CondBody::MatchArm { + discriminant, + variant_index: _, + } => self.extend([discriminant]), + }) + } +} + +impl Extend for SlotSet { + fn extend>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|v| v.body)) + } +} + +#[derive(Debug)] +struct Assignment { + inputs: SlotSet, + outputs: SlotSet, + conditions: Interned<[Cond]>, + insns: Vec, + source_location: SourceLocation, +} + +#[derive(Debug)] +struct SlotToAssignmentIndexFullMap(TypeParts); + +impl StatePartsValue for SlotToAssignmentIndexFullMap { + type Value = Box<[Vec]>; +} + +impl SlotToAssignmentIndexFullMap { + fn new(len: TypeLen) -> Self { + let TypeLen { + small_slots, + big_slots, + } = len; + Self(TypeParts { + small_slots: vec![Vec::new(); small_slots.value.try_into().expect("length too big")] + .into_boxed_slice(), + big_slots: vec![Vec::new(); big_slots.value.try_into().expect("length too big")] + .into_boxed_slice(), + }) + } + fn len(&self) -> TypeLen { + TypeLen { + small_slots: StatePartLen { + value: self.0.small_slots.len() as _, + _phantom: PhantomData, + }, + big_slots: StatePartLen { + value: self.0.big_slots.len() as _, + _phantom: PhantomData, + }, + } + } + fn keys_for_assignment( + &mut self, + assignment_index: usize, + ) -> SlotToAssignmentIndexFullMapKeysForAssignment<'_> { + SlotToAssignmentIndexFullMapKeysForAssignment { + map: self, + assignment_index, + } + } + fn for_each( + &self, + mut small_slots_fn: impl FnMut(StatePartIndex, &[usize]), + mut big_slots_fn: impl FnMut(StatePartIndex, &[usize]), + ) { + let Self(TypeParts { + small_slots, + big_slots, + }) = self; + small_slots.iter().enumerate().for_each(|(k, v)| { + small_slots_fn( + StatePartIndex { + value: k as _, + _phantom: PhantomData, + }, + v, + ) + }); + big_slots.iter().enumerate().for_each(|(k, v)| { + big_slots_fn( + StatePartIndex { + value: k as _, + _phantom: PhantomData, + }, + v, + ) + }); + } +} + +impl std::ops::Index> for SlotToAssignmentIndexFullMap { + type Output = Vec; + + fn index(&self, index: StatePartIndex) -> &Self::Output { + &self.0.small_slots[index.as_usize()] + } +} + +impl std::ops::IndexMut> for SlotToAssignmentIndexFullMap { + fn index_mut(&mut self, index: StatePartIndex) -> &mut Self::Output { + &mut self.0.small_slots[index.as_usize()] + } +} + +impl std::ops::Index> for SlotToAssignmentIndexFullMap { + type Output = Vec; + + fn index(&self, index: StatePartIndex) -> &Self::Output { + &self.0.big_slots[index.as_usize()] + } +} + +impl std::ops::IndexMut> for SlotToAssignmentIndexFullMap { + fn index_mut(&mut self, index: StatePartIndex) -> &mut Self::Output { + &mut self.0.big_slots[index.as_usize()] + } +} + +struct SlotToAssignmentIndexFullMapKeysForAssignment<'a> { + map: &'a mut SlotToAssignmentIndexFullMap, + assignment_index: usize, +} + +impl<'a, K: StatePartKind> Extend<&'a StatePartIndex> + for SlotToAssignmentIndexFullMapKeysForAssignment<'_> +where + Self: Extend>, +{ + fn extend>>(&mut self, iter: T) { + self.extend(iter.into_iter().copied()); + } +} + +impl Extend> + for SlotToAssignmentIndexFullMapKeysForAssignment<'_> +where + SlotToAssignmentIndexFullMap: IndexMut, Output = Vec>, +{ + fn extend>>(&mut self, iter: T) { + iter.into_iter() + .for_each(|slot| self.map[slot].push(self.assignment_index)); + } +} + +impl<'a> Extend<&'a SlotSet> for SlotToAssignmentIndexFullMapKeysForAssignment<'_> { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each( + |SlotSet(TypeParts { + small_slots, + big_slots, + })| { + self.extend(small_slots); + self.extend(big_slots); + }, + ); + } +} + +impl<'a> Extend<&'a Cond> for SlotToAssignmentIndexFullMapKeysForAssignment<'_> { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|cond| match cond.body { + CondBody::IfTrue { cond } | CondBody::IfFalse { cond } => { + let CompiledValue { + range: + TypeIndexRange { + small_slots, + big_slots, + }, + layout: _, + write: _, + } = cond; + self.extend(small_slots.iter()); + self.extend(big_slots.iter()); + } + CondBody::MatchArm { + discriminant, + variant_index: _, + } => self.extend([discriminant]), + }); + } +} + +impl Assignment { + fn new( + conditions: Interned<[Cond]>, + insns: Vec, + source_location: SourceLocation, + ) -> Self { + let mut inputs = SlotSet::default(); + let mut outputs = SlotSet::default(); + for insn in &insns { + let insn = match insn { + InsnOrLabel::Insn(insn) => insn, + InsnOrLabel::Label(_) => continue, + }; + for InsnField { ty, kind } in insn.fields() { + match (kind, ty) { + (InsnFieldKind::Input, InsnFieldType::SmallSlot(&slot)) => { + inputs.extend([slot]); + } + (InsnFieldKind::Input, InsnFieldType::BigSlot(&slot)) => { + inputs.extend([slot]); + } + ( + InsnFieldKind::Input, + InsnFieldType::SmallSlotArrayIndexed(&array_indexed), + ) => { + array_indexed.for_each_target(|slot| inputs.extend([slot])); + inputs.extend(array_indexed.indexes); + } + (InsnFieldKind::Input, InsnFieldType::BigSlotArrayIndexed(&array_indexed)) => { + array_indexed.for_each_target(|slot| inputs.extend([slot])); + inputs.extend(array_indexed.indexes); + } + (InsnFieldKind::Output, InsnFieldType::SmallSlot(&slot)) => { + outputs.extend([slot]); + } + (InsnFieldKind::Output, InsnFieldType::BigSlot(&slot)) => { + outputs.extend([slot]); + } + ( + InsnFieldKind::Output, + InsnFieldType::SmallSlotArrayIndexed(&array_indexed), + ) => { + array_indexed.for_each_target(|slot| { + outputs.extend([slot]); + }); + inputs.extend(array_indexed.indexes); + } + (InsnFieldKind::Output, InsnFieldType::BigSlotArrayIndexed(&array_indexed)) => { + array_indexed.for_each_target(|slot| { + outputs.extend([slot]); + }); + inputs.extend(array_indexed.indexes); + } + ( + _, + InsnFieldType::Memory(_) + | InsnFieldType::SmallUInt(_) + | InsnFieldType::SmallSInt(_) + | InsnFieldType::InternedBigInt(_) + | InsnFieldType::U8(_) + | InsnFieldType::USize(_) + | InsnFieldType::Empty(_), + ) + | ( + InsnFieldKind::Immediate + | InsnFieldKind::Memory + | InsnFieldKind::BranchTarget, + _, + ) => {} + } + } + } + Self { + inputs, + outputs, + conditions, + insns, + source_location, + } + } +} + +#[derive(Debug)] +struct RegisterReset { + is_async: bool, + init: CompiledValue, + rst: StatePartIndex, +} + +#[derive(Debug, Clone, Copy)] +struct ClockTrigger { + last_clk_was_low: StatePartIndex, + clk: StatePartIndex, + clk_triggered: StatePartIndex, + source_location: SourceLocation, +} + +#[derive(Debug)] +struct Register { + value: CompiledValue, + clk_triggered: StatePartIndex, + reset: Option, + source_location: SourceLocation, +} + +#[derive(Debug)] + +struct MemoryPort { + clk_triggered: StatePartIndex, + addr_delayed: Vec>, + en_delayed: Vec>, + data_layout: CompiledTypeLayout, + read_data_delayed: Vec, + write_data_delayed: Vec, + write_mask_delayed: Vec, + write_mode_delayed: Vec>, + write_insns: Vec, +} + +struct MemoryPortReadInsns<'a> { + addr: StatePartIndex, + en: StatePartIndex, + write_mode: Option>, + data: TypeIndexRange, + insns: &'a mut Vec, +} + +struct MemoryPortWriteInsns<'a> { + addr: StatePartIndex, + en: StatePartIndex, + write_mode: Option>, + data: TypeIndexRange, + mask: TypeIndexRange, + insns: &'a mut Vec, +} + +#[derive(Debug)] +struct Memory { + mem: Mem, + memory: StatePartIndex, + trace: TraceMem, + ports: Vec, +} + +#[derive(Copy, Clone)] +enum MakeTraceDeclTarget { + Expr(Expr), + Memory { + id: TraceMemoryId, + depth: usize, + stride: usize, + start: usize, + ty: CanonicalType, + }, +} + +impl MakeTraceDeclTarget { + fn flow(self) -> Flow { + match self { + MakeTraceDeclTarget::Expr(expr) => Expr::flow(expr), + MakeTraceDeclTarget::Memory { .. } => Flow::Duplex, + } + } + fn ty(self) -> CanonicalType { + match self { + MakeTraceDeclTarget::Expr(expr) => Expr::ty(expr), + MakeTraceDeclTarget::Memory { ty, .. } => ty, + } + } +} + +struct DebugOpaque(T); + +impl fmt::Debug for DebugOpaque { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("<...>") + } +} + +#[derive(Debug)] +pub struct Compiler { + insns: Insns, + original_base_module: Interned>, + base_module: Interned>, + modules: HashMap, + compiled_values: HashMap>, + compiled_exprs: HashMap, CompiledExpr>, + compiled_exprs_to_values: HashMap, CompiledValue>, + decl_conditions: HashMap>, + compiled_values_to_dyn_array_indexes: + HashMap, StatePartIndex>, + compiled_value_bool_dest_is_small_map: + HashMap, StatePartIndex>, + assignments: Assignments, + clock_triggers: Vec, + compiled_value_to_clock_trigger_map: HashMap, ClockTrigger>, + enum_discriminants: HashMap, StatePartIndex>, + registers: Vec, + traces: SimTraces>>, + memories: Vec, + dump_assignments_dot: Option>>, +} + +impl Compiler { + pub fn new(base_module: Interned>) -> Self { + let original_base_module = base_module; + let base_module = deduce_resets(base_module, true) + .unwrap_or_else(|e| panic!("failed to deduce reset types: {e}")); + Self { + insns: Insns::new(), + original_base_module, + base_module, + modules: HashMap::new(), + compiled_values: HashMap::new(), + compiled_exprs: HashMap::new(), + compiled_exprs_to_values: HashMap::new(), + decl_conditions: HashMap::new(), + compiled_values_to_dyn_array_indexes: HashMap::new(), + compiled_value_bool_dest_is_small_map: HashMap::new(), + assignments: Assignments::default(), + clock_triggers: Vec::new(), + compiled_value_to_clock_trigger_map: HashMap::new(), + enum_discriminants: HashMap::new(), + registers: Vec::new(), + traces: SimTraces(Vec::new()), + memories: Vec::new(), + dump_assignments_dot: None, + } + } + #[doc(hidden)] + /// This is explicitly unstable and may be changed/removed at any time + pub fn dump_assignments_dot(&mut self, callback: Box) { + self.dump_assignments_dot = Some(DebugOpaque(callback)); + } + fn new_sim_trace(&mut self, kind: SimTraceKind) -> TraceScalarId { + let id = TraceScalarId(self.traces.0.len()); + self.traces.0.push(SimTrace { + kind, + state: (), + last_state: (), + }); + id + } + fn make_trace_scalar_helper( + &mut self, + instantiated_module: InstantiatedModule, + target: MakeTraceDeclTarget, + source_location: SourceLocation, + small_kind: impl FnOnce(StatePartIndex) -> SimTraceKind, + big_kind: impl FnOnce(StatePartIndex) -> SimTraceKind, + ) -> TraceLocation { + match target { + MakeTraceDeclTarget::Expr(target) => { + let compiled_value = self.compile_expr(instantiated_module, target); + let compiled_value = self.compiled_expr_to_value(compiled_value, source_location); + TraceLocation::Scalar(self.new_sim_trace(match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => small_kind(compiled_value.range.small_slots.start), + TypeLen::A_BIG_SLOT => big_kind(compiled_value.range.big_slots.start), + _ => unreachable!(), + })) + } + MakeTraceDeclTarget::Memory { + id, + depth, + stride, + start, + ty, + } => TraceLocation::Memory(TraceMemoryLocation { + id, + depth, + stride, + start, + len: ty.bit_width(), + }), + } + } + fn make_trace_scalar( + &mut self, + instantiated_module: InstantiatedModule, + target: MakeTraceDeclTarget, + name: Interned, + source_location: SourceLocation, + ) -> TraceDecl { + let flow = target.flow(); + match target.ty() { + CanonicalType::UInt(ty) => TraceUInt { + location: self.make_trace_scalar_helper( + instantiated_module, + target, + source_location, + |index| SimTraceKind::SmallUInt { index, ty }, + |index| SimTraceKind::BigUInt { index, ty }, + ), + name, + ty, + flow, + } + .into(), + CanonicalType::SInt(ty) => TraceSInt { + location: self.make_trace_scalar_helper( + instantiated_module, + target, + source_location, + |index| SimTraceKind::SmallSInt { index, ty }, + |index| SimTraceKind::BigSInt { index, ty }, + ), + name, + ty, + flow, + } + .into(), + CanonicalType::Bool(_) => TraceBool { + location: self.make_trace_scalar_helper( + instantiated_module, + target, + source_location, + |index| SimTraceKind::SmallBool { index }, + |index| SimTraceKind::BigBool { index }, + ), + name, + flow, + } + .into(), + CanonicalType::Array(_) => unreachable!(), + CanonicalType::Enum(ty) => { + assert_eq!(ty.discriminant_bit_width(), ty.type_properties().bit_width); + let location = match target { + MakeTraceDeclTarget::Expr(target) => { + let compiled_value = self.compile_expr(instantiated_module, target); + let compiled_value = + self.compiled_expr_to_value(compiled_value, source_location); + let discriminant = self.compile_enum_discriminant( + compiled_value.map_ty(Enum::from_canonical), + source_location, + ); + TraceLocation::Scalar(self.new_sim_trace(SimTraceKind::EnumDiscriminant { + index: discriminant, + ty, + })) + } + MakeTraceDeclTarget::Memory { + id, + depth, + stride, + start, + ty: _, + } => TraceLocation::Memory(TraceMemoryLocation { + id, + depth, + stride, + start, + len: ty.type_properties().bit_width, + }), + }; + TraceFieldlessEnum { + location, + name, + ty, + flow, + } + .into() + } + CanonicalType::Bundle(_) => unreachable!(), + CanonicalType::AsyncReset(_) => TraceAsyncReset { + location: self.make_trace_scalar_helper( + instantiated_module, + target, + source_location, + |index| SimTraceKind::SmallAsyncReset { index }, + |index| SimTraceKind::BigAsyncReset { index }, + ), + name, + flow, + } + .into(), + CanonicalType::SyncReset(_) => TraceSyncReset { + location: self.make_trace_scalar_helper( + instantiated_module, + target, + source_location, + |index| SimTraceKind::SmallSyncReset { index }, + |index| SimTraceKind::BigSyncReset { index }, + ), + name, + flow, + } + .into(), + CanonicalType::Reset(_) => unreachable!(), + CanonicalType::Clock(_) => TraceClock { + location: self.make_trace_scalar_helper( + instantiated_module, + target, + source_location, + |index| SimTraceKind::SmallClock { index }, + |index| SimTraceKind::BigClock { index }, + ), + name, + flow, + } + .into(), + } + } + fn make_trace_decl_child( + &mut self, + instantiated_module: InstantiatedModule, + target: MakeTraceDeclTarget, + name: Interned, + source_location: SourceLocation, + ) -> TraceDecl { + match target.ty() { + CanonicalType::Array(ty) => { + let elements = Interned::from_iter((0..ty.len()).map(|index| { + self.make_trace_decl_child( + instantiated_module, + match target { + MakeTraceDeclTarget::Expr(target) => MakeTraceDeclTarget::Expr( + Expr::::from_canonical(target)[index], + ), + MakeTraceDeclTarget::Memory { + id, + depth, + stride, + start, + ty: _, + } => MakeTraceDeclTarget::Memory { + id, + depth, + stride, + start: start + ty.element().bit_width() * index, + ty: ty.element(), + }, + }, + Intern::intern_owned(format!("[{index}]")), + source_location, + ) + })); + TraceArray { + name, + elements, + ty, + flow: target.flow(), + } + .into() + } + CanonicalType::Enum(ty) => { + if ty.variants().iter().all(|v| v.ty.is_none()) { + self.make_trace_scalar(instantiated_module, target, name, source_location) + } else { + let flow = target.flow(); + let location = match target { + MakeTraceDeclTarget::Expr(target) => { + let compiled_value = self.compile_expr(instantiated_module, target); + let compiled_value = + self.compiled_expr_to_value(compiled_value, source_location); + let discriminant = self.compile_enum_discriminant( + compiled_value.map_ty(Enum::from_canonical), + source_location, + ); + TraceLocation::Scalar(self.new_sim_trace( + SimTraceKind::EnumDiscriminant { + index: discriminant, + ty, + }, + )) + } + MakeTraceDeclTarget::Memory { + id, + depth, + stride, + start, + ty: _, + } => TraceLocation::Memory(TraceMemoryLocation { + id, + depth, + stride, + start, + len: ty.discriminant_bit_width(), + }), + }; + let discriminant = TraceEnumDiscriminant { + location, + name: "$tag".intern(), + ty, + flow, + }; + let non_empty_fields = + Interned::from_iter(ty.variants().into_iter().enumerate().flat_map( + |(variant_index, variant)| { + variant.ty.map(|variant_ty| { + self.make_trace_decl_child( + instantiated_module, + match target { + MakeTraceDeclTarget::Expr(target) => { + MakeTraceDeclTarget::Expr( + ops::VariantAccess::new_by_index( + Expr::::from_canonical(target), + variant_index, + ) + .to_expr(), + ) + } + MakeTraceDeclTarget::Memory { + id, + depth, + stride, + start, + ty: _, + } => MakeTraceDeclTarget::Memory { + id, + depth, + stride, + start: start + ty.discriminant_bit_width(), + ty: variant_ty, + }, + }, + variant.name, + source_location, + ) + }) + }, + )); + TraceEnumWithFields { + name, + discriminant, + non_empty_fields, + ty, + flow, + } + .into() + } + } + CanonicalType::Bundle(ty) => { + let fields = Interned::from_iter(ty.fields().iter().zip(ty.field_offsets()).map( + |(field, field_offset)| { + self.make_trace_decl_child( + instantiated_module, + match target { + MakeTraceDeclTarget::Expr(target) => { + MakeTraceDeclTarget::Expr(Expr::field( + Expr::::from_canonical(target), + &field.name, + )) + } + MakeTraceDeclTarget::Memory { + id, + depth, + stride, + start, + ty: _, + } => MakeTraceDeclTarget::Memory { + id, + depth, + stride, + start: start + field_offset, + ty: field.ty, + }, + }, + field.name, + source_location, + ) + }, + )); + TraceBundle { + name, + fields, + ty, + flow: target.flow(), + } + .into() + } + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) => { + self.make_trace_scalar(instantiated_module, target, name, source_location) + } + } + } + fn make_trace_decl( + &mut self, + instantiated_module: InstantiatedModule, + target_base: TargetBase, + ) -> TraceDecl { + let target = MakeTraceDeclTarget::Expr(target_base.to_expr()); + match target_base { + TargetBase::ModuleIO(module_io) => TraceModuleIO { + name: module_io.name(), + child: self + .make_trace_decl_child( + instantiated_module, + target, + module_io.name(), + module_io.source_location(), + ) + .intern(), + ty: module_io.ty(), + flow: module_io.flow(), + } + .into(), + TargetBase::MemPort(mem_port) => { + let name = Intern::intern_owned(mem_port.port_name().to_string()); + let TraceDecl::Scope(TraceScope::Bundle(bundle)) = self.make_trace_decl_child( + instantiated_module, + target, + name, + mem_port.source_location(), + ) else { + unreachable!() + }; + TraceMemPort { + name, + bundle, + ty: mem_port.ty(), + } + .into() + } + TargetBase::Reg(reg) => TraceReg { + name: reg.name(), + child: self + .make_trace_decl_child( + instantiated_module, + target, + reg.name(), + reg.source_location(), + ) + .intern(), + ty: reg.ty(), + } + .into(), + TargetBase::RegSync(reg) => TraceReg { + name: reg.name(), + child: self + .make_trace_decl_child( + instantiated_module, + target, + reg.name(), + reg.source_location(), + ) + .intern(), + ty: reg.ty(), + } + .into(), + TargetBase::RegAsync(reg) => TraceReg { + name: reg.name(), + child: self + .make_trace_decl_child( + instantiated_module, + target, + reg.name(), + reg.source_location(), + ) + .intern(), + ty: reg.ty(), + } + .into(), + TargetBase::Wire(wire) => TraceWire { + name: wire.name(), + child: self + .make_trace_decl_child( + instantiated_module, + target, + wire.name(), + wire.source_location(), + ) + .intern(), + ty: wire.ty(), + } + .into(), + TargetBase::Instance(instance) => { + let TraceDecl::Scope(TraceScope::Bundle(instance_io)) = self.make_trace_decl_child( + instantiated_module, + target, + instance.name(), + instance.source_location(), + ) else { + unreachable!() + }; + let compiled_module = &self.modules[&InstantiatedModule::Child { + parent: instantiated_module.intern(), + instance: instance.intern(), + }]; + TraceInstance { + name: instance.name(), + instance_io, + module: compiled_module.trace_decls, + ty: instance.ty(), + } + .into() + } + } + } + fn compile_value( + &mut self, + target: TargetInInstantiatedModule, + ) -> CompiledValue { + if let Some(&retval) = self.compiled_values.get(&target) { + return retval; + } + let retval = match target.target { + Target::Base(base) => { + let unprefixed_layout = CompiledTypeLayout::get(base.canonical_ty()); + let layout = unprefixed_layout.with_prefixed_debug_names(&format!( + "{:?}.{:?}", + target.instantiated_module, + base.target_name() + )); + let range = self.insns.allocate_variable(&layout.layout); + let write = match *base { + TargetBase::ModuleIO(_) + | TargetBase::MemPort(_) + | TargetBase::Wire(_) + | TargetBase::Instance(_) => None, + TargetBase::Reg(_) | TargetBase::RegSync(_) | TargetBase::RegAsync(_) => { + let write_layout = unprefixed_layout.with_prefixed_debug_names(&format!( + "{:?}.{:?}$next", + target.instantiated_module, + base.target_name() + )); + Some(( + write_layout, + self.insns.allocate_variable(&write_layout.layout), + )) + } + }; + CompiledValue { + range, + layout, + write, + } + } + Target::Child(target_child) => { + let parent = self.compile_value(TargetInInstantiatedModule { + instantiated_module: target.instantiated_module, + target: *target_child.parent(), + }); + match *target_child.path_element() { + TargetPathElement::BundleField(TargetPathBundleField { name }) => { + parent.map_ty(Bundle::from_canonical).field_by_name(name) + } + TargetPathElement::ArrayElement(TargetPathArrayElement { index }) => { + parent.map_ty(Array::from_canonical).element(index) + } + TargetPathElement::DynArrayElement(_) => unreachable!(), + } + } + }; + self.compiled_values.insert(target, retval); + retval + } + fn compiled_expr_to_value( + &mut self, + expr: CompiledExpr, + source_location: SourceLocation, + ) -> CompiledValue { + if let Some(&retval) = self.compiled_exprs_to_values.get(&expr) { + return retval; + } + assert!( + expr.static_part.layout.ty.is_passive(), + "invalid expression passed to compiled_expr_to_value -- type must be passive", + ); + let CompiledExpr { + static_part, + indexes, + } = expr; + let retval = if indexes.as_ref().is_empty() { + CompiledValue { + layout: static_part.layout, + range: static_part.range, + write: None, + } + } else { + let layout = static_part.layout.with_anonymized_debug_info(); + let retval = CompiledValue { + layout, + range: self.insns.allocate_variable(&layout.layout), + write: None, + }; + let TypeIndexRange { + small_slots, + big_slots, + } = retval.range; + self.add_assignment( + Interned::default(), + small_slots + .iter() + .zip(static_part.range.small_slots.iter()) + .map(|(dest, base)| Insn::ReadSmallIndexed { + dest, + src: StatePartArrayIndexed { + base, + indexes: indexes.small_slots, + }, + }) + .chain( + big_slots + .iter() + .zip(static_part.range.big_slots.iter()) + .map(|(dest, base)| Insn::ReadIndexed { + dest, + src: StatePartArrayIndexed { + base, + indexes: indexes.big_slots, + }, + }), + ), + source_location, + ); + retval + }; + self.compiled_exprs_to_values.insert(expr, retval); + retval + } + fn add_assignment>( + &mut self, + conditions: Interned<[Cond]>, + insns: impl IntoIterator, + source_location: SourceLocation, + ) { + let insns = Vec::from_iter(insns.into_iter().map(Into::into)); + self.assignments + .push(Assignment::new(conditions, insns, source_location)); + } + fn simple_big_expr_input( + &mut self, + instantiated_module: InstantiatedModule, + input: Expr, + ) -> StatePartIndex { + let input = self.compile_expr(instantiated_module, input); + let input = + self.compiled_expr_to_value(input, instantiated_module.leaf_module().source_location()); + assert_eq!(input.range.len(), TypeLen::A_BIG_SLOT); + input.range.big_slots.start + } + fn compile_expr_helper( + &mut self, + instantiated_module: InstantiatedModule, + dest_ty: CanonicalType, + make_insns: impl FnOnce(&mut Self, TypeIndexRange) -> Vec, + ) -> CompiledValue { + let layout = CompiledTypeLayout::get(dest_ty); + let range = self.insns.allocate_variable(&layout.layout); + let retval = CompiledValue { + layout, + range, + write: None, + }; + let insns = make_insns(self, range); + self.add_assignment( + Interned::default(), + insns, + instantiated_module.leaf_module().source_location(), + ); + retval + } + fn simple_nary_big_expr_helper( + &mut self, + instantiated_module: InstantiatedModule, + dest_ty: CanonicalType, + make_insns: impl FnOnce(StatePartIndex) -> Vec, + ) -> CompiledValue { + self.compile_expr_helper(instantiated_module, dest_ty, |_, dest| { + assert_eq!(dest.len(), TypeLen::A_BIG_SLOT); + make_insns(dest.big_slots.start) + }) + } + fn simple_nary_big_expr( + &mut self, + instantiated_module: InstantiatedModule, + dest_ty: CanonicalType, + inputs: [Expr; N], + make_insns: impl FnOnce( + StatePartIndex, + [StatePartIndex; N], + ) -> Vec, + ) -> CompiledValue { + let inputs = inputs.map(|input| self.simple_big_expr_input(instantiated_module, input)); + self.simple_nary_big_expr_helper(instantiated_module, dest_ty, |dest| { + make_insns(dest, inputs) + }) + } + fn compiled_value_to_dyn_array_index( + &mut self, + compiled_value: CompiledValue, + source_location: SourceLocation, + ) -> StatePartIndex { + if let Some(&retval) = self + .compiled_values_to_dyn_array_indexes + .get(&compiled_value) + { + return retval; + } + let mut ty = compiled_value.layout.ty; + ty.width = ty.width.min(SmallUInt::BITS as usize); + let retval = match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => compiled_value.range.small_slots.start, + TypeLen::A_BIG_SLOT => { + let debug_data = SlotDebugData { + name: Interned::default(), + ty: ty.canonical(), + }; + let dest = self + .insns + .allocate_variable(&TypeLayout { + small_slots: StatePartLayout::scalar(debug_data, ()), + big_slots: StatePartLayout::empty(), + }) + .small_slots + .start; + self.add_assignment( + Interned::default(), + vec![Insn::CastBigToArrayIndex { + dest, + src: compiled_value.range.big_slots.start, + }], + source_location, + ); + dest + } + _ => unreachable!(), + }; + self.compiled_values_to_dyn_array_indexes + .insert(compiled_value, retval); + retval + } + fn compiled_value_bool_dest_is_small( + &mut self, + compiled_value: CompiledValue, + source_location: SourceLocation, + ) -> StatePartIndex { + if let Some(&retval) = self + .compiled_value_bool_dest_is_small_map + .get(&compiled_value) + { + return retval; + } + let retval = match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => compiled_value.range.small_slots.start, + TypeLen::A_BIG_SLOT => { + let debug_data = SlotDebugData { + name: Interned::default(), + ty: Bool.canonical(), + }; + let dest = self + .insns + .allocate_variable(&TypeLayout { + small_slots: StatePartLayout::scalar(debug_data, ()), + big_slots: StatePartLayout::empty(), + }) + .small_slots + .start; + self.add_assignment( + Interned::default(), + vec![Insn::IsNonZeroDestIsSmall { + dest, + src: compiled_value.range.big_slots.start, + }], + source_location, + ); + dest + } + _ => unreachable!(), + }; + self.compiled_value_bool_dest_is_small_map + .insert(compiled_value, retval); + retval + } + fn compile_cast_scalar_to_bits( + &mut self, + instantiated_module: InstantiatedModule, + arg: Expr, + cast_fn: impl FnOnce(Expr) -> Expr, + ) -> CompiledValue { + let arg = Expr::::from_canonical(arg); + let retval = cast_fn(arg); + let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); + let retval = self + .compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()); + retval.map_ty(UInt::from_canonical) + } + fn compile_cast_aggregate_to_bits( + &mut self, + instantiated_module: InstantiatedModule, + parts: impl IntoIterator>, + ) -> CompiledValue { + let retval = parts + .into_iter() + .map(|part| part.cast_to_bits()) + .reduce(|accumulator, part| accumulator | (part << Expr::ty(accumulator).width)) + .unwrap_or_else(|| UInt[0].zero().to_expr()); + let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); + let retval = self + .compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()); + retval.map_ty(UInt::from_canonical) + } + fn compile_cast_to_bits( + &mut self, + instantiated_module: InstantiatedModule, + expr: ops::CastToBits, + ) -> CompiledValue { + match Expr::ty(expr.arg()) { + CanonicalType::UInt(_) => { + self.compile_cast_scalar_to_bits(instantiated_module, expr.arg(), |arg| arg) + } + CanonicalType::SInt(ty) => self.compile_cast_scalar_to_bits( + instantiated_module, + expr.arg(), + |arg: Expr| arg.cast_to(ty.as_same_width_uint()), + ), + CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) => self.compile_cast_scalar_to_bits( + instantiated_module, + expr.arg(), + |arg: Expr| arg.cast_to(UInt[1]), + ), + CanonicalType::Array(ty) => self.compile_cast_aggregate_to_bits( + instantiated_module, + (0..ty.len()).map(|index| Expr::::from_canonical(expr.arg())[index]), + ), + CanonicalType::Enum(ty) => self + .simple_nary_big_expr( + instantiated_module, + UInt[ty.type_properties().bit_width].canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| vec![Insn::Copy { dest, src }], + ) + .map_ty(UInt::from_canonical), + CanonicalType::Bundle(ty) => self.compile_cast_aggregate_to_bits( + instantiated_module, + ty.fields().iter().map(|field| { + Expr::field(Expr::::from_canonical(expr.arg()), &field.name) + }), + ), + } + } + fn compile_cast_bits_to( + &mut self, + instantiated_module: InstantiatedModule, + expr: ops::CastBitsTo, + ) -> CompiledValue { + let retval = match expr.ty() { + CanonicalType::UInt(_) => Expr::canonical(expr.arg()), + CanonicalType::SInt(ty) => Expr::canonical(expr.arg().cast_to(ty)), + CanonicalType::Bool(ty) => Expr::canonical(expr.arg().cast_to(ty)), + CanonicalType::Array(ty) => { + let stride = ty.element().bit_width(); + Expr::::canonical( + ops::ArrayLiteral::new( + ty.element(), + Interned::from_iter((0..ty.len()).map(|index| { + let start = stride * index; + let end = start + stride; + expr.arg()[start..end].cast_bits_to(ty.element()) + })), + ) + .to_expr(), + ) + } + ty @ CanonicalType::Enum(_) => { + return self.simple_nary_big_expr( + instantiated_module, + ty, + [Expr::canonical(expr.arg())], + |dest, [src]| vec![Insn::Copy { dest, src }], + ); + } + CanonicalType::Bundle(ty) => Expr::canonical( + ops::BundleLiteral::new( + ty, + Interned::from_iter(ty.field_offsets().iter().zip(&ty.fields()).map( + |(&offset, &field)| { + let end = offset + field.ty.bit_width(); + expr.arg()[offset..end].cast_bits_to(field.ty) + }, + )), + ) + .to_expr(), + ), + CanonicalType::AsyncReset(ty) => Expr::canonical(expr.arg().cast_to(ty)), + CanonicalType::SyncReset(ty) => Expr::canonical(expr.arg().cast_to(ty)), + CanonicalType::Reset(_) => unreachable!(), + CanonicalType::Clock(ty) => Expr::canonical(expr.arg().cast_to(ty)), + }; + let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); + self.compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()) + } + fn compile_aggregate_literal( + &mut self, + instantiated_module: InstantiatedModule, + dest_ty: CanonicalType, + inputs: Interned<[Expr]>, + ) -> CompiledValue { + self.compile_expr_helper(instantiated_module, dest_ty, |this, dest| { + let mut insns = Vec::new(); + let mut offset = TypeIndex::ZERO; + for input in inputs { + let input = this.compile_expr(instantiated_module, input); + let input = this + .compiled_expr_to_value( + input, + instantiated_module.leaf_module().source_location(), + ) + .range; + insns.extend( + input.insns_for_copy_to(dest.slice(TypeIndexRange::new(offset, input.len()))), + ); + offset = offset.offset(input.len().as_index()); + } + insns + }) + } + fn compile_expr( + &mut self, + instantiated_module: InstantiatedModule, + expr: Expr, + ) -> CompiledExpr { + if let Some(&retval) = self.compiled_exprs.get(&expr) { + return retval; + } + let mut cast_bit = |arg: Expr| { + let src_signed = match Expr::ty(arg) { + CanonicalType::UInt(_) => false, + CanonicalType::SInt(_) => true, + CanonicalType::Bool(_) => false, + CanonicalType::Array(_) => unreachable!(), + CanonicalType::Enum(_) => unreachable!(), + CanonicalType::Bundle(_) => unreachable!(), + CanonicalType::AsyncReset(_) => false, + CanonicalType::SyncReset(_) => false, + CanonicalType::Reset(_) => false, + CanonicalType::Clock(_) => false, + }; + let dest_signed = match Expr::ty(expr) { + CanonicalType::UInt(_) => false, + CanonicalType::SInt(_) => true, + CanonicalType::Bool(_) => false, + CanonicalType::Array(_) => unreachable!(), + CanonicalType::Enum(_) => unreachable!(), + CanonicalType::Bundle(_) => unreachable!(), + CanonicalType::AsyncReset(_) => false, + CanonicalType::SyncReset(_) => false, + CanonicalType::Reset(_) => false, + CanonicalType::Clock(_) => false, + }; + self.simple_nary_big_expr(instantiated_module, Expr::ty(expr), [arg], |dest, [src]| { + match (src_signed, dest_signed) { + (false, false) | (true, true) => { + vec![Insn::Copy { dest, src }] + } + (false, true) => vec![Insn::CastToSInt { + dest, + src, + dest_width: 1, + }], + (true, false) => vec![Insn::CastToUInt { + dest, + src, + dest_width: 1, + }], + } + }) + .into() + }; + let retval: CompiledExpr<_> = match *Expr::expr_enum(expr) { + ExprEnum::UIntLiteral(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [], + |dest, []| { + vec![Insn::Const { + dest, + value: expr.to_bigint().intern_sized(), + }] + }, + ) + .into(), + ExprEnum::SIntLiteral(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [], + |dest, []| { + vec![Insn::Const { + dest, + value: expr.to_bigint().intern_sized(), + }] + }, + ) + .into(), + ExprEnum::BoolLiteral(expr) => self + .simple_nary_big_expr(instantiated_module, Bool.canonical(), [], |dest, []| { + vec![Insn::Const { + dest, + value: BigInt::from(expr).intern_sized(), + }] + }) + .into(), + ExprEnum::BundleLiteral(literal) => self + .compile_aggregate_literal( + instantiated_module, + Expr::ty(expr), + literal.field_values(), + ) + .into(), + ExprEnum::ArrayLiteral(literal) => self + .compile_aggregate_literal( + instantiated_module, + Expr::ty(expr), + literal.element_values(), + ) + .into(), + ExprEnum::EnumLiteral(expr) => { + let enum_bits_ty = UInt[expr.ty().type_properties().bit_width]; + let enum_bits = if let Some(variant_value) = expr.variant_value() { + ( + UInt[expr.ty().discriminant_bit_width()] + .from_int_wrapping(expr.variant_index()), + variant_value, + ) + .cast_to_bits() + .cast_to(enum_bits_ty) + } else { + enum_bits_ty + .from_int_wrapping(expr.variant_index()) + .to_expr() + }; + self.compile_expr( + instantiated_module, + enum_bits.cast_bits_to(expr.ty().canonical()), + ) + } + ExprEnum::Uninit(expr) => self.compile_expr( + instantiated_module, + UInt[expr.ty().bit_width()].zero().cast_bits_to(expr.ty()), + ), + ExprEnum::NotU(expr) => self + .simple_nary_big_expr( + instantiated_module, + Expr::ty(expr.arg()).canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| { + vec![Insn::NotU { + dest, + src, + width: Expr::ty(expr.arg()).width(), + }] + }, + ) + .into(), + ExprEnum::NotS(expr) => self + .simple_nary_big_expr( + instantiated_module, + Expr::ty(expr.arg()).canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| vec![Insn::NotS { dest, src }], + ) + .into(), + ExprEnum::NotB(expr) => self + .simple_nary_big_expr( + instantiated_module, + Expr::ty(expr.arg()).canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| { + vec![Insn::NotU { + dest, + src, + width: 1, + }] + }, + ) + .into(), + ExprEnum::Neg(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| vec![Insn::Neg { dest, src }], + ) + .into(), + ExprEnum::BitAndU(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], + ) + .into(), + ExprEnum::BitAndS(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], + ) + .into(), + ExprEnum::BitAndB(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], + ) + .into(), + ExprEnum::BitOrU(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], + ) + .into(), + ExprEnum::BitOrS(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], + ) + .into(), + ExprEnum::BitOrB(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], + ) + .into(), + ExprEnum::BitXorU(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], + ) + .into(), + ExprEnum::BitXorS(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], + ) + .into(), + ExprEnum::BitXorB(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], + ) + .into(), + ExprEnum::AddU(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::Add { dest, lhs, rhs }], + ) + .into(), + ExprEnum::AddS(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::Add { dest, lhs, rhs }], + ) + .into(), + ExprEnum::SubU(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| { + vec![Insn::SubU { + dest, + lhs, + rhs, + dest_width: expr.ty().width(), + }] + }, + ) + .into(), + ExprEnum::SubS(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::SubS { dest, lhs, rhs }], + ) + .into(), + ExprEnum::MulU(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::Mul { dest, lhs, rhs }], + ) + .into(), + ExprEnum::MulS(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::Mul { dest, lhs, rhs }], + ) + .into(), + ExprEnum::DivU(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::Div { dest, lhs, rhs }], + ) + .into(), + ExprEnum::DivS(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::Div { dest, lhs, rhs }], + ) + .into(), + ExprEnum::RemU(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::Rem { dest, lhs, rhs }], + ) + .into(), + ExprEnum::RemS(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::Rem { dest, lhs, rhs }], + ) + .into(), + ExprEnum::DynShlU(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::DynShl { dest, lhs, rhs }], + ) + .into(), + ExprEnum::DynShlS(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::DynShl { dest, lhs, rhs }], + ) + .into(), + ExprEnum::DynShrU(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::DynShr { dest, lhs, rhs }], + ) + .into(), + ExprEnum::DynShrS(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::DynShr { dest, lhs, rhs }], + ) + .into(), + ExprEnum::FixedShlU(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs())], + |dest, [lhs]| { + vec![Insn::Shl { + dest, + lhs, + rhs: expr.rhs(), + }] + }, + ) + .into(), + ExprEnum::FixedShlS(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs())], + |dest, [lhs]| { + vec![Insn::Shl { + dest, + lhs, + rhs: expr.rhs(), + }] + }, + ) + .into(), + ExprEnum::FixedShrU(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs())], + |dest, [lhs]| { + vec![Insn::Shr { + dest, + lhs, + rhs: expr.rhs(), + }] + }, + ) + .into(), + ExprEnum::FixedShrS(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.lhs())], + |dest, [lhs]| { + vec![Insn::Shr { + dest, + lhs, + rhs: expr.rhs(), + }] + }, + ) + .into(), + ExprEnum::CmpLtB(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpLeB(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpGtB(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + // swap both comparison direction and lhs/rhs + [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], + |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpGeB(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + // swap both comparison direction and lhs/rhs + [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], + |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpEqB(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpNeB(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpLtU(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpLeU(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpGtU(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + // swap both comparison direction and lhs/rhs + [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], + |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpGeU(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + // swap both comparison direction and lhs/rhs + [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], + |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpEqU(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpNeU(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpLtS(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpLeS(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpGtS(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + // swap both comparison direction and lhs/rhs + [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], + |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpGeS(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + // swap both comparison direction and lhs/rhs + [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], + |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpEqS(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CmpNeS(expr) => self + .simple_nary_big_expr( + instantiated_module, + Bool.canonical(), + [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], + |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], + ) + .into(), + ExprEnum::CastUIntToUInt(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| { + vec![Insn::CastToUInt { + dest, + src, + dest_width: expr.ty().width(), + }] + }, + ) + .into(), + ExprEnum::CastUIntToSInt(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| { + vec![Insn::CastToSInt { + dest, + src, + dest_width: expr.ty().width(), + }] + }, + ) + .into(), + ExprEnum::CastSIntToUInt(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| { + vec![Insn::CastToUInt { + dest, + src, + dest_width: expr.ty().width(), + }] + }, + ) + .into(), + ExprEnum::CastSIntToSInt(expr) => self + .simple_nary_big_expr( + instantiated_module, + expr.ty().canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| { + vec![Insn::CastToSInt { + dest, + src, + dest_width: expr.ty().width(), + }] + }, + ) + .into(), + ExprEnum::CastBoolToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastBoolToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastUIntToBool(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastSIntToBool(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastBoolToSyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastUIntToSyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastSIntToSyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastBoolToAsyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastUIntToAsyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastSIntToAsyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastSyncResetToBool(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastSyncResetToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastSyncResetToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastSyncResetToReset(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastAsyncResetToBool(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastAsyncResetToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastAsyncResetToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastAsyncResetToReset(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastResetToBool(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastResetToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastResetToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastBoolToClock(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastUIntToClock(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastSIntToClock(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastClockToBool(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastClockToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::CastClockToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), + ExprEnum::FieldAccess(expr) => self + .compile_expr(instantiated_module, Expr::canonical(expr.base())) + .map_ty(Bundle::from_canonical) + .field_by_index(expr.field_index()), + ExprEnum::VariantAccess(variant_access) => { + let start = Expr::ty(variant_access.base()).discriminant_bit_width(); + let len = Expr::ty(expr).bit_width(); + self.compile_expr( + instantiated_module, + variant_access.base().cast_to_bits()[start..start + len] + .cast_bits_to(Expr::ty(expr)), + ) + } + ExprEnum::ArrayIndex(expr) => self + .compile_expr(instantiated_module, Expr::canonical(expr.base())) + .map_ty(Array::from_canonical) + .element(expr.element_index()), + ExprEnum::DynArrayIndex(expr) => { + let element_index = + self.compile_expr(instantiated_module, Expr::canonical(expr.element_index())); + let element_index = self.compiled_expr_to_value( + element_index, + instantiated_module.leaf_module().source_location(), + ); + let index_slot = self.compiled_value_to_dyn_array_index( + element_index.map_ty(UInt::from_canonical), + instantiated_module.leaf_module().source_location(), + ); + self.compile_expr(instantiated_module, Expr::canonical(expr.base())) + .map_ty(Array::from_canonical) + .element_dyn(index_slot) + } + ExprEnum::ReduceBitAndU(expr) => if Expr::ty(expr.arg()).width() == 0 { + self.compile_expr(instantiated_module, Expr::canonical(true.to_expr())) + } else { + self.compile_expr( + instantiated_module, + Expr::canonical( + expr.arg() + .cmp_eq(Expr::ty(expr.arg()).from_int_wrapping(-1)), + ), + ) + } + .into(), + ExprEnum::ReduceBitAndS(expr) => if Expr::ty(expr.arg()).width() == 0 { + self.compile_expr(instantiated_module, Expr::canonical(true.to_expr())) + } else { + self.compile_expr( + instantiated_module, + Expr::canonical( + expr.arg() + .cmp_eq(Expr::ty(expr.arg()).from_int_wrapping(-1)), + ), + ) + } + .into(), + ExprEnum::ReduceBitOrU(expr) => if Expr::ty(expr.arg()).width() == 0 { + self.compile_expr(instantiated_module, Expr::canonical(false.to_expr())) + } else { + self.compile_expr( + instantiated_module, + Expr::canonical(expr.arg().cmp_ne(Expr::ty(expr.arg()).from_int_wrapping(0))), + ) + } + .into(), + ExprEnum::ReduceBitOrS(expr) => if Expr::ty(expr.arg()).width() == 0 { + self.compile_expr(instantiated_module, Expr::canonical(false.to_expr())) + } else { + self.compile_expr( + instantiated_module, + Expr::canonical(expr.arg().cmp_ne(Expr::ty(expr.arg()).from_int_wrapping(0))), + ) + } + .into(), + ExprEnum::ReduceBitXorU(expr) => self + .simple_nary_big_expr( + instantiated_module, + UInt::<1>::TYPE.canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| { + vec![Insn::ReduceBitXor { + dest, + src, + input_width: Expr::ty(expr.arg()).width(), + }] + }, + ) + .into(), + ExprEnum::ReduceBitXorS(expr) => self + .simple_nary_big_expr( + instantiated_module, + UInt::<1>::TYPE.canonical(), + [Expr::canonical(expr.arg())], + |dest, [src]| { + vec![Insn::ReduceBitXor { + dest, + src, + input_width: Expr::ty(expr.arg()).width(), + }] + }, + ) + .into(), + ExprEnum::SliceUInt(expr) => self + .simple_nary_big_expr( + instantiated_module, + UInt::new_dyn(expr.range().len()).canonical(), + [Expr::canonical(expr.base())], + |dest, [src]| { + vec![Insn::SliceInt { + dest, + src, + start: expr.range().start, + len: expr.range().len(), + }] + }, + ) + .into(), + ExprEnum::SliceSInt(expr) => self + .simple_nary_big_expr( + instantiated_module, + UInt::new_dyn(expr.range().len()).canonical(), + [Expr::canonical(expr.base())], + |dest, [src]| { + vec![Insn::SliceInt { + dest, + src, + start: expr.range().start, + len: expr.range().len(), + }] + }, + ) + .into(), + ExprEnum::CastToBits(expr) => self + .compile_cast_to_bits(instantiated_module, expr) + .map_ty(CanonicalType::UInt) + .into(), + ExprEnum::CastBitsTo(expr) => { + self.compile_cast_bits_to(instantiated_module, expr).into() + } + ExprEnum::ModuleIO(expr) => self + .compile_value(TargetInInstantiatedModule { + instantiated_module, + target: expr.into(), + }) + .into(), + ExprEnum::Instance(expr) => self + .compile_value(TargetInInstantiatedModule { + instantiated_module, + target: expr.into(), + }) + .into(), + ExprEnum::Wire(expr) => self + .compile_value(TargetInInstantiatedModule { + instantiated_module, + target: expr.into(), + }) + .into(), + ExprEnum::Reg(expr) => self + .compile_value(TargetInInstantiatedModule { + instantiated_module, + target: expr.into(), + }) + .into(), + ExprEnum::RegSync(expr) => self + .compile_value(TargetInInstantiatedModule { + instantiated_module, + target: expr.into(), + }) + .into(), + ExprEnum::RegAsync(expr) => self + .compile_value(TargetInInstantiatedModule { + instantiated_module, + target: expr.into(), + }) + .into(), + ExprEnum::MemPort(expr) => self + .compile_value(TargetInInstantiatedModule { + instantiated_module, + target: expr.into(), + }) + .into(), + }; + self.compiled_exprs.insert(expr, retval); + retval + } + fn compile_simple_connect( + &mut self, + conditions: Interned<[Cond]>, + lhs: CompiledExpr, + rhs: CompiledValue, + source_location: SourceLocation, + ) { + let CompiledExpr { + static_part: lhs_static_part, + indexes, + } = lhs; + let (lhs_layout, lhs_range) = lhs_static_part.write(); + assert!( + lhs_layout.ty.is_passive(), + "invalid expression passed to compile_simple_connect -- type must be passive", + ); + let TypeIndexRange { + small_slots, + big_slots, + } = lhs_range; + self.add_assignment( + conditions, + small_slots + .iter() + .zip(rhs.range.small_slots.iter()) + .map(|(base, src)| { + if indexes.small_slots.is_empty() { + Insn::CopySmall { dest: base, src } + } else { + Insn::WriteSmallIndexed { + dest: StatePartArrayIndexed { + base, + indexes: indexes.small_slots, + }, + src, + } + } + }) + .chain( + big_slots + .iter() + .zip(rhs.range.big_slots.iter()) + .map(|(base, src)| { + if indexes.big_slots.is_empty() { + Insn::Copy { dest: base, src } + } else { + Insn::WriteIndexed { + dest: StatePartArrayIndexed { + base, + indexes: indexes.big_slots, + }, + src, + } + } + }), + ), + source_location, + ); + } + fn compile_connect( + &mut self, + lhs_instantiated_module: InstantiatedModule, + lhs_conditions: Interned<[Cond]>, + lhs: Expr, + rhs_instantiated_module: InstantiatedModule, + rhs_conditions: Interned<[Cond]>, + mut rhs: Expr, + source_location: SourceLocation, + ) { + if Expr::ty(lhs) != Expr::ty(rhs) || !Expr::ty(lhs).is_passive() { + match Expr::ty(lhs) { + CanonicalType::UInt(lhs_ty) => { + rhs = Expr::canonical(Expr::::from_canonical(rhs).cast_to(lhs_ty)); + } + CanonicalType::SInt(lhs_ty) => { + rhs = Expr::canonical(Expr::::from_canonical(rhs).cast_to(lhs_ty)); + } + CanonicalType::Bool(_) => unreachable!(), + CanonicalType::Array(lhs_ty) => { + let CanonicalType::Array(rhs_ty) = Expr::ty(rhs) else { + unreachable!(); + }; + assert_eq!(lhs_ty.len(), rhs_ty.len()); + let lhs = Expr::::from_canonical(lhs); + let rhs = Expr::::from_canonical(rhs); + for index in 0..lhs_ty.len() { + self.compile_connect( + lhs_instantiated_module, + lhs_conditions, + lhs[index], + rhs_instantiated_module, + rhs_conditions, + rhs[index], + source_location, + ); + } + return; + } + CanonicalType::Enum(lhs_ty) => { + let CanonicalType::Enum(rhs_ty) = Expr::ty(rhs) else { + unreachable!(); + }; + todo!("handle connect with different enum types"); + } + CanonicalType::Bundle(lhs_ty) => { + let CanonicalType::Bundle(rhs_ty) = Expr::ty(rhs) else { + unreachable!(); + }; + assert_eq!(lhs_ty.fields().len(), rhs_ty.fields().len()); + let lhs = Expr::::from_canonical(lhs); + let rhs = Expr::::from_canonical(rhs); + for ( + field_index, + ( + BundleField { + name, + flipped, + ty: _, + }, + rhs_field, + ), + ) in lhs_ty.fields().into_iter().zip(rhs_ty.fields()).enumerate() + { + assert_eq!(name, rhs_field.name); + assert_eq!(flipped, rhs_field.flipped); + let lhs_expr = ops::FieldAccess::new_by_index(lhs, field_index).to_expr(); + let rhs_expr = ops::FieldAccess::new_by_index(rhs, field_index).to_expr(); + if flipped { + // swap lhs/rhs + self.compile_connect( + rhs_instantiated_module, + rhs_conditions, + rhs_expr, + lhs_instantiated_module, + lhs_conditions, + lhs_expr, + source_location, + ); + } else { + self.compile_connect( + lhs_instantiated_module, + lhs_conditions, + lhs_expr, + rhs_instantiated_module, + rhs_conditions, + rhs_expr, + source_location, + ); + } + } + return; + } + CanonicalType::AsyncReset(_) => unreachable!(), + CanonicalType::SyncReset(_) => unreachable!(), + CanonicalType::Reset(_) => unreachable!(), + CanonicalType::Clock(_) => unreachable!(), + } + } + let Some(target) = lhs.target() else { + unreachable!("connect lhs must have target"); + }; + let lhs_decl_conditions = self.decl_conditions[&TargetInInstantiatedModule { + instantiated_module: lhs_instantiated_module, + target: target.base().into(), + }]; + let lhs = self.compile_expr(lhs_instantiated_module, lhs); + let rhs = self.compile_expr(rhs_instantiated_module, rhs); + let rhs = self.compiled_expr_to_value(rhs, source_location); + self.compile_simple_connect( + lhs_conditions[lhs_decl_conditions.len()..].intern(), + lhs, + rhs, + source_location, + ); + } + fn compile_clock( + &mut self, + clk: CompiledValue, + source_location: SourceLocation, + ) -> ClockTrigger { + if let Some(&retval) = self.compiled_value_to_clock_trigger_map.get(&clk) { + return retval; + } + let mut alloc_small_slot = |part_name: &str| { + self.insns + .state_layout + .ty + .small_slots + .allocate(&StatePartLayout::scalar( + SlotDebugData { + name: Interned::default(), + ty: Bool.canonical(), + }, + (), + )) + .start + }; + let last_clk_was_low = alloc_small_slot("last_clk_was_low"); + let clk_triggered = alloc_small_slot("clk_triggered"); + let retval = ClockTrigger { + last_clk_was_low, + clk: self.compiled_value_bool_dest_is_small( + clk.map_ty(CanonicalType::Clock), + source_location, + ), + clk_triggered, + source_location, + }; + self.add_assignment( + Interned::default(), + [Insn::AndSmall { + dest: clk_triggered, + lhs: retval.clk, + rhs: last_clk_was_low, + }], + source_location, + ); + self.clock_triggers.push(retval); + self.compiled_value_to_clock_trigger_map.insert(clk, retval); + retval + } + fn compile_enum_discriminant( + &mut self, + enum_value: CompiledValue, + source_location: SourceLocation, + ) -> StatePartIndex { + if let Some(&retval) = self.enum_discriminants.get(&enum_value) { + return retval; + } + let retval_ty = Enum::new( + enum_value + .layout + .ty + .variants() + .iter() + .map(|variant| EnumVariant { + name: variant.name, + ty: None, + }) + .collect(), + ); + let retval = if retval_ty == enum_value.layout.ty + && enum_value.range.len() == TypeLen::A_SMALL_SLOT + { + enum_value.range.small_slots.start + } else { + let retval = self + .insns + .state_layout + .ty + .small_slots + .allocate(&StatePartLayout::scalar( + SlotDebugData { + name: Interned::default(), + ty: retval_ty.canonical(), + }, + (), + )) + .start; + let discriminant_bit_width = enum_value.layout.ty.discriminant_bit_width(); + let discriminant_mask = !(!0u64 << discriminant_bit_width); + let insn = match enum_value.range.len() { + TypeLen::A_BIG_SLOT => Insn::AndBigWithSmallImmediate { + dest: retval, + lhs: enum_value.range.big_slots.start, + rhs: discriminant_mask, + }, + TypeLen::A_SMALL_SLOT => { + if discriminant_bit_width == enum_value.layout.ty.type_properties().bit_width { + Insn::CopySmall { + dest: retval, + src: enum_value.range.small_slots.start, + } + } else { + Insn::AndSmallImmediate { + dest: retval, + lhs: enum_value.range.small_slots.start, + rhs: discriminant_mask, + } + } + } + _ => unreachable!(), + }; + self.add_assignment(Interned::default(), [insn], source_location); + retval + }; + self.enum_discriminants.insert(enum_value, retval); + retval + } + fn compile_stmt_reg( + &mut self, + stmt_reg: StmtReg, + instantiated_module: InstantiatedModule, + value: CompiledValue, + ) { + let StmtReg { annotations, reg } = stmt_reg; + let clk = self.compile_expr(instantiated_module, Expr::canonical(reg.clock_domain().clk)); + let clk = self + .compiled_expr_to_value(clk, reg.source_location()) + .map_ty(Clock::from_canonical); + let clk = self.compile_clock(clk, reg.source_location()); + struct Dispatch; + impl ResetTypeDispatch for Dispatch { + type Input = (); + + type Output = bool; + + fn reset(self, _input: Self::Input) -> Self::Output { + unreachable!() + } + + fn sync_reset(self, _input: Self::Input) -> Self::Output { + false + } + + fn async_reset(self, _input: Self::Input) -> Self::Output { + true + } + } + let reset = if let Some(init) = reg.init() { + let init = self.compile_expr(instantiated_module, init); + let init = self.compiled_expr_to_value(init, reg.source_location()); + let rst = + self.compile_expr(instantiated_module, Expr::canonical(reg.clock_domain().rst)); + let rst = self.compiled_expr_to_value(rst, reg.source_location()); + let rst = self.compiled_value_bool_dest_is_small(rst, reg.source_location()); + let is_async = R::dispatch((), Dispatch); + if is_async { + let cond = Expr::canonical(reg.clock_domain().rst.cast_to(Bool)); + let cond = self.compile_expr(instantiated_module, cond); + let cond = self.compiled_expr_to_value(cond, reg.source_location()); + let cond = cond.map_ty(Bool::from_canonical); + // write to the register's current value since asynchronous reset is combinational + let lhs = CompiledValue { + layout: value.layout, + range: value.range, + write: None, + } + .into(); + self.compile_simple_connect( + [Cond { + body: CondBody::IfTrue { cond }, + source_location: reg.source_location(), + }][..] + .intern(), + lhs, + init, + reg.source_location(), + ); + } + Some(RegisterReset { + is_async, + init, + rst, + }) + } else { + None + }; + self.registers.push(Register { + value, + clk_triggered: clk.clk_triggered, + reset, + source_location: reg.source_location(), + }); + } + fn compile_declaration( + &mut self, + declaration: StmtDeclaration, + parent_module: Interned, + conditions: Interned<[Cond]>, + ) -> TraceDecl { + let target_base: TargetBase = match &declaration { + StmtDeclaration::Wire(v) => v.wire.into(), + StmtDeclaration::Reg(v) => v.reg.into(), + StmtDeclaration::RegSync(v) => v.reg.into(), + StmtDeclaration::RegAsync(v) => v.reg.into(), + StmtDeclaration::Instance(v) => v.instance.into(), + }; + let target = TargetInInstantiatedModule { + instantiated_module: *parent_module, + target: target_base.into(), + }; + self.decl_conditions.insert(target, conditions); + let compiled_value = self.compile_value(target); + match declaration { + StmtDeclaration::Wire(StmtWire { annotations, wire }) => {} + StmtDeclaration::Reg(_) => { + unreachable!("Reset types were already replaced by SyncReset or AsyncReset"); + } + StmtDeclaration::RegSync(stmt_reg) => { + self.compile_stmt_reg(stmt_reg, *parent_module, compiled_value) + } + StmtDeclaration::RegAsync(stmt_reg) => { + self.compile_stmt_reg(stmt_reg, *parent_module, compiled_value) + } + StmtDeclaration::Instance(StmtInstance { + annotations, + instance, + }) => { + let inner_instantiated_module = InstantiatedModule::Child { + parent: parent_module, + instance: instance.intern_sized(), + } + .intern_sized(); + let instance_expr = instance.to_expr(); + self.compile_module(inner_instantiated_module); + for (field_index, module_io) in + instance.instantiated().module_io().into_iter().enumerate() + { + let instance_field = + ops::FieldAccess::new_by_index(instance_expr, field_index).to_expr(); + match Expr::flow(instance_field) { + Flow::Source => { + // we need to supply the value to the instance since the + // parent module expects to read from the instance + self.compile_connect( + *parent_module, + conditions, + instance_field, + *inner_instantiated_module, + Interned::default(), + module_io.module_io.to_expr(), + instance.source_location(), + ); + } + Flow::Sink => { + // we need to take the value from the instance since the + // parent module expects to write to the instance + self.compile_connect( + *inner_instantiated_module, + Interned::default(), + module_io.module_io.to_expr(), + *parent_module, + conditions, + instance_field, + instance.source_location(), + ); + } + Flow::Duplex => unreachable!(), + } + } + } + } + self.make_trace_decl(*parent_module, target_base) + } + fn allocate_delay_chain( + &mut self, + len: usize, + layout: &TypeLayout, + first: Option, + last: Option, + mut from_allocation: impl FnMut(TypeIndexRange) -> T, + ) -> Vec { + match (len, first, last) { + (0, _, _) => Vec::new(), + (1, Some(v), _) | (1, None, Some(v)) => vec![v], + (2, Some(first), Some(last)) => vec![first, last], + (len, first, last) => { + let inner_len = len - first.is_some() as usize - last.is_some() as usize; + first + .into_iter() + .chain( + (0..inner_len) + .map(|_| from_allocation(self.insns.allocate_variable(layout))), + ) + .chain(last) + .collect() + } + } + } + fn allocate_delay_chain_small( + &mut self, + len: usize, + ty: CanonicalType, + first: Option>, + last: Option>, + ) -> Vec> { + self.allocate_delay_chain( + len, + &TypeLayout { + small_slots: StatePartLayout::scalar( + SlotDebugData { + name: Interned::default(), + ty, + }, + (), + ), + big_slots: StatePartLayout::empty(), + }, + first, + last, + |range| range.small_slots.start, + ) + } + fn compile_memory_port_rw_helper( + &mut self, + memory: StatePartIndex, + stride: usize, + mut start: usize, + data_layout: CompiledTypeLayout, + mask_layout: CompiledTypeLayout, + mut read: Option>, + mut write: Option>, + ) { + match data_layout.body { + CompiledTypeLayoutBody::Scalar => { + let CompiledTypeLayoutBody::Scalar = mask_layout.body else { + unreachable!(); + }; + let signed = match data_layout.ty { + CanonicalType::UInt(_) => false, + CanonicalType::SInt(_) => true, + CanonicalType::Bool(_) => false, + CanonicalType::Array(_) => unreachable!(), + CanonicalType::Enum(_) => false, + CanonicalType::Bundle(_) => unreachable!(), + CanonicalType::AsyncReset(_) => false, + CanonicalType::SyncReset(_) => false, + CanonicalType::Reset(_) => false, + CanonicalType::Clock(_) => false, + }; + let width = data_layout.ty.bit_width(); + if let Some(MemoryPortReadInsns { + addr, + en: _, + write_mode: _, + data, + insns, + }) = read + { + insns.push( + match data.len() { + TypeLen::A_BIG_SLOT => { + let dest = data.big_slots.start; + if signed { + Insn::MemoryReadSInt { + dest, + memory, + addr, + stride, + start, + width, + } + } else { + Insn::MemoryReadUInt { + dest, + memory, + addr, + stride, + start, + width, + } + } + } + TypeLen::A_SMALL_SLOT => { + let _dest = data.small_slots.start; + todo!("memory ports' data are always big for now"); + } + _ => unreachable!(), + } + .into(), + ); + } + if let Some(MemoryPortWriteInsns { + addr, + en: _, + write_mode: _, + data, + mask, + insns, + }) = write + { + let end_label = self.insns.new_label(); + insns.push( + match mask.len() { + TypeLen::A_BIG_SLOT => Insn::BranchIfZero { + target: end_label.0, + value: mask.big_slots.start, + }, + TypeLen::A_SMALL_SLOT => Insn::BranchIfSmallZero { + target: end_label.0, + value: mask.small_slots.start, + }, + _ => unreachable!(), + } + .into(), + ); + insns.push( + match data.len() { + TypeLen::A_BIG_SLOT => { + let value = data.big_slots.start; + if signed { + Insn::MemoryWriteSInt { + value, + memory, + addr, + stride, + start, + width, + } + } else { + Insn::MemoryWriteUInt { + value, + memory, + addr, + stride, + start, + width, + } + } + } + TypeLen::A_SMALL_SLOT => { + let _value = data.small_slots.start; + todo!("memory ports' data are always big for now"); + } + _ => unreachable!(), + } + .into(), + ); + insns.push(end_label.into()); + } + } + CompiledTypeLayoutBody::Array { element } => { + let CompiledTypeLayoutBody::Array { + element: mask_element, + } = mask_layout.body + else { + unreachable!(); + }; + let ty = ::from_canonical(data_layout.ty); + let element_bit_width = ty.element().bit_width(); + let element_size = element.layout.len(); + let mask_element_size = mask_element.layout.len(); + for element_index in 0..ty.len() { + self.compile_memory_port_rw_helper( + memory, + stride, + start, + *element, + *mask_element, + read.as_mut().map( + |MemoryPortReadInsns { + addr, + en, + write_mode, + data, + insns, + }| MemoryPortReadInsns { + addr: *addr, + en: *en, + write_mode: *write_mode, + data: data.index_array(element_size, element_index), + insns, + }, + ), + write.as_mut().map( + |MemoryPortWriteInsns { + addr, + en, + write_mode, + data, + mask, + insns, + }| { + MemoryPortWriteInsns { + addr: *addr, + en: *en, + write_mode: *write_mode, + data: data.index_array(element_size, element_index), + mask: mask.index_array(mask_element_size, element_index), + insns, + } + }, + ), + ); + start += element_bit_width; + } + } + CompiledTypeLayoutBody::Bundle { fields } => { + let CompiledTypeLayoutBody::Bundle { + fields: mask_fields, + } = mask_layout.body + else { + unreachable!(); + }; + assert_eq!(fields.len(), mask_fields.len()); + for (field, mask_field) in fields.into_iter().zip(mask_fields) { + let field_index_range = + TypeIndexRange::new(field.offset, field.ty.layout.len()); + let mask_field_index_range = + TypeIndexRange::new(mask_field.offset, mask_field.ty.layout.len()); + self.compile_memory_port_rw_helper( + memory, + stride, + start, + field.ty, + mask_field.ty, + read.as_mut().map( + |MemoryPortReadInsns { + addr, + en, + write_mode, + data, + insns, + }| MemoryPortReadInsns { + addr: *addr, + en: *en, + write_mode: *write_mode, + data: data.slice(field_index_range), + insns, + }, + ), + write.as_mut().map( + |MemoryPortWriteInsns { + addr, + en, + write_mode, + data, + mask, + insns, + }| { + MemoryPortWriteInsns { + addr: *addr, + en: *en, + write_mode: *write_mode, + data: data.slice(field_index_range), + mask: mask.slice(mask_field_index_range), + insns, + } + }, + ), + ); + start = start + field.ty.ty.bit_width(); + } + } + } + } + fn compile_memory_port_rw( + &mut self, + memory: StatePartIndex, + data_layout: CompiledTypeLayout, + mask_layout: CompiledTypeLayout, + mut read: Option>, + mut write: Option>, + ) { + let read_else_label = read.as_mut().map( + |MemoryPortReadInsns { + addr: _, + en, + write_mode, + data: _, + insns, + }| { + let else_label = self.insns.new_label(); + insns.push( + Insn::BranchIfSmallZero { + target: else_label.0, + value: *en, + } + .into(), + ); + if let Some(write_mode) = *write_mode { + insns.push( + Insn::BranchIfSmallNonZero { + target: else_label.0, + value: write_mode, + } + .into(), + ); + } + else_label + }, + ); + let write_end_label = write.as_mut().map( + |MemoryPortWriteInsns { + addr: _, + en, + write_mode, + data: _, + mask: _, + insns, + }| { + let end_label = self.insns.new_label(); + insns.push( + Insn::BranchIfSmallZero { + target: end_label.0, + value: *en, + } + .into(), + ); + if let Some(write_mode) = *write_mode { + insns.push( + Insn::BranchIfSmallZero { + target: end_label.0, + value: write_mode, + } + .into(), + ); + } + end_label + }, + ); + self.compile_memory_port_rw_helper( + memory, + data_layout.ty.bit_width(), + 0, + data_layout, + mask_layout, + read.as_mut().map( + |MemoryPortReadInsns { + addr, + en, + write_mode, + data, + insns, + }| MemoryPortReadInsns { + addr: *addr, + en: *en, + write_mode: *write_mode, + data: *data, + insns: *insns, + }, + ), + write.as_mut().map( + |MemoryPortWriteInsns { + addr, + en, + write_mode, + data, + mask, + insns, + }| MemoryPortWriteInsns { + addr: *addr, + en: *en, + write_mode: *write_mode, + data: *data, + mask: *mask, + insns: *insns, + }, + ), + ); + if let ( + Some(else_label), + Some(MemoryPortReadInsns { + addr: _, + en: _, + write_mode: _, + data, + insns, + }), + ) = (read_else_label, read) + { + let end_label = self.insns.new_label(); + insns.push( + Insn::Branch { + target: end_label.0, + } + .into(), + ); + insns.push(else_label.into()); + let TypeIndexRange { + small_slots, + big_slots, + } = data; + for dest in small_slots.iter() { + insns.push(Insn::ConstSmall { dest, value: 0 }.into()); + } + for dest in big_slots.iter() { + insns.push( + Insn::Const { + dest, + value: BigInt::ZERO.intern_sized(), + } + .into(), + ); + } + insns.push(end_label.into()); + } + if let (Some(end_label), Some(write)) = (write_end_label, write) { + write.insns.push(end_label.into()); + } + } + fn compile_memory( + &mut self, + mem: Mem, + instantiated_module: InstantiatedModule, + conditions: Interned<[Cond]>, + trace_decls: &mut Vec, + ) { + let data_layout = CompiledTypeLayout::get(mem.array_type().element()); + let mask_layout = CompiledTypeLayout::get(mem.array_type().element().mask_type()); + let read_latency_plus_1 = mem + .read_latency() + .checked_add(1) + .expect("read latency too big"); + let write_latency_plus_1 = mem + .write_latency() + .get() + .checked_add(1) + .expect("write latency too big"); + let read_cycle = match mem.read_under_write() { + ReadUnderWrite::Old => 0, + ReadUnderWrite::New => mem.read_latency(), + ReadUnderWrite::Undefined => mem.read_latency() / 2, // something other than Old or New + }; + let memory = self + .insns + .state_layout + .memories + .allocate(&StatePartLayout::scalar( + (), + MemoryData { + array_type: mem.array_type(), + data: mem.initial_value().unwrap_or_else(|| { + Intern::intern_owned(BitVec::repeat( + false, + mem.array_type().type_properties().bit_width, + )) + }), + }, + )) + .start; + let (ports, trace_ports) = mem + .ports() + .iter() + .map(|&port| { + let target_base = TargetBase::MemPort(port); + let target = TargetInInstantiatedModule { + instantiated_module, + target: target_base.into(), + }; + self.decl_conditions.insert(target, conditions); + let TraceDecl::Scope(TraceScope::MemPort(trace_port)) = + self.make_trace_decl(instantiated_module, target_base) + else { + unreachable!(); + }; + let clk = Expr::field(port.to_expr(), "clk"); + let clk = self.compile_expr(instantiated_module, clk); + let clk = self.compiled_expr_to_value(clk, mem.source_location()); + let clk_triggered = self + .compile_clock(clk.map_ty(Clock::from_canonical), mem.source_location()) + .clk_triggered; + let en = Expr::field(port.to_expr(), "en"); + let en = self.compile_expr(instantiated_module, en); + let en = self.compiled_expr_to_value(en, mem.source_location()); + let en = self.compiled_value_bool_dest_is_small(en, mem.source_location()); + let addr = Expr::field(port.to_expr(), "addr"); + let addr = self.compile_expr(instantiated_module, addr); + let addr = self.compiled_expr_to_value(addr, mem.source_location()); + let addr_ty = addr.layout.ty; + let addr = self.compiled_value_to_dyn_array_index( + addr.map_ty(UInt::from_canonical), + mem.source_location(), + ); + let read_data = port.port_kind().rdata_name().map(|name| { + let read_data = + self.compile_expr(instantiated_module, Expr::field(port.to_expr(), name)); + let read_data = self.compiled_expr_to_value(read_data, mem.source_location()); + read_data.range + }); + let write_data = port.port_kind().wdata_name().map(|name| { + let write_data = + self.compile_expr(instantiated_module, Expr::field(port.to_expr(), name)); + let write_data = self.compiled_expr_to_value(write_data, mem.source_location()); + write_data.range + }); + let write_mask = port.port_kind().wmask_name().map(|name| { + let write_mask = + self.compile_expr(instantiated_module, Expr::field(port.to_expr(), name)); + let write_mask = self.compiled_expr_to_value(write_mask, mem.source_location()); + write_mask.range + }); + let write_mode = port.port_kind().wmode_name().map(|name| { + let write_mode = + self.compile_expr(instantiated_module, Expr::field(port.to_expr(), name)); + let write_mode = self.compiled_expr_to_value(write_mode, mem.source_location()); + self.compiled_value_bool_dest_is_small(write_mode, mem.source_location()) + }); + struct PortParts { + en_delayed_len: usize, + addr_delayed_len: usize, + read_data_delayed_len: usize, + write_data_delayed_len: usize, + write_mask_delayed_len: usize, + write_mode_delayed_len: usize, + read_cycle: Option, + write_cycle: Option, + } + let PortParts { + en_delayed_len, + addr_delayed_len, + read_data_delayed_len, + write_data_delayed_len, + write_mask_delayed_len, + write_mode_delayed_len, + read_cycle, + write_cycle, + } = match port.port_kind() { + PortKind::ReadOnly => PortParts { + en_delayed_len: read_cycle + 1, + addr_delayed_len: read_cycle + 1, + read_data_delayed_len: read_latency_plus_1 - read_cycle, + write_data_delayed_len: 0, + write_mask_delayed_len: 0, + write_mode_delayed_len: 0, + read_cycle: Some(read_cycle), + write_cycle: None, + }, + PortKind::WriteOnly => PortParts { + en_delayed_len: write_latency_plus_1, + addr_delayed_len: write_latency_plus_1, + read_data_delayed_len: 0, + write_data_delayed_len: write_latency_plus_1, + write_mask_delayed_len: write_latency_plus_1, + write_mode_delayed_len: 0, + read_cycle: None, + write_cycle: Some(mem.write_latency().get()), + }, + PortKind::ReadWrite => { + let can_rw_at_end = match mem.read_under_write() { + ReadUnderWrite::Old => false, + ReadUnderWrite::New | ReadUnderWrite::Undefined => true, + }; + let latency_plus_1 = read_latency_plus_1; + if latency_plus_1 != write_latency_plus_1 || !can_rw_at_end { + todo!( + "not sure what to do, issue: \ + https://github.com/chipsalliance/firrtl-spec/issues/263" + ); + } + PortParts { + en_delayed_len: latency_plus_1, + addr_delayed_len: latency_plus_1, + read_data_delayed_len: 1, + write_data_delayed_len: latency_plus_1, + write_mask_delayed_len: latency_plus_1, + write_mode_delayed_len: latency_plus_1, + read_cycle: Some(latency_plus_1 - 1), + write_cycle: Some(latency_plus_1 - 1), + } + } + }; + let addr_delayed = self.allocate_delay_chain_small( + addr_delayed_len, + addr_ty.canonical(), + Some(addr), + None, + ); + let en_delayed = self.allocate_delay_chain_small( + en_delayed_len, + Bool.canonical(), + Some(en), + None, + ); + let read_data_delayed = self.allocate_delay_chain( + read_data_delayed_len, + &data_layout.layout, + None, + read_data, + |v| v, + ); + let write_data_delayed = self.allocate_delay_chain( + write_data_delayed_len, + &data_layout.layout, + write_data, + None, + |v| v, + ); + let write_mask_delayed = self.allocate_delay_chain( + write_mask_delayed_len, + &mask_layout.layout, + write_mask, + None, + |v| v, + ); + let write_mode_delayed = self.allocate_delay_chain_small( + write_mode_delayed_len, + Bool.canonical(), + write_mode, + None, + ); + let mut read_insns = Vec::new(); + let mut write_insns = Vec::new(); + self.compile_memory_port_rw( + memory, + data_layout, + mask_layout, + read_cycle.map(|read_cycle| MemoryPortReadInsns { + addr: addr_delayed[read_cycle], + en: en_delayed[read_cycle], + write_mode: write_mode_delayed.get(read_cycle).copied(), + data: read_data_delayed[0], + insns: &mut read_insns, + }), + write_cycle.map(|write_cycle| MemoryPortWriteInsns { + addr: addr_delayed[write_cycle], + en: en_delayed[write_cycle], + write_mode: write_mode_delayed.get(write_cycle).copied(), + data: write_data_delayed[write_cycle], + mask: write_mask_delayed[write_cycle], + insns: &mut write_insns, + }), + ); + self.add_assignment(Interned::default(), read_insns, mem.source_location()); + ( + MemoryPort { + clk_triggered, + addr_delayed, + en_delayed, + data_layout, + read_data_delayed, + write_data_delayed, + write_mask_delayed, + write_mode_delayed, + write_insns, + }, + trace_port, + ) + }) + .unzip(); + let name = mem.scoped_name().1 .0; + let id = TraceMemoryId(self.memories.len()); + let stride = mem.array_type().element().bit_width(); + let trace = TraceMem { + id, + name, + stride, + element_type: self + .make_trace_decl_child( + instantiated_module, + MakeTraceDeclTarget::Memory { + id, + depth: mem.array_type().len(), + stride, + start: 0, + ty: mem.array_type().element(), + }, + name, + mem.source_location(), + ) + .intern_sized(), + ports: Intern::intern_owned(trace_ports), + array_type: mem.array_type(), + }; + trace_decls.push(trace.into()); + self.memories.push(Memory { + mem, + memory, + trace, + ports, + }); + } + fn compile_block( + &mut self, + parent_module: Interned, + block: Block, + conditions: Interned<[Cond]>, + trace_decls: &mut Vec, + ) { + let Block { memories, stmts } = block; + for memory in memories { + self.compile_memory(memory, *parent_module, conditions, trace_decls); + } + for stmt in stmts { + match stmt { + Stmt::Connect(StmtConnect { + lhs, + rhs, + source_location, + }) => self.compile_connect( + *parent_module, + conditions, + lhs, + *parent_module, + conditions, + rhs, + source_location, + ), + Stmt::Formal(StmtFormal { .. }) => todo!("implement simulating formal statements"), + Stmt::If(StmtIf { + cond, + source_location, + blocks: [then_block, else_block], + }) => { + let cond = self.compile_expr(*parent_module, Expr::canonical(cond)); + let cond = self.compiled_expr_to_value(cond, source_location); + let cond = cond.map_ty(Bool::from_canonical); + self.compile_block( + parent_module, + then_block, + Interned::from_iter(conditions.iter().copied().chain([Cond { + body: CondBody::IfTrue { cond }, + source_location, + }])), + trace_decls, + ); + self.compile_block( + parent_module, + else_block, + Interned::from_iter(conditions.iter().copied().chain([Cond { + body: CondBody::IfFalse { cond }, + source_location, + }])), + trace_decls, + ); + } + Stmt::Match(StmtMatch { + expr, + source_location, + blocks, + }) => { + let enum_expr = self.compile_expr(*parent_module, Expr::canonical(expr)); + let enum_expr = self.compiled_expr_to_value(enum_expr, source_location); + let enum_expr = enum_expr.map_ty(Enum::from_canonical); + let discriminant = self.compile_enum_discriminant(enum_expr, source_location); + for (variant_index, block) in blocks.into_iter().enumerate() { + self.compile_block( + parent_module, + block, + Interned::from_iter(conditions.iter().copied().chain([Cond { + body: CondBody::MatchArm { + discriminant, + variant_index, + }, + source_location, + }])), + trace_decls, + ); + } + } + Stmt::Declaration(declaration) => { + trace_decls.push(self.compile_declaration( + declaration, + parent_module, + conditions, + )); + } + } + } + } + fn compile_module(&mut self, module: Interned) -> &CompiledModule { + let mut trace_decls = Vec::new(); + let module_io = module + .leaf_module() + .module_io() + .iter() + .map( + |&AnnotatedModuleIO { + annotations: _, + module_io, + }| { + let target = TargetInInstantiatedModule { + instantiated_module: *module, + target: Target::from(module_io), + }; + self.decl_conditions.insert(target, Interned::default()); + trace_decls.push(self.make_trace_decl(*module, module_io.into())); + self.compile_value(target) + }, + ) + .collect(); + match module.leaf_module().body() { + ModuleBody::Normal(NormalModuleBody { body }) => { + self.compile_block(module, body, Interned::default(), &mut trace_decls); + } + ModuleBody::Extern(_extern_module_body) => { + todo!("simulating extern module: {:?}", module); + } + } + let hashbrown::hash_map::Entry::Vacant(entry) = self.modules.entry(*module) else { + unreachable!("compiled same instantiated module twice"); + }; + entry.insert(CompiledModule { + module_io, + trace_decls: TraceModule { + name: module.leaf_module().name(), + children: Intern::intern_owned(trace_decls), + }, + }) + } + fn process_assignments(&mut self) { + self.assignments + .finalize(self.insns.state_layout().ty.clone().into()); + if let Some(DebugOpaque(dump_assignments_dot)) = &self.dump_assignments_dot { + let graph = + petgraph::graph::DiGraph::<_, _, usize>::from_elements(self.assignments.elements()); + dump_assignments_dot(&petgraph::dot::Dot::new(&graph)); + } + let assignments_order: Vec<_> = match petgraph::algo::toposort(&self.assignments, None) { + Ok(nodes) => nodes + .into_iter() + .filter_map(|n| match n { + AssignmentOrSlotIndex::AssignmentIndex(v) => Some(v), + _ => None, + }) + .collect(), + Err(e) => match e.node_id() { + AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => panic!( + "combinatorial logic cycle detected at: {}", + self.assignments.assignments()[assignment_index].source_location, + ), + AssignmentOrSlotIndex::SmallSlot(slot) => panic!( + "combinatorial logic cycle detected through: {}", + self.insns.state_layout().ty.small_slots.debug_data[slot.as_usize()].name, + ), + AssignmentOrSlotIndex::BigSlot(slot) => panic!( + "combinatorial logic cycle detected through: {}", + self.insns.state_layout().ty.big_slots.debug_data[slot.as_usize()].name, + ), + }, + }; + struct CondStackEntry<'a> { + cond: &'a Cond, + end_label: Label, + } + let mut cond_stack = Vec::>::new(); + for assignment_index in assignments_order { + let Assignment { + inputs: _, + outputs: _, + conditions, + insns, + source_location, + } = &self.assignments.assignments()[assignment_index]; + let mut same_len = 0; + for (index, (entry, cond)) in cond_stack.iter().zip(conditions).enumerate() { + if entry.cond != cond { + break; + } + same_len = index + 1; + } + while cond_stack.len() > same_len { + let CondStackEntry { cond: _, end_label } = + cond_stack.pop().expect("just checked len"); + self.insns.define_label_at_next_insn(end_label); + } + for cond in &conditions[cond_stack.len()..] { + let end_label = self.insns.new_label(); + match cond.body { + CondBody::IfTrue { cond: cond_value } + | CondBody::IfFalse { cond: cond_value } => { + let (branch_if_zero, branch_if_non_zero) = match cond_value.range.len() { + TypeLen::A_SMALL_SLOT => ( + Insn::BranchIfSmallZero { + target: end_label.0, + value: cond_value.range.small_slots.start, + }, + Insn::BranchIfSmallNonZero { + target: end_label.0, + value: cond_value.range.small_slots.start, + }, + ), + TypeLen::A_BIG_SLOT => ( + Insn::BranchIfZero { + target: end_label.0, + value: cond_value.range.big_slots.start, + }, + Insn::BranchIfNonZero { + target: end_label.0, + value: cond_value.range.big_slots.start, + }, + ), + _ => unreachable!(), + }; + self.insns.push( + if let CondBody::IfTrue { .. } = cond.body { + branch_if_zero + } else { + branch_if_non_zero + }, + cond.source_location, + ); + } + CondBody::MatchArm { + discriminant, + variant_index, + } => { + self.insns.push( + Insn::BranchIfSmallNeImmediate { + target: end_label.0, + lhs: discriminant, + rhs: variant_index as _, + }, + cond.source_location, + ); + } + } + cond_stack.push(CondStackEntry { cond, end_label }); + } + self.insns.extend(insns.iter().copied(), *source_location); + } + } + fn process_clocks(&mut self) -> Interned<[StatePartIndex]> { + mem::take(&mut self.clock_triggers) + .into_iter() + .map( + |ClockTrigger { + last_clk_was_low, + clk, + clk_triggered, + source_location, + }| { + self.insns.push( + Insn::XorSmallImmediate { + dest: last_clk_was_low, + lhs: clk, + rhs: 1, + }, + source_location, + ); + clk_triggered + }, + ) + .collect() + } + fn process_registers(&mut self) { + for Register { + value, + clk_triggered, + reset, + source_location, + } in mem::take(&mut self.registers) + { + match reset { + Some(RegisterReset { + is_async, + init, + rst, + }) => { + let reg_end = self.insns.new_label(); + let reg_reset = self.insns.new_label(); + let branch_if_reset = Insn::BranchIfSmallNonZero { + target: reg_reset.0, + value: rst, + }; + let branch_if_not_triggered = Insn::BranchIfSmallZero { + target: reg_end.0, + value: clk_triggered, + }; + if is_async { + self.insns.push(branch_if_reset, source_location); + self.insns.push(branch_if_not_triggered, source_location); + } else { + self.insns.push(branch_if_not_triggered, source_location); + self.insns.push(branch_if_reset, source_location); + } + self.insns.extend( + value.range.insns_for_copy_from(value.write_value().range), + source_location, + ); + self.insns + .push(Insn::Branch { target: reg_end.0 }, source_location); + self.insns.define_label_at_next_insn(reg_reset); + self.insns + .extend(value.range.insns_for_copy_from(init.range), source_location); + self.insns.define_label_at_next_insn(reg_end); + } + None => { + let reg_end = self.insns.new_label(); + self.insns.push( + Insn::BranchIfSmallZero { + target: reg_end.0, + value: clk_triggered, + }, + source_location, + ); + self.insns.extend( + value.range.insns_for_copy_from(value.write_value().range), + source_location, + ); + self.insns.define_label_at_next_insn(reg_end); + } + } + } + } + fn process_memories(&mut self) { + for memory_index in 0..self.memories.len() { + let Memory { + mem, + memory: _, + trace: _, + ref mut ports, + } = self.memories[memory_index]; + for MemoryPort { + clk_triggered, + addr_delayed, + en_delayed, + data_layout: _, + read_data_delayed, + write_data_delayed, + write_mask_delayed, + write_mode_delayed, + write_insns, + } in mem::take(ports) + { + let port_end = self.insns.new_label(); + let small_shift_reg = + |this: &mut Self, values: &[StatePartIndex]| { + for pair in values.windows(2).rev() { + this.insns.push( + Insn::CopySmall { + dest: pair[1], + src: pair[0], + }, + mem.source_location(), + ); + } + }; + let shift_reg = |this: &mut Self, values: &[TypeIndexRange]| { + for pair in values.windows(2).rev() { + this.insns + .extend(pair[0].insns_for_copy_to(pair[1]), mem.source_location()); + } + }; + self.insns.push( + Insn::BranchIfSmallZero { + target: port_end.0, + value: clk_triggered, + }, + mem.source_location(), + ); + small_shift_reg(self, &addr_delayed); + small_shift_reg(self, &en_delayed); + shift_reg(self, &write_data_delayed); + shift_reg(self, &write_mask_delayed); + small_shift_reg(self, &write_mode_delayed); + shift_reg(self, &read_data_delayed); + self.insns.extend(write_insns, mem.source_location()); + self.insns.define_label_at_next_insn(port_end); + } + } + } + pub fn compile(mut self) -> Compiled { + let base_module = + *self.compile_module(InstantiatedModule::Base(self.base_module).intern_sized()); + self.process_assignments(); + self.process_registers(); + self.process_memories(); + let clocks_triggered = self.process_clocks(); + self.insns + .push(Insn::Return, self.base_module.source_location()); + Compiled { + insns: Insns::from(self.insns).intern_sized(), + base_module, + io: Instance::new_unchecked( + ScopedNameId( + NameId("".intern(), Id::new()), + self.original_base_module.name_id(), + ), + self.original_base_module, + self.original_base_module.source_location(), + ), + traces: SimTraces(Intern::intern_owned(self.traces.0)), + trace_memories: Interned::from_iter(self.memories.iter().map( + |&Memory { + mem: _, + memory, + trace, + ports: _, + }| (memory, trace), + )), + clocks_triggered, + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +struct CompiledModule { + module_io: Interned<[CompiledValue]>, + trace_decls: TraceModule, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct Compiled { + insns: Interned>, + base_module: CompiledModule, + io: Instance, + traces: SimTraces]>>, + trace_memories: Interned<[(StatePartIndex, TraceMem)]>, + clocks_triggered: Interned<[StatePartIndex]>, +} + +impl Compiled { + pub fn new(module: Interned>) -> Self { + Self::from_canonical(Compiler::new(module.canonical().intern()).compile()) + } + pub fn canonical(self) -> Compiled { + let Self { + insns, + base_module, + io, + traces, + trace_memories, + clocks_triggered, + } = self; + Compiled { + insns, + base_module, + io: Instance::from_canonical(io.canonical()), + traces, + trace_memories, + clocks_triggered, + } + } + pub fn from_canonical(canonical: Compiled) -> Self { + let Compiled { + insns, + base_module, + io, + traces, + trace_memories, + clocks_triggered, + } = canonical; + Self { + insns, + base_module, + io: Instance::from_canonical(io.canonical()), + traces, + trace_memories, + clocks_triggered, + } + } +} + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct TraceScalarId(usize); @@ -264,7 +5203,7 @@ impl_trace_decl! { }), Instance(TraceInstance { fn children(self) -> _ { - [self.instance_io.into(), self.module.into()].intern_slice() + [self.instance_io.into(), self.module.into()][..].intern() } name: Interned, instance_io: TraceBundle, @@ -284,7 +5223,7 @@ impl_trace_decl! { }), MemPort(TraceMemPort { fn children(self) -> _ { - [self.bundle.into()].intern_slice() + [self.bundle.into()][..].intern() } name: Interned, bundle: TraceBundle, @@ -292,7 +5231,7 @@ impl_trace_decl! { }), Wire(TraceWire { fn children(self) -> _ { - [*self.child].intern_slice() + [*self.child][..].intern() } name: Interned, child: Interned, @@ -300,7 +5239,7 @@ impl_trace_decl! { }), Reg(TraceReg { fn children(self) -> _ { - [*self.child].intern_slice() + [*self.child][..].intern() } name: Interned, child: Interned, @@ -308,7 +5247,7 @@ impl_trace_decl! { }), ModuleIO(TraceModuleIO { fn children(self) -> _ { - [*self.child].intern_slice() + [*self.child][..].intern() } name: Interned, child: Interned, @@ -415,15 +5354,6 @@ impl_trace_decl! { name: Interned, flow: Flow, }), - SimOnly(TraceSimOnly { - fn location(self) -> _ { - self.location - } - location: TraceLocation, - name: Interned, - ty: DynSimOnly, - flow: Flow, - }), }), } @@ -525,11 +5455,6 @@ pub trait TraceWriter: fmt::Debug + 'static { variant_index: usize, ty: Enum, ) -> Result<(), Self::Error>; - fn set_signal_sim_only_value( - &mut self, - id: TraceScalarId, - value: &DynSimOnlyValue, - ) -> Result<(), Self::Error>; } pub struct DynTraceWriterDecls(Box); @@ -577,18 +5502,13 @@ trait TraceWriterDynTrait: fmt::Debug + 'static { fn set_signal_clock_dyn(&mut self, id: TraceScalarId, value: bool) -> std::io::Result<()>; fn set_signal_sync_reset_dyn(&mut self, id: TraceScalarId, value: bool) -> std::io::Result<()>; fn set_signal_async_reset_dyn(&mut self, id: TraceScalarId, value: bool) - -> std::io::Result<()>; + -> std::io::Result<()>; fn set_signal_enum_discriminant_dyn( &mut self, id: TraceScalarId, variant_index: usize, ty: Enum, ) -> std::io::Result<()>; - fn set_signal_sim_only_value_dyn( - &mut self, - id: TraceScalarId, - value: &DynSimOnlyValue, - ) -> std::io::Result<()>; } impl TraceWriterDynTrait for T { @@ -648,13 +5568,6 @@ impl TraceWriterDynTrait for T { .map_err(err_into_io)?, ) } - fn set_signal_sim_only_value_dyn( - &mut self, - id: TraceScalarId, - value: &DynSimOnlyValue, - ) -> std::io::Result<()> { - Ok(TraceWriter::set_signal_sim_only_value(self, id, value).map_err(err_into_io)?) - } } pub struct DynTraceWriter(Box); @@ -719,13 +5632,6 @@ impl TraceWriter for DynTraceWriter { self.0 .set_signal_enum_discriminant_dyn(id, variant_index, ty) } - fn set_signal_sim_only_value( - &mut self, - id: TraceScalarId, - value: &DynSimOnlyValue, - ) -> Result<(), Self::Error> { - self.0.set_signal_sim_only_value_dyn(id, value) - } } #[derive(Debug)] @@ -769,7 +5675,7 @@ where } } -impl SimTraceDebug for Box +impl SimTraceDebug for Box where T: SimTraceDebug, { @@ -793,15 +5699,15 @@ where } } -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub(crate) struct SimTrace { +#[derive(Clone, PartialEq, Eq, Hash)] +struct SimTrace { kind: K, state: S, last_state: S, } #[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub(crate) struct SimTraces(T); +struct SimTraces(T); impl fmt::Debug for SimTraces where @@ -828,7 +5734,7 @@ impl SimTraceDebug for SimTrace { } } -impl SimTraceDebug for SimTrace { +impl SimTraceDebug for SimTrace { fn fmt(&self, id: TraceScalarId, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { kind, @@ -838,14 +5744,14 @@ impl SimTraceDebug for SimTrace f.debug_struct("SimTrace") .field("id", &id) .field("kind", kind) - .field("state", state) - .field("last_state", last_state) + .field("state", &BitSliceWriteWithBase(state)) + .field("last_state", &BitSliceWriteWithBase(last_state)) .finish() } } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub(crate) enum SimTraceKind { +enum SimTraceKind { BigUInt { index: StatePartIndex, ty: UInt, @@ -890,83 +5796,16 @@ pub(crate) enum SimTraceKind { index: StatePartIndex, ty: Enum, }, - SimOnly { - index: StatePartIndex, - ty: DynSimOnly, - }, -} - -#[derive(PartialEq, Eq)] -pub(crate) enum SimTraceState { - Bits(BitVec), - SimOnly(DynSimOnlyValue), -} - -impl Clone for SimTraceState { - fn clone(&self) -> Self { - match self { - Self::Bits(v) => Self::Bits(v.clone()), - Self::SimOnly(v) => Self::SimOnly(v.clone()), - } - } - fn clone_from(&mut self, source: &Self) { - match (&mut *self, source) { - (SimTraceState::Bits(dest), SimTraceState::Bits(source)) => { - dest.clone_from_bitslice(source); - } - _ => *self = source.clone(), - } - } -} - -impl SimTraceState { - fn unwrap_bits_ref(&self) -> &BitVec { - if let SimTraceState::Bits(v) = self { - v - } else { - unreachable!() - } - } - fn unwrap_bits_mut(&mut self) -> &mut BitVec { - if let SimTraceState::Bits(v) = self { - v - } else { - unreachable!() - } - } - fn unwrap_sim_only_ref(&self) -> &DynSimOnlyValue { - if let SimTraceState::SimOnly(v) = self { - v - } else { - unreachable!() - } - } - fn unwrap_sim_only_mut(&mut self) -> &mut DynSimOnlyValue { - if let SimTraceState::SimOnly(v) = self { - v - } else { - unreachable!() - } - } -} - -impl fmt::Debug for SimTraceState { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SimTraceState::Bits(v) => BitSliceWriteWithBase(v).fmt(f), - SimTraceState::SimOnly(v) => v.fmt(f), - } - } } impl SimTraceKind { - fn make_state(self) -> SimTraceState { + fn make_state(self) -> BitVec { match self { SimTraceKind::BigUInt { index: _, ty } | SimTraceKind::SmallUInt { index: _, ty } => { - SimTraceState::Bits(BitVec::repeat(false, ty.width)) + BitVec::repeat(false, ty.width) } SimTraceKind::BigSInt { index: _, ty } | SimTraceKind::SmallSInt { index: _, ty } => { - SimTraceState::Bits(BitVec::repeat(false, ty.width)) + BitVec::repeat(false, ty.width) } SimTraceKind::BigBool { index: _ } | SimTraceKind::BigAsyncReset { index: _ } @@ -975,96 +5814,688 @@ impl SimTraceKind { | SimTraceKind::SmallBool { index: _ } | SimTraceKind::SmallAsyncReset { index: _ } | SimTraceKind::SmallSyncReset { index: _ } - | SimTraceKind::SmallClock { index: _ } => { - SimTraceState::Bits(BitVec::repeat(false, 1)) - } + | SimTraceKind::SmallClock { index: _ } => BitVec::repeat(false, 1), SimTraceKind::EnumDiscriminant { index: _, ty } => { - SimTraceState::Bits(BitVec::repeat(false, ty.discriminant_bit_width())) + BitVec::repeat(false, ty.discriminant_bit_width()) } - SimTraceKind::SimOnly { index: _, ty } => SimTraceState::SimOnly(ty.default_value()), } } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -enum MaybeNeedsSettle { - NeedsSettle(S), - NoSettleNeeded(N), +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct SimValue { + ty: T, + bits: BitVec, } -impl MaybeNeedsSettle { - fn map(self, f: impl FnOnce(T) -> U) -> MaybeNeedsSettle { - match self { - MaybeNeedsSettle::NeedsSettle(v) => MaybeNeedsSettle::NeedsSettle(f(v)), - MaybeNeedsSettle::NoSettleNeeded(v) => MaybeNeedsSettle::NoSettleNeeded(f(v)), +impl SimValue { + #[track_caller] + fn to_expr_impl(ty: CanonicalType, bits: &BitSlice) -> Expr { + match ty { + CanonicalType::UInt(_) => Expr::canonical(::bits_to_expr(Cow::Borrowed(bits))), + CanonicalType::SInt(_) => Expr::canonical(::bits_to_expr(Cow::Borrowed(bits))), + CanonicalType::Bool(_) => Expr::canonical(Bool::bits_to_expr(Cow::Borrowed(bits))), + CanonicalType::Array(ty) => { + let element_bit_width = ty.element().bit_width(); + Expr::::canonical( + crate::expr::ops::ArrayLiteral::new( + ty.element(), + (0..ty.len()) + .map(|array_index| { + let start = element_bit_width * array_index; + let end = start + element_bit_width; + Self::to_expr_impl(ty.element(), &bits[start..end]) + }) + .collect(), + ) + .to_expr(), + ) + } + CanonicalType::Enum(ty) => { + let discriminant_bit_width = ty.discriminant_bit_width(); + let mut variant_index = [0; mem::size_of::()]; + variant_index.view_bits_mut::()[0..discriminant_bit_width] + .clone_from_bitslice(&bits[..discriminant_bit_width]); + let variant_index = usize::from_le_bytes(variant_index); + if let Some(variant) = ty.variants().get(variant_index) { + let data_bit_width = variant.ty.map_or(0, CanonicalType::bit_width); + Expr::canonical( + crate::expr::ops::EnumLiteral::new_by_index( + ty, + variant_index, + variant.ty.map(|ty| { + Self::to_expr_impl( + ty, + &bits[discriminant_bit_width + ..discriminant_bit_width + data_bit_width], + ) + }), + ) + .to_expr(), + ) + } else { + Expr::canonical(::bits_to_expr(Cow::Borrowed(bits)).cast_bits_to(ty)) + } + } + CanonicalType::Bundle(ty) => Expr::canonical( + crate::expr::ops::BundleLiteral::new( + ty, + ty.fields() + .iter() + .zip(ty.field_offsets().iter()) + .map(|(field, &field_offset)| { + Self::to_expr_impl( + field.ty, + &bits[field_offset..field_offset + field.ty.bit_width()], + ) + }) + .collect(), + ) + .to_expr(), + ), + CanonicalType::AsyncReset(ty) => { + Expr::canonical(Bool::bits_to_expr(Cow::Borrowed(bits)).cast_to(ty)) + } + CanonicalType::SyncReset(ty) => { + Expr::canonical(Bool::bits_to_expr(Cow::Borrowed(bits)).cast_to(ty)) + } + CanonicalType::Reset(_) => panic!( + "can't convert SimValue to Expr -- \ + can't deduce whether reset value should be sync or async" + ), + CanonicalType::Clock(ty) => { + Expr::canonical(Bool::bits_to_expr(Cow::Borrowed(bits)).cast_to(ty)) + } } } } -// workaround implementing FnOnce not being stable -trait MaybeNeedsSettleFn { - type Output; +impl ToExpr for SimValue { + type Type = T; - fn call(self, arg: A) -> Self::Output; -} - -impl O, A, O> MaybeNeedsSettleFn for T { - type Output = O; - - fn call(self, arg: A) -> Self::Output { - self(arg) + #[track_caller] + fn to_expr(&self) -> Expr { + Expr::from_canonical(SimValue::to_expr_impl(self.ty.canonical(), &self.bits)) } } -impl MaybeNeedsSettle { - fn apply_no_settle(self, arg: T) -> MaybeNeedsSettle +impl ToSimValue for SimValue { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue { + assert_eq!(self.ty, ty); + self.clone() + } + + #[track_caller] + fn into_sim_value(self, ty: T) -> SimValue { + assert_eq!(self.ty, ty); + self + } + + #[track_caller] + fn box_into_sim_value(self: Box, ty: T) -> SimValue { + assert_eq!(self.ty, ty); + *self + } +} + +impl ToSimValue for BitVec { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue { + self.clone().into_sim_value(ty) + } + + #[track_caller] + fn into_sim_value(self, ty: T) -> SimValue { + assert_eq!(ty.canonical().bit_width(), self.len()); + SimValue { ty, bits: self } + } + + #[track_caller] + fn box_into_sim_value(self: Box, ty: T) -> SimValue { + Self::into_sim_value(*self, ty) + } +} + +impl ToSimValue for bitvec::boxed::BitBox { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue { + self.clone().into_sim_value(ty) + } + + #[track_caller] + fn into_sim_value(self, ty: T) -> SimValue { + assert_eq!(ty.canonical().bit_width(), self.len()); + SimValue { + ty, + bits: self.into_bitvec(), + } + } + + #[track_caller] + fn box_into_sim_value(self: Box, ty: T) -> SimValue { + Self::into_sim_value(*self, ty) + } +} + +impl ToSimValue for BitSlice { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue { + assert_eq!(ty.canonical().bit_width(), self.len()); + SimValue { + ty, + bits: self.to_bitvec(), + } + } +} + +impl SimValue { + pub fn ty(&self) -> T { + self.ty + } + pub fn bits(&self) -> &BitSlice { + &self.bits + } + pub fn into_bits(self) -> BitVec { + self.bits + } + #[track_caller] + pub fn from_canonical(v: SimValue) -> Self { + Self { + ty: T::from_canonical(v.ty), + bits: v.bits, + } + } + pub fn into_canonical(self) -> SimValue { + SimValue { + ty: self.ty.canonical(), + bits: self.bits, + } + } + #[track_caller] + pub fn from_dyn_int(v: SimValue) -> Self where - N: MaybeNeedsSettleFn, + T: IntType, { - match self { - MaybeNeedsSettle::NeedsSettle(v) => MaybeNeedsSettle::NeedsSettle(v), - MaybeNeedsSettle::NoSettleNeeded(v) => MaybeNeedsSettle::NoSettleNeeded(v.call(arg)), + Self { + ty: T::from_dyn_int(v.ty), + bits: v.bits, + } + } + pub fn into_dyn_int(self) -> SimValue + where + T: IntType, + { + SimValue { + ty: self.ty.as_dyn_int(), + bits: self.bits, + } + } + #[track_caller] + pub fn from_bundle(v: SimValue) -> Self + where + T: BundleType, + { + Self { + ty: T::from_canonical(CanonicalType::Bundle(v.ty)), + bits: v.bits, + } + } + pub fn into_bundle(self) -> SimValue + where + T: BundleType, + { + SimValue { + ty: Bundle::from_canonical(self.ty.canonical()), + bits: self.bits, + } + } + #[track_caller] + pub fn from_enum(v: SimValue) -> Self + where + T: EnumType, + { + Self { + ty: T::from_canonical(CanonicalType::Enum(v.ty)), + bits: v.bits, + } + } + pub fn into_enum(self) -> SimValue + where + T: EnumType, + { + SimValue { + ty: Enum::from_canonical(self.ty.canonical()), + bits: self.bits, } } } -struct SimulationModuleState { - base_targets: Vec, - uninitialized_ios: HashMap>, - io_targets: HashMap>, - did_initial_settle: bool, -} - -impl fmt::Debug for SimulationModuleState { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - base_targets, - uninitialized_ios, - io_targets, - did_initial_settle, - } = self; - f.debug_struct("SimulationModuleState") - .field("base_targets", base_targets) - .field("uninitialized_ios", &SortedSetDebug(uninitialized_ios)) - .field("io_targets", &SortedSetDebug(io_targets)) - .field("did_initial_settle", did_initial_settle) - .finish() +pub trait ToSimValue { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue; + #[track_caller] + fn into_sim_value(self, ty: T) -> SimValue + where + Self: Sized, + { + self.to_sim_value(ty) + } + #[track_caller] + fn box_into_sim_value(self: Box, ty: T) -> SimValue { + self.to_sim_value(ty) } } -impl SimulationModuleState { - fn new(base_targets: impl IntoIterator)>) -> Self { - let mut retval = Self { - base_targets: Vec::new(), - uninitialized_ios: HashMap::default(), - io_targets: HashMap::default(), - did_initial_settle: false, +impl, T: Type> ToSimValue for &'_ This { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue { + This::to_sim_value(self, ty) + } +} + +impl, T: Type> ToSimValue for &'_ mut This { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue { + This::to_sim_value(self, ty) + } +} + +impl, T: Type> ToSimValue for Box { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue { + This::to_sim_value(self, ty) + } + #[track_caller] + fn into_sim_value(self, ty: T) -> SimValue { + This::box_into_sim_value(self, ty) + } + #[track_caller] + fn box_into_sim_value(self: Box, ty: T) -> SimValue { + This::box_into_sim_value(*self, ty) + } +} + +impl + Send + Sync + 'static, T: Type> ToSimValue + for Interned +{ + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue { + This::to_sim_value(self, ty) + } +} + +impl SimValue> { + #[track_caller] + pub fn from_array_elements< + I: IntoIterator, IntoIter: ExactSizeIterator>, + >( + elements: I, + ty: ArrayType, + ) -> Self { + let mut iter = elements.into_iter(); + assert_eq!(iter.len(), ty.len()); + let Some(first) = iter.next() else { + return SimValue { + ty, + bits: BitVec::new(), + }; }; - for (base_target, value) in base_targets { - retval.base_targets.push(base_target); - retval.parse_io(base_target, value); + let SimValue { + ty: element_ty, + mut bits, + } = first.into_sim_value(ty.element()); + assert_eq!(element_ty, ty.element()); + bits.reserve(ty.type_properties().bit_width - bits.len()); + for element in iter { + let SimValue { + ty: element_ty, + bits: element_bits, + } = element.into_sim_value(ty.element()); + assert_eq!(element_ty, ty.element()); + bits.extend_from_bitslice(&element_bits); } - retval + SimValue { ty, bits } + } +} + +impl, T: Type> ToSimValue> for [Element] { + #[track_caller] + fn to_sim_value(&self, ty: Array) -> SimValue> { + SimValue::from_array_elements(self, ty) + } + #[track_caller] + fn box_into_sim_value(self: Box, ty: Array) -> SimValue> { + SimValue::from_array_elements(self, ty) + } +} + +impl> ToSimValue for [Element] { + #[track_caller] + fn to_sim_value(&self, ty: CanonicalType) -> SimValue { + SimValue::from_array_elements(self, ::from_canonical(ty)).into_canonical() + } + #[track_caller] + fn box_into_sim_value(self: Box, ty: CanonicalType) -> SimValue { + SimValue::from_array_elements(self, ::from_canonical(ty)).into_canonical() + } +} + +impl, T: Type, const N: usize> ToSimValue> for [Element; N] +where + ConstUsize: KnownSize, +{ + #[track_caller] + fn to_sim_value(&self, ty: Array) -> SimValue> { + SimValue::from_array_elements(self, ty) + } + #[track_caller] + fn into_sim_value(self, ty: Array) -> SimValue> { + SimValue::from_array_elements(self, ty) + } + #[track_caller] + fn box_into_sim_value(self: Box, ty: Array) -> SimValue> { + SimValue::from_array_elements( as From>>::from(self), ty) + } +} + +impl, T: Type, const N: usize> ToSimValue> for [Element; N] +where + ConstUsize: KnownSize, +{ + #[track_caller] + fn to_sim_value(&self, ty: Array) -> SimValue> { + SimValue::from_array_elements(self, ty) + } + #[track_caller] + fn into_sim_value(self, ty: Array) -> SimValue> { + SimValue::from_array_elements(self, ty) + } + #[track_caller] + fn box_into_sim_value(self: Box, ty: Array) -> SimValue> { + SimValue::from_array_elements( as From>>::from(self), ty) + } +} + +impl, const N: usize> ToSimValue + for [Element; N] +{ + #[track_caller] + fn to_sim_value(&self, ty: CanonicalType) -> SimValue { + SimValue::from_array_elements(self, ::from_canonical(ty)).into_canonical() + } + #[track_caller] + fn into_sim_value(self, ty: CanonicalType) -> SimValue { + SimValue::from_array_elements(self, ::from_canonical(ty)).into_canonical() + } + #[track_caller] + fn box_into_sim_value(self: Box, ty: CanonicalType) -> SimValue { + SimValue::from_array_elements( + as From>>::from(self), + ::from_canonical(ty), + ) + .into_canonical() + } +} + +impl, T: Type> ToSimValue> for Vec { + #[track_caller] + fn to_sim_value(&self, ty: Array) -> SimValue> { + SimValue::from_array_elements(self, ty) + } + #[track_caller] + fn into_sim_value(self, ty: Array) -> SimValue> { + SimValue::from_array_elements(self, ty) + } + #[track_caller] + fn box_into_sim_value(self: Box, ty: Array) -> SimValue> { + SimValue::from_array_elements(*self, ty) + } +} + +impl> ToSimValue for Vec { + #[track_caller] + fn to_sim_value(&self, ty: CanonicalType) -> SimValue { + SimValue::from_array_elements(self, ::from_canonical(ty)).into_canonical() + } + #[track_caller] + fn into_sim_value(self, ty: CanonicalType) -> SimValue { + SimValue::from_array_elements(self, ::from_canonical(ty)).into_canonical() + } + #[track_caller] + fn box_into_sim_value(self: Box, ty: CanonicalType) -> SimValue { + SimValue::from_array_elements(*self, ::from_canonical(ty)).into_canonical() + } +} + +impl ToSimValue for Expr { + #[track_caller] + fn to_sim_value(&self, ty: T) -> SimValue { + assert_eq!(Expr::ty(*self), ty); + SimValue { + ty, + bits: self + .to_literal_bits() + .expect("must be a literal expression") + .to_bitvec(), + } + } +} + +macro_rules! impl_to_sim_value_for_bool_like { + ($ty:ident) => { + impl ToSimValue<$ty> for bool { + fn to_sim_value(&self, ty: $ty) -> SimValue<$ty> { + SimValue { + ty, + bits: BitVec::repeat(*self, 1), + } + } + } + }; +} + +impl_to_sim_value_for_bool_like!(Bool); +impl_to_sim_value_for_bool_like!(AsyncReset); +impl_to_sim_value_for_bool_like!(SyncReset); +impl_to_sim_value_for_bool_like!(Reset); +impl_to_sim_value_for_bool_like!(Clock); + +impl ToSimValue for bool { + #[track_caller] + fn to_sim_value(&self, ty: CanonicalType) -> SimValue { + match ty { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Array(_) + | CanonicalType::Enum(_) + | CanonicalType::Bundle(_) => { + panic!("can't create SimValue from bool: expected value of type: {ty:?}"); + } + CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) => SimValue { + ty, + bits: BitVec::repeat(*self, 1), + }, + } + } +} + +macro_rules! impl_to_sim_value_for_primitive_int { + ($prim:ident) => { + impl ToSimValue<<$prim as ToExpr>::Type> for $prim { + #[track_caller] + fn to_sim_value( + &self, + ty: <$prim as ToExpr>::Type, + ) -> SimValue<<$prim as ToExpr>::Type> { + SimValue { + ty, + bits: <<$prim as ToExpr>::Type as BoolOrIntType>::le_bytes_to_bits_wrapping( + &self.to_le_bytes(), + ty.width(), + ), + } + } + } + + impl ToSimValue<<<$prim as ToExpr>::Type as IntType>::Dyn> for $prim { + #[track_caller] + fn to_sim_value( + &self, + ty: <<$prim as ToExpr>::Type as IntType>::Dyn, + ) -> SimValue<<<$prim as ToExpr>::Type as IntType>::Dyn> { + SimValue { + ty, + bits: <<$prim as ToExpr>::Type as BoolOrIntType>::le_bytes_to_bits_wrapping( + &self.to_le_bytes(), + ty.width(), + ), + } + } + } + + impl ToSimValue for $prim { + #[track_caller] + fn to_sim_value(&self, ty: CanonicalType) -> SimValue { + let ty: <<$prim as ToExpr>::Type as IntType>::Dyn = Type::from_canonical(ty); + self.to_sim_value(ty).into_canonical() + } + } + }; +} + +impl_to_sim_value_for_primitive_int!(u8); +impl_to_sim_value_for_primitive_int!(u16); +impl_to_sim_value_for_primitive_int!(u32); +impl_to_sim_value_for_primitive_int!(u64); +impl_to_sim_value_for_primitive_int!(u128); +impl_to_sim_value_for_primitive_int!(usize); +impl_to_sim_value_for_primitive_int!(i8); +impl_to_sim_value_for_primitive_int!(i16); +impl_to_sim_value_for_primitive_int!(i32); +impl_to_sim_value_for_primitive_int!(i64); +impl_to_sim_value_for_primitive_int!(i128); +impl_to_sim_value_for_primitive_int!(isize); + +macro_rules! impl_to_sim_value_for_int_value { + ($IntValue:ident, $Int:ident, $IntType:ident) => { + impl ToSimValue<$IntType> for $IntValue { + fn to_sim_value(&self, ty: $IntType) -> SimValue<$IntType> { + self.bits().to_bitvec().into_sim_value(ty) + } + + fn into_sim_value(self, ty: $IntType) -> SimValue<$IntType> { + Arc::try_unwrap(self.into_bits()) + .unwrap_or_else(|v: Arc| v.to_bitvec()) + .into_sim_value(ty) + } + + fn box_into_sim_value( + self: Box, + ty: $IntType, + ) -> SimValue<$IntType> { + Self::into_sim_value(*self, ty) + } + } + + impl ToSimValue<$Int> for $IntValue { + fn to_sim_value(&self, ty: $Int) -> SimValue<$Int> { + self.bits().to_bitvec().into_sim_value(ty) + } + + fn into_sim_value(self, ty: $Int) -> SimValue<$Int> { + Arc::try_unwrap(self.into_bits()) + .unwrap_or_else(|v: Arc| v.to_bitvec()) + .into_sim_value(ty) + } + + fn box_into_sim_value(self: Box, ty: $Int) -> SimValue<$Int> { + Self::into_sim_value(*self, ty) + } + } + + impl ToSimValue for $IntValue { + #[track_caller] + fn to_sim_value(&self, ty: CanonicalType) -> SimValue { + ToSimValue::<$Int>::to_sim_value(self, $Int::from_canonical(ty)).into_canonical() + } + + #[track_caller] + fn into_sim_value(self, ty: CanonicalType) -> SimValue { + ToSimValue::<$Int>::into_sim_value(self, $Int::from_canonical(ty)).into_canonical() + } + + #[track_caller] + fn box_into_sim_value(self: Box, ty: CanonicalType) -> SimValue { + Self::into_sim_value(*self, ty) + } + } + }; +} + +impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType); +impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType); + +struct SimulationImpl { + state: interpreter::State, + io: Expr, + uninitialized_inputs: HashMap>, + io_targets: HashMap>, + made_initial_step: bool, + needs_settle: bool, + trace_decls: TraceModule, + traces: SimTraces]>>, + trace_memories: HashMap, TraceMem>, + trace_writers: Vec>, + instant: SimInstant, + clocks_triggered: Interned<[StatePartIndex]>, + breakpoints: Option, +} + +impl fmt::Debug for SimulationImpl { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.debug_fmt(None, f) + } +} + +impl SimulationImpl { + fn debug_fmt(&self, io: Option<&dyn fmt::Debug>, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + state, + io: self_io, + uninitialized_inputs, + io_targets, + made_initial_step, + needs_settle, + trace_decls, + traces, + trace_memories, + trace_writers, + instant, + clocks_triggered, + breakpoints: _, + } = self; + f.debug_struct("Simulation") + .field("state", state) + .field("io", io.unwrap_or(self_io)) + .field( + "uninitialized_inputs", + &SortedSetDebug(uninitialized_inputs), + ) + .field("io_targets", &SortedMapDebug(io_targets)) + .field("made_initial_step", made_initial_step) + .field("needs_settle", needs_settle) + .field("trace_decls", trace_decls) + .field("traces", traces) + .field("trace_memories", trace_memories) + .field("trace_writers", trace_writers) + .field("instant", instant) + .field("clocks_triggered", clocks_triggered) + .finish_non_exhaustive() } /// returns `true` if `target` or any sub-targets are uninitialized inputs fn parse_io(&mut self, target: Target, value: CompiledValue) -> bool { @@ -1073,7 +6504,7 @@ impl SimulationModuleState { CompiledTypeLayoutBody::Scalar => match target.flow() { Flow::Source => false, Flow::Sink => { - self.uninitialized_ios.insert(target, vec![]); + self.uninitialized_inputs.insert(target, vec![]); true } Flow::Duplex => unreachable!(), @@ -1092,7 +6523,7 @@ impl SimulationModuleState { if sub_targets.is_empty() { false } else { - self.uninitialized_ios.insert(target, sub_targets); + self.uninitialized_inputs.insert(target, sub_targets); true } } @@ -1110,506 +6541,20 @@ impl SimulationModuleState { if sub_targets.is_empty() { false } else { - self.uninitialized_ios.insert(target, sub_targets); + self.uninitialized_inputs.insert(target, sub_targets); true } } } } - fn mark_target_as_initialized(&mut self, mut target: Target) { - fn remove_target_and_children( - uninitialized_ios: &mut HashMap>, - target: Target, - ) { - let Some(children) = uninitialized_ios.remove(&target) else { - return; - }; - for child in children { - remove_target_and_children(uninitialized_ios, child); - } - } - remove_target_and_children(&mut self.uninitialized_ios, target); - while let Some(target_child) = target.child() { - let parent = target_child.parent(); - for child in self - .uninitialized_ios - .get(&*parent) - .map(|v| &**v) - .unwrap_or(&[]) - { - if self.uninitialized_ios.contains_key(child) { - return; - } - } - target = *parent; - self.uninitialized_ios.remove(&target); - } - } - #[track_caller] - fn get_io( - &self, - mut target: Target, - which_module: WhichModule, - ) -> CompiledValue { - assert!( - target.canonical_ty().is_passive(), - "simulator read/write expression must have a passive type \ - (recursively contains no fields with `#[hdl(flip)]`)" - ); - if let Some(&retval) = self.io_targets.get(&target) { - return retval; - } - loop { - target = match target { - Target::Base(_) => break, - Target::Child(child) => { - match *child.path_element() { - TargetPathElement::BundleField(_) | TargetPathElement::ArrayElement(_) => {} - TargetPathElement::DynArrayElement(_) => panic!( - "simulator read/write expression must not have dynamic array indexes" - ), - } - *child.parent() - } - }; - } - match which_module { - WhichModule::Main => panic!( - "simulator read/write expression must be \ - an array element/field of `Simulation::io()`" - ), - WhichModule::Extern { .. } => panic!( - "simulator read/write expression must be \ - one of this module's inputs/outputs or an \ - array element/field of one of this module's inputs/outputs" - ), - } - } - #[track_caller] - fn read_helper( - &self, - io: Expr, - which_module: WhichModule, - ) -> MaybeNeedsSettle> { - let Some(target) = io.target() else { - match which_module { - WhichModule::Main => panic!( - "can't read from an expression that's not a field/element of `Simulation::io()`" - ), - WhichModule::Extern { .. } => panic!( - "can't read from an expression that's not based on one of this module's inputs/outputs" - ), - } - }; - let compiled_value = self.get_io(*target, which_module); - match target.flow() { - Flow::Source => { - if !self.uninitialized_ios.is_empty() { - match which_module { - WhichModule::Main => { - panic!("can't read from an output before initializing all inputs"); - } - WhichModule::Extern { .. } => { - panic!("can't read from an input before initializing all outputs"); - } - } - } - MaybeNeedsSettle::NeedsSettle(compiled_value) - } - Flow::Sink => { - if self.uninitialized_ios.contains_key(&*target) { - match which_module { - WhichModule::Main => panic!("can't read from an uninitialized input"), - WhichModule::Extern { .. } => { - panic!("can't read from an uninitialized output"); - } - } - } - MaybeNeedsSettle::NoSettleNeeded(compiled_value) - } - Flow::Duplex => unreachable!(), - } - } - #[track_caller] - fn write_helper( - &mut self, - io: Expr, - which_module: WhichModule, - ) -> CompiledValue { - let Some(target) = io.target() else { - match which_module { - WhichModule::Main => panic!( - "can't write to an expression that's not a field/element of `Simulation::io()`" - ), - WhichModule::Extern { .. } => panic!( - "can't write to an expression that's not based on one of this module's outputs" - ), - } - }; - let compiled_value = self.get_io(*target, which_module); - match target.flow() { - Flow::Source => match which_module { - WhichModule::Main => panic!("can't write to an output"), - WhichModule::Extern { .. } => panic!("can't write to an input"), - }, - Flow::Sink => {} - Flow::Duplex => unreachable!(), - } - if !self.did_initial_settle { - self.mark_target_as_initialized(*target); - } - compiled_value - } -} - -#[derive(Copy, Clone, Debug)] -enum WaitTarget { - Settle, - Instant(SimInstant), - Change { key: ChangeKey, value: ChangeValue }, -} - -#[derive(Clone)] -struct EarliestWaitTargets { - settle: bool, - instant: Option, - changes: HashMap, SimValue>, -} - -impl fmt::Debug for EarliestWaitTargets { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_set().entries(self.iter()).finish() - } -} - -impl Default for EarliestWaitTargets { - fn default() -> Self { - Self { - settle: false, - instant: None, - changes: HashMap::default(), - } - } -} - -impl EarliestWaitTargets { - fn settle() -> Self { - Self { - settle: true, - instant: None, - changes: HashMap::default(), - } - } - fn instant(instant: SimInstant) -> Self { - Self { - settle: false, - instant: Some(instant), - changes: HashMap::default(), - } - } - fn len(&self) -> usize { - self.settle as usize + self.instant.is_some() as usize + self.changes.len() - } - fn is_empty(&self) -> bool { - self.len() == 0 - } - fn clear(&mut self) { - let Self { - settle, - instant, - changes, - } = self; - *settle = false; - *instant = None; - changes.clear(); - } - fn insert( - &mut self, - value: impl std::borrow::Borrow, ChangeValue>>, - ) where - ChangeValue: std::borrow::Borrow>, - { - let value = value.borrow(); - match value { - WaitTarget::Settle => self.settle = true, - WaitTarget::Instant(instant) => { - if self.instant.is_none_or(|v| v > *instant) { - self.instant = Some(*instant); - } - } - WaitTarget::Change { key, value } => { - self.changes - .entry(*key) - .or_insert_with(|| value.borrow().clone()); - } - } - } - fn convert_earlier_instants_to_settle(&mut self, instant: SimInstant) { - if self.instant.is_some_and(|v| v <= instant) { - self.settle = true; - self.instant = None; - } - } - fn iter<'a>( - &'a self, - ) -> impl Clone - + Iterator, &'a SimValue>> - + 'a { - self.settle - .then_some(WaitTarget::Settle) - .into_iter() - .chain(self.instant.map(|instant| WaitTarget::Instant(instant))) - .chain( - self.changes - .iter() - .map(|(&key, value)| WaitTarget::Change { key, value }), - ) - } -} - -impl>> - Extend, ChangeValue>> for EarliestWaitTargets -{ - fn extend, ChangeValue>>>( - &mut self, - iter: T, - ) { - iter.into_iter().for_each(|v| self.insert(v)) - } -} - -impl<'a, ChangeValue: std::borrow::Borrow>> - Extend<&'a WaitTarget, ChangeValue>> for EarliestWaitTargets -{ - fn extend, ChangeValue>>>( - &mut self, - iter: T, - ) { - iter.into_iter().for_each(|v| self.insert(v)) - } -} - -impl FromIterator for EarliestWaitTargets -where - Self: Extend, -{ - fn from_iter>(iter: T) -> Self { - let mut retval = Self::default(); - retval.extend(iter); - retval - } -} - -struct SimulationExternModuleState { - module_state: SimulationModuleState, - sim: ExternModuleSimulation, - running_generator: Option + 'static>>>, - wait_targets: EarliestWaitTargets, -} - -impl fmt::Debug for SimulationExternModuleState { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - module_state, - sim, - running_generator, - wait_targets, - } = self; - f.debug_struct("SimulationExternModuleState") - .field("module_state", module_state) - .field("sim", sim) - .field( - "running_generator", - &running_generator.as_ref().map(|_| DebugAsDisplay("...")), - ) - .field("wait_targets", wait_targets) - .finish() - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -enum WhichModule { - Main, - Extern { module_index: usize }, -} - -struct ReadBitFn { - compiled_value: CompiledValue, -} - -impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadBitFn { - type Output = bool; - - fn call(self, state: &mut interpreter::State) -> Self::Output { - match self.compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => { - state.small_slots[self.compiled_value.range.small_slots.start] != 0 - } - Some(TypeLenSingle::BigSlot) => !state.big_slots - [self.compiled_value.range.big_slots.start] - .clone() - .is_zero(), - Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(), - } - } -} - -struct ReadBoolOrIntFn { - compiled_value: CompiledValue, - io: Expr, -} - -impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadBoolOrIntFn { - type Output = I::Value; - - fn call(self, state: &mut interpreter::State) -> Self::Output { - let Self { compiled_value, io } = self; - match compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => Expr::ty(io) - .value_from_int_wrapping(state.small_slots[compiled_value.range.small_slots.start]), - Some(TypeLenSingle::BigSlot) => Expr::ty(io).value_from_int_wrapping( - state.big_slots[compiled_value.range.big_slots.start].clone(), - ), - Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(), - } - } -} - -struct ReadFn { - compiled_value: CompiledValue, - io: Expr, -} - -impl MaybeNeedsSettleFn<&'_ mut interpreter::State> for ReadFn { - type Output = SimValue; - - fn call(self, state: &mut interpreter::State) -> Self::Output { - let Self { compiled_value, io } = self; - SimulationImpl::read_no_settle_helper(state, io, compiled_value) - } -} - -struct GeneratorWaker; - -impl std::task::Wake for GeneratorWaker { - fn wake(self: Arc) { - panic!("can't await other kinds of futures in function passed to ExternalModuleSimulation"); - } -} - -#[derive(Default)] -struct ReadyToRunSet { - state_ready_to_run: bool, - extern_modules_ready_to_run: Vec, -} - -impl ReadyToRunSet { - fn clear(&mut self) { - let Self { - state_ready_to_run, - extern_modules_ready_to_run, - } = self; - *state_ready_to_run = false; - extern_modules_ready_to_run.clear(); - } -} - -struct SimulationImpl { - state: interpreter::State, - io: Expr, - main_module: SimulationModuleState, - extern_modules: Box<[SimulationExternModuleState]>, - state_ready_to_run: bool, - trace_decls: TraceModule, - traces: SimTraces]>>, - trace_memories: BTreeMap, TraceMem>, - trace_writers: Vec>, - instant: SimInstant, - clocks_triggered: Interned<[StatePartIndex]>, - breakpoints: Option, - generator_waker: std::task::Waker, -} - -impl fmt::Debug for SimulationImpl { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.debug_fmt(None, f) - } -} - -impl SimulationImpl { - fn debug_fmt(&self, io: Option<&dyn fmt::Debug>, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - state, - io: self_io, - main_module, - extern_modules, - state_ready_to_run, - trace_decls, - traces, - trace_memories, - trace_writers, - instant, - clocks_triggered, - breakpoints: _, - generator_waker: _, - } = self; - f.debug_struct("Simulation") - .field("state", state) - .field("io", io.unwrap_or(self_io)) - .field("main_module", main_module) - .field("extern_modules", extern_modules) - .field("state_ready_to_run", state_ready_to_run) - .field("trace_decls", trace_decls) - .field("traces", traces) - .field("trace_memories", trace_memories) - .field("trace_writers", trace_writers) - .field("instant", instant) - .field("clocks_triggered", clocks_triggered) - .finish_non_exhaustive() - } fn new(compiled: Compiled) -> Self { - let io_target = Target::from(compiled.io); - let extern_modules = Box::from_iter(compiled.extern_modules.iter().map( - |&CompiledExternModule { - module_io_targets, - module_io, - simulation, - }| { - SimulationExternModuleState { - module_state: SimulationModuleState::new( - module_io_targets - .iter() - .copied() - .zip(module_io.iter().copied()), - ), - sim: simulation, - running_generator: None, - wait_targets: EarliestWaitTargets::settle(), - } - }, - )); - Self { + let mut retval = Self { state: State::new(compiled.insns), io: compiled.io.to_expr(), - main_module: SimulationModuleState::new( - compiled - .io - .ty() - .fields() - .into_iter() - .zip(compiled.base_module.module_io) - .map(|(BundleField { name, .. }, value)| { - ( - io_target.join( - TargetPathElement::from(TargetPathBundleField { name }) - .intern_sized(), - ), - value, - ) - }), - ), - extern_modules, - state_ready_to_run: true, + uninitialized_inputs: HashMap::new(), + io_targets: HashMap::new(), + made_initial_step: false, + needs_settle: true, trace_decls: compiled.base_module.trace_decls, traces: SimTraces(Box::from_iter(compiled.traces.0.iter().map( |&SimTrace { @@ -1622,13 +6567,27 @@ impl SimulationImpl { last_state: kind.make_state(), }, ))), - trace_memories: BTreeMap::from_iter(compiled.trace_memories.iter().copied()), + trace_memories: HashMap::from_iter(compiled.trace_memories.iter().copied()), trace_writers: vec![], instant: SimInstant::START, clocks_triggered: compiled.clocks_triggered, breakpoints: None, - generator_waker: Arc::new(GeneratorWaker).into(), + }; + let io_target = Target::from(compiled.io); + for (BundleField { name, .. }, value) in compiled + .io + .ty() + .fields() + .into_iter() + .zip(compiled.base_module.module_io) + { + retval.parse_io( + io_target + .join(TargetPathElement::from(TargetPathBundleField { name }).intern_sized()), + value, + ); } + retval } fn write_traces( &mut self, @@ -1671,25 +6630,24 @@ impl SimulationImpl { let id = TraceScalarId(id); match kind { SimTraceKind::BigUInt { .. } | SimTraceKind::SmallUInt { .. } => { - trace_writer.set_signal_uint(id, state.unwrap_bits_ref())?; + trace_writer.set_signal_uint(id, state)?; } SimTraceKind::BigSInt { .. } | SimTraceKind::SmallSInt { .. } => { - trace_writer.set_signal_sint(id, state.unwrap_bits_ref())?; + trace_writer.set_signal_sint(id, state)?; } SimTraceKind::BigBool { .. } | SimTraceKind::SmallBool { .. } => { - trace_writer.set_signal_bool(id, state.unwrap_bits_ref()[0])?; + trace_writer.set_signal_bool(id, state[0])?; } SimTraceKind::BigAsyncReset { .. } | SimTraceKind::SmallAsyncReset { .. } => { - trace_writer.set_signal_async_reset(id, state.unwrap_bits_ref()[0])?; + trace_writer.set_signal_async_reset(id, state[0])?; } SimTraceKind::BigSyncReset { .. } | SimTraceKind::SmallSyncReset { .. } => { - trace_writer.set_signal_sync_reset(id, state.unwrap_bits_ref()[0])?; + trace_writer.set_signal_sync_reset(id, state[0])?; } SimTraceKind::BigClock { .. } | SimTraceKind::SmallClock { .. } => { - trace_writer.set_signal_clock(id, state.unwrap_bits_ref()[0])?; + trace_writer.set_signal_clock(id, state[0])?; } SimTraceKind::EnumDiscriminant { ty, .. } => { - let state = state.unwrap_bits_ref(); let mut variant_index = [0; mem::size_of::()]; variant_index.view_bits_mut::()[0..state.len()] .clone_from_bitslice(state); @@ -1699,9 +6657,6 @@ impl SimulationImpl { ty, )?; } - SimTraceKind::SimOnly { .. } => { - trace_writer.set_signal_sim_only_value(id, state.unwrap_sim_only_ref())? - } } } Ok(trace_writer) @@ -1733,7 +6688,6 @@ impl SimulationImpl { } match kind { SimTraceKind::BigUInt { index, ty: _ } | SimTraceKind::BigSInt { index, ty: _ } => { - let state = state.unwrap_bits_mut(); let bigint = &self.state.big_slots[index]; let mut bytes = bigint.to_signed_bytes_le(); bytes.resize( @@ -1748,14 +6702,11 @@ impl SimulationImpl { | SimTraceKind::BigAsyncReset { index } | SimTraceKind::BigSyncReset { index } | SimTraceKind::BigClock { index } => { - state - .unwrap_bits_mut() - .set(0, !self.state.big_slots[index].is_zero()); + state.set(0, !self.state.big_slots[index].is_zero()); } SimTraceKind::SmallUInt { index, ty: _ } | SimTraceKind::SmallSInt { index, ty: _ } | SimTraceKind::EnumDiscriminant { index, ty: _ } => { - let state = state.unwrap_bits_mut(); let bytes = self.state.small_slots[index].to_le_bytes(); let bitslice = BitSlice::::from_slice(&bytes); let bitslice = &bitslice[..state.len()]; @@ -1765,139 +6716,18 @@ impl SimulationImpl { | SimTraceKind::SmallAsyncReset { index } | SimTraceKind::SmallSyncReset { index } | SimTraceKind::SmallClock { index } => { - state - .unwrap_bits_mut() - .set(0, self.state.small_slots[index] != 0); - } - SimTraceKind::SimOnly { index, ty: _ } => { - state - .unwrap_sim_only_mut() - .clone_from(&self.state.sim_only_slots[index]); + state.set(0, self.state.small_slots[index] != 0); } } if IS_INITIAL_STEP { - last_state.clone_from(state); + last_state.copy_from_bitslice(state); } } } #[track_caller] - fn advance_time(this_ref: &Rc>, duration: SimDuration) { - let run_target = this_ref.borrow().instant + duration; - Self::run_until(this_ref, run_target); - } - /// clears `targets` - #[must_use] - fn yield_wait<'a>( - this: Rc>, - module_index: usize, - targets: &'a mut EarliestWaitTargets, - ) -> impl Future + 'a { - struct MyGenerator<'a> { - sim: Rc>, - yielded_at_all: bool, - module_index: usize, - targets: &'a mut EarliestWaitTargets, - } - impl Future for MyGenerator<'_> { - type Output = (); - - fn poll( - mut self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> Poll { - let this = &mut *self; - let mut sim = this.sim.borrow_mut(); - let sim = &mut *sim; - assert!( - cx.waker().will_wake(&sim.generator_waker), - "can't use ExternModuleSimulationState's methods outside of ExternModuleSimulation" - ); - this.targets.convert_earlier_instants_to_settle(sim.instant); - if this.targets.is_empty() { - this.targets.settle = true; - } - if this.targets.settle { - if this.yielded_at_all { - this.targets.clear(); - return Poll::Ready(()); - } - } - sim.extern_modules[this.module_index] - .wait_targets - .extend(this.targets.iter()); - this.targets.clear(); - this.yielded_at_all = true; - Poll::Pending - } - } - MyGenerator { - sim: this, - yielded_at_all: false, - module_index, - targets, - } - } - async fn yield_advance_time_or_settle( - this: Rc>, - module_index: usize, - duration: Option, - ) { - let mut targets = duration.map_or(EarliestWaitTargets::settle(), |duration| { - EarliestWaitTargets::instant(this.borrow().instant + duration) - }); - Self::yield_wait(this, module_index, &mut targets).await; - } - fn is_extern_module_ready_to_run(&mut self, module_index: usize) -> Option { - let module = &self.extern_modules[module_index]; - let mut retval = None; - for wait_target in module.wait_targets.iter() { - retval = match (wait_target, retval) { - (WaitTarget::Settle, _) => Some(self.instant), - (WaitTarget::Instant(instant), _) if instant <= self.instant => Some(self.instant), - (WaitTarget::Instant(instant), None) => Some(instant), - (WaitTarget::Instant(instant), Some(retval)) => Some(instant.min(retval)), - (WaitTarget::Change { key, value }, retval) => { - if Self::value_changed(&mut self.state, key, SimValue::opaque(value)) { - Some(self.instant) - } else { - retval - } - } - }; - if retval == Some(self.instant) { - break; - } - } - retval - } - fn get_ready_to_run_set(&mut self, ready_to_run_set: &mut ReadyToRunSet) -> Option { - ready_to_run_set.clear(); - let mut retval = None; - if self.state_ready_to_run { - ready_to_run_set.state_ready_to_run = true; - retval = Some(self.instant); - } - for module_index in 0..self.extern_modules.len() { - let Some(instant) = self.is_extern_module_ready_to_run(module_index) else { - continue; - }; - if let Some(retval) = &mut retval { - match instant.cmp(retval) { - std::cmp::Ordering::Less => ready_to_run_set.clear(), - std::cmp::Ordering::Equal => {} - std::cmp::Ordering::Greater => continue, - } - } else { - retval = Some(instant); - } - ready_to_run_set - .extern_modules_ready_to_run - .push(module_index); - } - retval - } - fn set_instant_no_sim(&mut self, instant: SimInstant) { - self.instant = instant; + fn advance_time(&mut self, duration: SimDuration) { + self.settle(); + self.instant += duration; self.for_each_trace_writer_storing_error(|this, mut trace_writer_state| { match &mut trace_writer_state { TraceWriterState::Decls(_) | TraceWriterState::Init(_) => unreachable!(), @@ -1909,145 +6739,54 @@ impl SimulationImpl { Ok(trace_writer_state) }); } - #[must_use] #[track_caller] - fn run_state_settle_cycle(&mut self) -> bool { - self.state_ready_to_run = false; - self.state.setup_call(0); - if self.breakpoints.is_some() { - loop { - match self - .state - .run(self.breakpoints.as_mut().expect("just checked")) - { - RunResult::Break(break_action) => { - println!( - "hit breakpoint at:\n{:?}", - self.state.debug_insn_at(self.state.pc), - ); - match break_action { - BreakAction::DumpStateAndContinue => { - println!("{self:#?}"); - } - BreakAction::Continue => {} - } - } - RunResult::Return(()) => break, - } - } - } else { - let RunResult::Return(()) = self.state.run(()); - } - if self - .clocks_triggered - .iter() - .any(|i| self.state.small_slots[*i] != 0) - { - self.state_ready_to_run = true; - true - } else { - false - } - } - #[track_caller] - fn run_extern_modules_cycle( - this_ref: &Rc>, - generator_waker: &std::task::Waker, - extern_modules_ready_to_run: &[usize], - ) { - let mut this = this_ref.borrow_mut(); - for module_index in extern_modules_ready_to_run.iter().copied() { - let extern_module = &mut this.extern_modules[module_index]; - extern_module.wait_targets.clear(); - let mut generator = if !extern_module.module_state.did_initial_settle { - let sim = extern_module.sim; - drop(this); - Box::into_pin(sim.run(ExternModuleSimulationState { - sim_impl: this_ref.clone(), - module_index, - wait_for_changes_wait_targets: EarliestWaitTargets::default(), - })) - } else if let Some(generator) = extern_module.running_generator.take() { - drop(this); - generator - } else { - continue; - }; - let generator = match generator - .as_mut() - .poll(&mut std::task::Context::from_waker(generator_waker)) - { - Poll::Ready(()) => None, - Poll::Pending => Some(generator), - }; - this = this_ref.borrow_mut(); - this.extern_modules[module_index] - .module_state - .did_initial_settle = true; - if !this.extern_modules[module_index] - .module_state - .uninitialized_ios - .is_empty() - { - panic!( - "extern module didn't initialize all outputs before \ - waiting, settling, or reading any inputs: {}", - this.extern_modules[module_index].sim.source_location - ); - } - this.extern_modules[module_index].running_generator = generator; - } - } - /// clears `targets` - #[track_caller] - fn run_until(this_ref: &Rc>, run_target: SimInstant) { - let mut this = this_ref.borrow_mut(); - let mut ready_to_run_set = ReadyToRunSet::default(); - let generator_waker = this.generator_waker.clone(); + fn settle(&mut self) { assert!( - this.main_module.uninitialized_ios.is_empty(), + self.uninitialized_inputs.is_empty(), "didn't initialize all inputs", ); - let run_target = run_target.max(this.instant); - let mut settle_cycle = 0; - let mut run_extern_modules = true; - loop { - assert!(settle_cycle < 100000, "settle(): took too many steps"); - settle_cycle += 1; - let next_wait_target = match this.get_ready_to_run_set(&mut ready_to_run_set) { - Some(next_wait_target) if next_wait_target <= run_target => next_wait_target, - _ => break, - }; - if next_wait_target > this.instant { - settle_cycle = 0; - this.set_instant_no_sim(next_wait_target); + for _ in 0..100000 { + if !self.needs_settle { + return; } - if run_extern_modules { - drop(this); - Self::run_extern_modules_cycle( - this_ref, - &generator_waker, - &ready_to_run_set.extern_modules_ready_to_run, - ); - this = this_ref.borrow_mut(); - } - if ready_to_run_set.state_ready_to_run { - if this.run_state_settle_cycle() { - // wait for clocks to settle before running extern modules again - run_extern_modules = false; - } else { - run_extern_modules = true; + self.state.setup_call(0); + if self.breakpoints.is_some() { + loop { + match self + .state + .run(self.breakpoints.as_mut().expect("just checked")) + { + RunResult::Break(break_action) => { + println!( + "hit breakpoint at:\n{:?}", + self.state.debug_insn_at(self.state.pc), + ); + match break_action { + BreakAction::DumpStateAndContinue => { + println!("{self:#?}"); + } + BreakAction::Continue => {} + } + } + RunResult::Return(()) => break, + } } - } - if this.main_module.did_initial_settle { - this.read_traces::(); } else { - this.read_traces::(); + let RunResult::Return(()) = self.state.run(()); } - this.state.memory_write_log.sort_unstable(); - this.state.memory_write_log.dedup(); - this.main_module.did_initial_settle = true; - this.for_each_trace_writer_storing_error(|this, trace_writer_state| { + if self.made_initial_step { + self.read_traces::(); + } else { + self.read_traces::(); + } + self.state.memory_write_log.sort_unstable(); + self.state.memory_write_log.dedup(); + self.made_initial_step = true; + self.needs_settle = self + .clocks_triggered + .iter() + .any(|i| self.state.small_slots[*i] != 0); + self.for_each_trace_writer_storing_error(|this, trace_writer_state| { Ok(match trace_writer_state { TraceWriterState::Decls(trace_writer_decls) => TraceWriterState::Running( this.init_trace_writer(trace_writer_decls.write_decls( @@ -2065,105 +6804,162 @@ impl SimulationImpl { TraceWriterState::Errored(e) => TraceWriterState::Errored(e), }) }); - this.state.memory_write_log.clear(); - } - if run_target > this.instant { - this.set_instant_no_sim(run_target); + self.state.memory_write_log.clear(); } + panic!("settle(): took too many steps"); } #[track_caller] - fn settle(this_ref: &Rc>) { - let run_target = this_ref.borrow().instant; - Self::run_until(this_ref, run_target); - } - fn get_module(&self, which_module: WhichModule) -> &SimulationModuleState { - match which_module { - WhichModule::Main => &self.main_module, - WhichModule::Extern { module_index } => &self.extern_modules[module_index].module_state, + fn get_io(&self, target: Target) -> CompiledValue { + if let Some(&retval) = self.io_targets.get(&target) { + return retval; } + if Some(&target) == self.io.target().as_deref() + || Some(target.base()) != self.io.target().map(|v| v.base()) + { + panic!("simulator read/write expression must be an array element/field of `Simulation::io()`"); + }; + panic!("simulator read/write expression must not have dynamic array indexes"); } - fn get_module_mut(&mut self, which_module: WhichModule) -> &mut SimulationModuleState { - match which_module { - WhichModule::Main => &mut self.main_module, - WhichModule::Extern { module_index } => { - &mut self.extern_modules[module_index].module_state + fn mark_target_as_initialized(&mut self, mut target: Target) { + fn remove_target_and_children( + uninitialized_inputs: &mut HashMap>, + target: Target, + ) { + let Some(children) = uninitialized_inputs.remove(&target) else { + return; + }; + for child in children { + remove_target_and_children(uninitialized_inputs, child); } } + remove_target_and_children(&mut self.uninitialized_inputs, target); + while let Some(target_child) = target.child() { + let parent = target_child.parent(); + for child in self + .uninitialized_inputs + .get(&*parent) + .map(|v| &**v) + .unwrap_or(&[]) + { + if self.uninitialized_inputs.contains_key(child) { + return; + } + } + target = *parent; + self.uninitialized_inputs.remove(&target); + } } #[track_caller] - fn read_bit( - &mut self, - io: Expr, - which_module: WhichModule, - ) -> MaybeNeedsSettle { - self.get_module(which_module) - .read_helper(Expr::canonical(io), which_module) - .map(|compiled_value| ReadBitFn { compiled_value }) - .apply_no_settle(&mut self.state) + fn read_helper(&mut self, io: Expr) -> CompiledValue { + let Some(target) = io.target() else { + panic!("can't read from expression that's not a field/element of `Simulation::io()`"); + }; + let compiled_value = self.get_io(*target); + if self.made_initial_step { + self.settle(); + } else { + match target.flow() { + Flow::Source => { + if !self.uninitialized_inputs.is_empty() { + panic!( + "can't read from an output before the simulation has made any steps" + ); + } + self.settle(); + } + Flow::Sink => { + if self.uninitialized_inputs.contains_key(&*target) { + panic!("can't read from an uninitialized input"); + } + } + Flow::Duplex => unreachable!(), + } + } + compiled_value } #[track_caller] - fn write_bit(&mut self, io: Expr, value: bool, which_module: WhichModule) { - let compiled_value = self - .get_module_mut(which_module) - .write_helper(io, which_module); - self.state_ready_to_run = true; - match compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => { + fn write_helper(&mut self, io: Expr) -> CompiledValue { + let Some(target) = io.target() else { + panic!("can't write to an expression that's not a field/element of `Simulation::io()`"); + }; + let compiled_value = self.get_io(*target); + match target.flow() { + Flow::Source => { + panic!("can't write to an output"); + } + Flow::Sink => {} + Flow::Duplex => unreachable!(), + } + if !self.made_initial_step { + self.mark_target_as_initialized(*target); + } + self.needs_settle = true; + compiled_value + } + #[track_caller] + fn read_bit(&mut self, io: Expr) -> bool { + let compiled_value = self.read_helper(Expr::canonical(io)); + match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => { + self.state.small_slots[compiled_value.range.small_slots.start] != 0 + } + TypeLen::A_BIG_SLOT => !self.state.big_slots[compiled_value.range.big_slots.start] + .clone() + .is_zero(), + _ => unreachable!(), + } + } + #[track_caller] + fn write_bit(&mut self, io: Expr, value: bool) { + let compiled_value = self.write_helper(io); + match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => { self.state.small_slots[compiled_value.range.small_slots.start] = value as _; } - Some(TypeLenSingle::BigSlot) => { + TypeLen::A_BIG_SLOT => { self.state.big_slots[compiled_value.range.big_slots.start] = value.into() } - Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(), + _ => unreachable!(), } } #[track_caller] - fn read_bool_or_int( - &mut self, - io: Expr, - which_module: WhichModule, - ) -> MaybeNeedsSettle, I::Value> { - self.get_module(which_module) - .read_helper(Expr::canonical(io), which_module) - .map(|compiled_value| ReadBoolOrIntFn { compiled_value, io }) - .apply_no_settle(&mut self.state) + fn read_bool_or_int(&mut self, io: Expr) -> I::Value { + let compiled_value = self.read_helper(Expr::canonical(io)); + match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => Expr::ty(io).value_from_int_wrapping( + self.state.small_slots[compiled_value.range.small_slots.start], + ), + TypeLen::A_BIG_SLOT => Expr::ty(io).value_from_int_wrapping( + self.state.big_slots[compiled_value.range.big_slots.start].clone(), + ), + _ => unreachable!(), + } } #[track_caller] - fn write_bool_or_int( - &mut self, - io: Expr, - value: I::Value, - which_module: WhichModule, - ) { - let compiled_value = self - .get_module_mut(which_module) - .write_helper(Expr::canonical(io), which_module); - self.state_ready_to_run = true; + fn write_bool_or_int(&mut self, io: Expr, value: I::Value) { + let compiled_value = self.write_helper(Expr::canonical(io)); let value: BigInt = value.into(); - match compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => { + match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => { let mut small_value = value.iter_u64_digits().next().unwrap_or(0); if value.is_negative() { small_value = small_value.wrapping_neg(); } self.state.small_slots[compiled_value.range.small_slots.start] = small_value; } - Some(TypeLenSingle::BigSlot) => { + TypeLen::A_BIG_SLOT => { self.state.big_slots[compiled_value.range.big_slots.start] = value } - Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(), + _ => unreachable!(), } } #[track_caller] - fn read_write_sim_value_helper( - state: &mut interpreter::State, + fn read_write_sim_value_helper( + &mut self, compiled_value: CompiledValue, - start_index: OpaqueSimValueSize, - opaque: &mut Opaque, - read_write_big_scalar: impl Fn(bool, std::ops::Range, &mut Opaque, &mut BigInt) + Copy, - read_write_small_scalar: impl Fn(bool, std::ops::Range, &mut Opaque, &mut SmallUInt) - + Copy, - read_write_sim_only_scalar: impl Fn(usize, &mut Opaque, &mut DynSimOnlyValue) + Copy, + bits: &mut BitSlice, + read_write_big_scalar: impl Fn(bool, &mut BitSlice, &mut BigInt) + Copy, + read_write_small_scalar: impl Fn(bool, &mut BitSlice, &mut SmallUInt) + Copy, ) { match compiled_value.layout.body { CompiledTypeLayoutBody::Scalar => { @@ -2178,39 +6974,26 @@ impl SimulationImpl { CanonicalType::SyncReset(_) => false, CanonicalType::Reset(_) => false, CanonicalType::Clock(_) => false, - CanonicalType::PhantomConst(_) => unreachable!(), - CanonicalType::DynSimOnly(_) => false, }; - let indexes = OpaqueSimValueSizeRange::from( - start_index..start_index + compiled_value.layout.ty.size(), - ); - match compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => read_write_small_scalar( + match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => read_write_small_scalar( signed, - indexes.bit_width, - opaque, - &mut state.small_slots[compiled_value.range.small_slots.start], + bits, + &mut self.state.small_slots[compiled_value.range.small_slots.start], ), - Some(TypeLenSingle::BigSlot) => read_write_big_scalar( + TypeLen::A_BIG_SLOT => read_write_big_scalar( signed, - indexes.bit_width, - opaque, - &mut state.big_slots[compiled_value.range.big_slots.start], + bits, + &mut self.state.big_slots[compiled_value.range.big_slots.start], ), - Some(TypeLenSingle::SimOnlySlot) => read_write_sim_only_scalar( - indexes.sim_only_values_len.start, - opaque, - &mut state.sim_only_slots[compiled_value.range.sim_only_slots.start], - ), - None => unreachable!(), + _ => unreachable!(), } } CompiledTypeLayoutBody::Array { element } => { let ty = ::from_canonical(compiled_value.layout.ty); - let element_size = ty.element().size(); + let element_bit_width = ty.element().bit_width(); for element_index in 0..ty.len() { - Self::read_write_sim_value_helper( - state, + self.read_write_sim_value_helper( CompiledValue { layout: *element, range: compiled_value @@ -2218,26 +7001,23 @@ impl SimulationImpl { .index_array(element.layout.len(), element_index), write: None, }, - start_index + element_index * element_size, - opaque, + &mut bits[element_index * element_bit_width..][..element_bit_width], read_write_big_scalar, read_write_small_scalar, - read_write_sim_only_scalar, ); } } CompiledTypeLayoutBody::Bundle { fields } => { let ty = Bundle::from_canonical(compiled_value.layout.ty); for ( - (_field, offset), + (field, offset), CompiledBundleField { offset: layout_offset, ty: field_layout, }, ) in ty.fields().iter().zip(ty.field_offsets()).zip(fields) { - Self::read_write_sim_value_helper( - state, + self.read_write_sim_value_helper( CompiledValue { layout: field_layout, range: compiled_value.range.slice(TypeIndexRange::new( @@ -2246,201 +7026,57 @@ impl SimulationImpl { )), write: None, }, - start_index + offset, - opaque, + &mut bits[offset..][..field.ty.bit_width()], read_write_big_scalar, read_write_small_scalar, - read_write_sim_only_scalar, ); } } } } #[track_caller] - fn read_no_settle_helper( - state: &mut interpreter::State, - io: Expr, - compiled_value: CompiledValue, - ) -> SimValue { - #[track_caller] - fn read_write_sim_only_scalar( - index: usize, - writer: &mut OpaqueSimValueWriter<'_>, - value: &mut DynSimOnlyValue, - ) { - assert_eq!(writer.sim_only_values_range().start, index); - writer.fill_prefix_with( - OpaqueSimValueSize { - bit_width: 0, - sim_only_values_len: 1, - }, - |writer| { - writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_parts( - BitSlice::empty(), - std::array::from_ref::(value), - )) - }, - ); - } - let size = Expr::ty(io).size(); - let mut opaque = OpaqueSimValue::with_capacity(size); - opaque.rewrite_with(size, |mut writer| { - SimulationImpl::read_write_sim_value_helper( - state, - compiled_value, - OpaqueSimValueSize::empty(), - &mut writer, - |_signed, bit_range, writer, value| { - writer.fill_prefix_with( - OpaqueSimValueSize::from_bit_width(bit_range.len()), - |writer| { - writer.fill_with_bits_with(|bits| { - ::copy_bits_from_bigint_wrapping(value, bits); - }) - }, - ); - }, - |_signed, bit_range, writer, value| { - let bytes = value.to_le_bytes(); - let bitslice = BitSlice::::from_slice(&bytes); - let bitslice = &bitslice[..bit_range.len()]; - writer.fill_prefix_with( - OpaqueSimValueSize::from_bit_width(bit_range.len()), - |writer| { - writer.fill_with_bits_with(|bits| bits.clone_from_bitslice(bitslice)) - }, - ); - }, - read_write_sim_only_scalar, - ); - writer.fill_cloned_from_slice(OpaqueSimValueSlice::empty()) - }); - SimValue::from_opaque(Expr::ty(io), opaque) - } - /// doesn't modify `opaque` - fn value_changed( - state: &mut interpreter::State, - compiled_value: CompiledValue, - mut opaque: &OpaqueSimValue, - ) -> bool { - assert_eq!(opaque.size(), compiled_value.layout.ty.size()); - let any_change = std::cell::Cell::new(false); - SimulationImpl::read_write_sim_value_helper( - state, + fn read(&mut self, io: Expr) -> SimValue { + let compiled_value = self.read_helper(io); + let mut bits = BitVec::repeat(false, compiled_value.layout.ty.bit_width()); + self.read_write_sim_value_helper( compiled_value, - OpaqueSimValueSize::empty(), - &mut opaque, - |_signed, bit_range, opaque, value| { - if !::bits_equal_bigint_wrapping(value, &opaque.bits().bits()[bit_range]) { - any_change.set(true); - } - }, - |_signed, bit_range, opaque, value| { + &mut bits, + |_signed, bits, value| ::copy_bits_from_bigint_wrapping(value, bits), + |_signed, bits, value| { let bytes = value.to_le_bytes(); let bitslice = BitSlice::::from_slice(&bytes); - let bitslice = &bitslice[..bit_range.len()]; - if opaque.bits().bits()[bit_range] != *bitslice { - any_change.set(true); - } - }, - |index, opaque, value| { - if opaque.sim_only_values()[index] != *value { - any_change.set(true); - } + bits.clone_from_bitslice(&bitslice[..bits.len()]); }, ); - any_change.get() + SimValue { + ty: Expr::ty(io), + bits, + } } #[track_caller] - fn read( - &mut self, - io: Expr, - which_module: WhichModule, - ) -> ( - CompiledValue, - MaybeNeedsSettle>, - ) { - let compiled_value = self.get_module(which_module).read_helper(io, which_module); - let value = compiled_value - .map(|compiled_value| ReadFn { compiled_value, io }) - .apply_no_settle(&mut self.state); - let (MaybeNeedsSettle::NeedsSettle(compiled_value) - | MaybeNeedsSettle::NoSettleNeeded(compiled_value)) = compiled_value; - (compiled_value, value) - } - #[track_caller] - fn write( - &mut self, - io: Expr, - value: &SimValue, - which_module: WhichModule, - ) { - let compiled_value = self - .get_module_mut(which_module) - .write_helper(io, which_module); - self.state_ready_to_run = true; - assert_eq!(Expr::ty(io), SimValue::ty(value)); - Self::read_write_sim_value_helper( - &mut self.state, + fn write(&mut self, io: Expr, value: SimValue) { + let compiled_value = self.write_helper(io); + assert_eq!(Expr::ty(io), value.ty()); + self.read_write_sim_value_helper( compiled_value, - OpaqueSimValueSize::empty(), - &mut SimValue::opaque(value), - |signed, bit_range, opaque, value| { + &mut value.into_bits(), + |signed, bits, value| { if signed { - *value = SInt::bits_to_bigint(&opaque.bits().bits()[bit_range]); + *value = SInt::bits_to_bigint(bits); } else { - *value = UInt::bits_to_bigint(&opaque.bits().bits()[bit_range]); + *value = UInt::bits_to_bigint(bits); } }, - |signed, bit_range, opaque, value| { + |signed, bits, value| { let mut small_value = [0; mem::size_of::()]; - if signed - && opaque.bits().bits()[bit_range.clone()] - .last() - .as_deref() - .copied() - == Some(true) - { + if signed && bits.last().as_deref().copied() == Some(true) { small_value.fill(u8::MAX); } - small_value.view_bits_mut::()[0..bit_range.len()] - .clone_from_bitslice(&opaque.bits().bits()[bit_range]); + small_value.view_bits_mut::()[0..bits.len()].clone_from_bitslice(bits); *value = SmallUInt::from_le_bytes(small_value); }, - |index, opaque, value: &mut DynSimOnlyValue| { - value.clone_from(&opaque.sim_only_values()[index]); - }, ); } - #[track_caller] - fn settle_if_needed(this_ref: &Rc>, v: MaybeNeedsSettle) -> O - where - for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>, - { - match v { - MaybeNeedsSettle::NeedsSettle(v) => { - Self::settle(this_ref); - v.call(&mut this_ref.borrow_mut().state) - } - MaybeNeedsSettle::NoSettleNeeded(v) => v, - } - } - async fn yield_settle_if_needed( - this_ref: &Rc>, - module_index: usize, - v: MaybeNeedsSettle, - ) -> O - where - for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>, - { - match v { - MaybeNeedsSettle::NeedsSettle(v) => { - Self::yield_advance_time_or_settle(this_ref.clone(), module_index, None).await; - v.call(&mut this_ref.borrow_mut().state) - } - MaybeNeedsSettle::NoSettleNeeded(v) => v, - } - } fn close_all_trace_writers(&mut self) -> std::io::Result<()> { let trace_writers = mem::take(&mut self.trace_writers); let mut retval = Ok(()); @@ -2510,17 +7146,17 @@ impl SimulationImpl { self.trace_writers = trace_writers; retval } - fn close(this: Rc>) -> std::io::Result<()> { - if this.borrow().main_module.did_initial_settle { - Self::settle(&this); + fn close(mut self) -> std::io::Result<()> { + if self.made_initial_step { + self.settle(); } - this.borrow_mut().close_all_trace_writers() + self.close_all_trace_writers() } - fn flush_traces(this_ref: &Rc>) -> std::io::Result<()> { - if this_ref.borrow().main_module.did_initial_settle { - Self::settle(this_ref); + fn flush_traces(&mut self) -> std::io::Result<()> { + if self.made_initial_step { + self.settle(); } - this_ref.borrow_mut().for_each_trace_writer_getting_error( + self.for_each_trace_writer_getting_error( |this, trace_writer: TraceWriterState| match trace_writer { TraceWriterState::Decls(v) => { let mut v = v.write_decls( @@ -2554,7 +7190,7 @@ impl Drop for SimulationImpl { } pub struct Simulation { - sim_impl: Rc>, + sim_impl: SimulationImpl, io: Expr, } @@ -2576,9 +7212,9 @@ impl fmt::Debug for SortedSetDebug<'_, T, V> { } } -struct SortedMapDebug<'a, K: 'static + Send + Sync, V>(&'a BTreeMap, V>); +struct SortedMapDebug<'a, K, V>(&'a HashMap); -impl fmt::Debug for SortedMapDebug<'_, K, V> { +impl fmt::Debug for SortedMapDebug<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut entries = Vec::from_iter(self.0.iter().map(|(k, v)| { if f.alternate() { @@ -2598,135 +7234,27 @@ impl fmt::Debug for Sorted } } -struct SliceAsMapDebug<'a, T>(&'a [Option]); - -impl fmt::Debug for SliceAsMapDebug<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_map() - .entries( - self.0 - .iter() - .enumerate() - .filter_map(|(k, v)| Some((k, v.as_ref()?))), - ) - .finish() - } -} - impl fmt::Debug for Simulation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { sim_impl, io } = self; - sim_impl.borrow().debug_fmt(Some(io), f) + sim_impl.debug_fmt(Some(io), f) } } -macro_rules! impl_simulation_methods { - ( - async_await = ($($async:tt, $await:tt)?), - track_caller = ($(#[$track_caller:tt])?), - which_module = |$self:ident| $which_module:expr, - ) => { - $(#[$track_caller])? - pub $($async)? fn read_bool_or_int(&mut $self, io: Expr) -> I::Value { - let retval = $self - .sim_impl - .borrow_mut() - .read_bool_or_int(io, $which_module); - $self.settle_if_needed(retval)$(.$await)? - } - $(#[$track_caller])? - pub $($async)? fn write_bool_or_int( - &mut $self, - io: Expr, - value: impl ToExpr, - ) { - let value = value.to_expr(); - assert_eq!(Expr::ty(io), Expr::ty(value), "type mismatch"); - let value = value - .to_literal_bits() - .expect("the value that is being written to an input must be a literal"); - $self.sim_impl.borrow_mut().write_bool_or_int( - io, - I::bits_to_value(Cow::Borrowed(&value)), - $which_module, - ); - } - $(#[$track_caller])? - pub $($async)? fn write_clock(&mut $self, io: Expr, value: bool) { - $self.sim_impl - .borrow_mut() - .write_bit(Expr::canonical(io), value, $which_module); - } - $(#[$track_caller])? - pub $($async)? fn read_clock(&mut $self, io: Expr) -> bool { - let retval = $self - .sim_impl - .borrow_mut() - .read_bit(Expr::canonical(io), $which_module); - $self.settle_if_needed(retval)$(.$await)? - } - $(#[$track_caller])? - pub $($async)? fn write_bool(&mut $self, io: Expr, value: bool) { - $self.sim_impl - .borrow_mut() - .write_bit(Expr::canonical(io), value, $which_module); - } - $(#[$track_caller])? - pub $($async)? fn read_bool(&mut $self, io: Expr) -> bool { - let retval = $self - .sim_impl - .borrow_mut() - .read_bit(Expr::canonical(io), $which_module); - $self.settle_if_needed(retval)$(.$await)? - } - $(#[$track_caller])? - pub $($async)? fn write_reset(&mut $self, io: Expr, value: bool) { - $self.sim_impl - .borrow_mut() - .write_bit(Expr::canonical(io), value, $which_module); - } - $(#[$track_caller])? - pub $($async)? fn read_reset(&mut $self, io: Expr) -> bool { - let retval = $self - .sim_impl - .borrow_mut() - .read_bit(Expr::canonical(io), $which_module); - $self.settle_if_needed(retval)$(.$await)? - } - $(#[$track_caller])? - pub $($async)? fn read(&mut $self, io: Expr) -> SimValue { - let retval = $self - .sim_impl - .borrow_mut() - .read(Expr::canonical(io), $which_module).1; - SimValue::from_canonical($self.settle_if_needed(retval)$(.$await)?) - } - $(#[$track_caller])? - pub $($async)? fn write>(&mut $self, io: Expr, value: V) { - $self.sim_impl.borrow_mut().write( - Expr::canonical(io), - &SimValue::into_canonical(value.into_sim_value_with_type(Expr::ty(io))), - $which_module, - ); - } - }; -} - impl Simulation { pub fn new(module: Interned>) -> Self { Self::from_compiled(Compiled::new(module)) } pub fn add_trace_writer(&mut self, writer: W) { self.sim_impl - .borrow_mut() .trace_writers .push(TraceWriterState::Decls(DynTraceWriterDecls::new(writer))); } pub fn flush_traces(&mut self) -> std::io::Result<()> { - SimulationImpl::flush_traces(&self.sim_impl) + self.sim_impl.flush_traces() } pub fn close(self) -> std::io::Result<()> { - SimulationImpl::close(self.sim_impl) + self.sim_impl.close() } pub fn canonical(self) -> Simulation { let Self { sim_impl, io } = self; @@ -2749,290 +7277,77 @@ impl Simulation { let sim_impl = SimulationImpl::new(compiled.canonical()); Self { io: Expr::from_bundle(sim_impl.io), - sim_impl: Rc::new(RefCell::new(sim_impl)), + sim_impl, } } #[track_caller] pub fn settle(&mut self) { - SimulationImpl::settle(&self.sim_impl); + self.sim_impl.settle(); } #[track_caller] pub fn advance_time(&mut self, duration: SimDuration) { - SimulationImpl::advance_time(&self.sim_impl, duration); + self.sim_impl.advance_time(duration); } #[track_caller] - fn settle_if_needed(&mut self, v: MaybeNeedsSettle) -> O - where - for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>, - { - SimulationImpl::settle_if_needed(&self.sim_impl, v) + pub fn read_bool_or_int(&mut self, io: Expr) -> I::Value { + self.sim_impl.read_bool_or_int(io) + } + #[track_caller] + pub fn write_bool_or_int( + &mut self, + io: Expr, + value: impl ToExpr, + ) { + let value = value.to_expr(); + assert_eq!(Expr::ty(io), Expr::ty(value), "type mismatch"); + let value = value + .to_literal_bits() + .expect("the value that is being written to an input must be a literal"); + self.sim_impl + .write_bool_or_int(io, I::bits_to_value(Cow::Borrowed(&value))); + } + #[track_caller] + pub fn write_clock(&mut self, io: Expr, value: bool) { + self.sim_impl.write_bit(Expr::canonical(io), value); + } + #[track_caller] + pub fn read_clock(&mut self, io: Expr) -> bool { + self.sim_impl.read_bit(Expr::canonical(io)) + } + #[track_caller] + pub fn write_bool(&mut self, io: Expr, value: bool) { + self.sim_impl.write_bit(Expr::canonical(io), value); + } + #[track_caller] + pub fn read_bool(&mut self, io: Expr) -> bool { + self.sim_impl.read_bit(Expr::canonical(io)) + } + #[track_caller] + pub fn write_reset(&mut self, io: Expr, value: bool) { + self.sim_impl.write_bit(Expr::canonical(io), value); + } + #[track_caller] + pub fn read_reset(&mut self, io: Expr) -> bool { + self.sim_impl.read_bit(Expr::canonical(io)) + } + #[track_caller] + pub fn read(&mut self, io: Expr) -> SimValue { + SimValue::from_canonical(self.sim_impl.read(Expr::canonical(io))) + } + #[track_caller] + pub fn write>(&mut self, io: Expr, value: V) { + self.sim_impl.write( + Expr::canonical(io), + value.into_sim_value(Expr::ty(io)).into_canonical(), + ); } - impl_simulation_methods!( - async_await = (), - track_caller = (#[track_caller]), - which_module = |self| WhichModule::Main, - ); #[doc(hidden)] /// This is explicitly unstable and may be changed/removed at any time pub fn set_breakpoints_unstable(&mut self, pcs: HashSet, trace: bool) { - self.sim_impl.borrow_mut().breakpoints = Some(BreakpointsSet { + self.sim_impl.breakpoints = Some(BreakpointsSet { last_was_break: false, set: pcs, trace, }); } } - -pub struct ExternModuleSimulationState { - sim_impl: Rc>, - module_index: usize, - wait_for_changes_wait_targets: EarliestWaitTargets, -} - -impl fmt::Debug for ExternModuleSimulationState { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - sim_impl: _, - module_index, - wait_for_changes_wait_targets: _, - } = self; - f.debug_struct("ExternModuleSimulationState") - .field("sim_impl", &DebugAsDisplay("...")) - .field("module_index", module_index) - .finish_non_exhaustive() - } -} - -impl ExternModuleSimulationState { - pub async fn settle(&mut self) { - SimulationImpl::yield_advance_time_or_settle(self.sim_impl.clone(), self.module_index, None) - .await - } - pub async fn advance_time(&mut self, duration: SimDuration) { - SimulationImpl::yield_advance_time_or_settle( - self.sim_impl.clone(), - self.module_index, - Some(duration), - ) - .await - } - pub async fn wait_for_changes>( - &mut self, - iter: I, - timeout: Option, - ) { - self.wait_for_changes_wait_targets.clear(); - let which_module = WhichModule::Extern { - module_index: self.module_index, - }; - for io in iter { - let io = Expr::canonical(io.to_expr()); - let (key, value) = self.sim_impl.borrow_mut().read(io, which_module); - let value = self.settle_if_needed(value).await; - self.wait_for_changes_wait_targets - .insert(WaitTarget::Change { key, value }); - } - if let Some(timeout) = timeout { - self.wait_for_changes_wait_targets.instant = - Some(self.sim_impl.borrow().instant + timeout); - } - SimulationImpl::yield_wait( - self.sim_impl.clone(), - self.module_index, - &mut self.wait_for_changes_wait_targets, - ) - .await; - } - pub async fn wait_for_clock_edge(&mut self, clk: impl ToExpr) { - let clk = clk.to_expr(); - while self.read_clock(clk).await { - self.wait_for_changes([clk], None).await; - } - while !self.read_clock(clk).await { - self.wait_for_changes([clk], None).await; - } - } - async fn settle_if_needed(&mut self, v: MaybeNeedsSettle) -> O - where - for<'a> F: MaybeNeedsSettleFn<&'a mut interpreter::State, Output = O>, - { - SimulationImpl::yield_settle_if_needed(&self.sim_impl, self.module_index, v).await - } - impl_simulation_methods!( - async_await = (async, await), - track_caller = (), - which_module = |self| WhichModule::Extern { module_index: self.module_index }, - ); -} - -pub trait ExternModuleSimGenerator: Clone + Eq + Hash + Any + Send + Sync + fmt::Debug { - fn run<'a>(&'a self, sim: ExternModuleSimulationState) -> impl IntoFuture + 'a; -} - -pub struct SimGeneratorFn { - pub args: Args, - pub f: fn(Args, ExternModuleSimulationState) -> Fut, -} - -impl fmt::Debug for SimGeneratorFn { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { args, f: _ } = self; - f.debug_struct("SimGeneratorFn") - .field("args", args) - .field("f", &DebugAsDisplay("...")) - .finish() - } -} - -impl Hash for SimGeneratorFn { - fn hash(&self, state: &mut H) { - let Self { args, f } = self; - args.hash(state); - f.hash(state); - } -} - -impl Eq for SimGeneratorFn {} - -impl PartialEq for SimGeneratorFn { - fn eq(&self, other: &Self) -> bool { - let Self { args, f } = self; - *args == other.args && ptr::fn_addr_eq(*f, other.f) - } -} - -impl Clone for SimGeneratorFn { - fn clone(&self) -> Self { - Self { - args: self.args.clone(), - f: self.f, - } - } -} - -impl Copy for SimGeneratorFn {} - -impl< - T: fmt::Debug + Clone + Eq + Hash + Send + Sync + 'static, - Fut: IntoFuture + 'static, -> ExternModuleSimGenerator for SimGeneratorFn -{ - fn run<'a>(&'a self, sim: ExternModuleSimulationState) -> impl IntoFuture + 'a { - (self.f)(self.args.clone(), sim) - } -} - -pub(crate) trait DynExternModuleSimGenerator: - Any + Send + Sync + SupportsPtrEqWithTypeId + fmt::Debug -{ - fn dyn_run<'a>(&'a self, sim: ExternModuleSimulationState) - -> Box + 'a>; -} - -impl DynExternModuleSimGenerator for T { - fn dyn_run<'a>( - &'a self, - sim: ExternModuleSimulationState, - ) -> Box + 'a> { - Box::new(self.run(sim).into_future()) - } -} - -impl InternedCompare for dyn DynExternModuleSimGenerator { - type InternedCompareKey = PtrEqWithTypeId; - - fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey { - this.get_ptr_eq_with_type_id() - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct ExternModuleSimulation { - pub(crate) generator: Interned, - /// Map of [`ModuleIO`]s for the containing module to the [`ModuleIO`]s that the generator will use. - /// Used when transforming the containing module's [`ModuleIO`]s to different types, e.g. with - /// [`deduce_resets`][crate::module::transform::deduce_resets::deduce_resets]. - /// - /// only the keys (sim I/O) are [visited][Visit]/[folded][Fold]. - pub sim_io_to_generator_map: - Interned>, Interned>>>, - pub source_location: SourceLocation, -} - -impl fmt::Debug for ExternModuleSimulation { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ExternModuleSimulation") - .field("generator", &self.generator) - .field( - "sim_io_to_generator_map", - &SortedMapDebug(&self.sim_io_to_generator_map), - ) - .field("source_location", &self.source_location) - .finish() - } -} - -impl ExternModuleSimulation { - pub fn new_with_loc( - source_location: SourceLocation, - generator: G, - ) -> Self { - Self { - generator: Interned::cast_unchecked( - generator.intern(), - |v| -> &dyn DynExternModuleSimGenerator { v }, - ), - sim_io_to_generator_map: Interned::default(), - source_location, - } - } - #[track_caller] - pub fn new(generator: G) -> Self { - Self::new_with_loc(SourceLocation::caller(), generator) - } - fn run(&self, sim: ExternModuleSimulationState) -> Box + 'static> { - Interned::into_inner(self.generator).dyn_run(sim) - } -} - -impl Visit for ExternModuleSimulation { - fn visit(&self, state: &mut State) -> Result<(), State::Error> { - state.visit_extern_module_simulation(self) - } - - fn default_visit(&self, state: &mut State) -> Result<(), State::Error> { - let Self { - generator: _, - sim_io_to_generator_map, - source_location, - } = self; - sim_io_to_generator_map - .keys() - .try_for_each(|k| k.visit(state))?; - source_location.visit(state) - } -} - -impl Fold for ExternModuleSimulation { - fn fold(self, state: &mut State) -> Result::Error> { - state.fold_extern_module_simulation(self) - } - - fn default_fold(self, state: &mut State) -> Result::Error> { - let Self { - generator, - sim_io_to_generator_map, - source_location, - } = self; - Ok(Self { - generator, - sim_io_to_generator_map: Result::, _>::from_iter( - sim_io_to_generator_map - .iter() - .map(|(&sim_io, generator_io)| Ok((sim_io.fold(state)?, *generator_io))), - )? - .intern_sized(), - source_location: source_location.fold(state)?, - }) - } -} diff --git a/crates/fayalite/src/sim/compiler.rs b/crates/fayalite/src/sim/compiler.rs deleted file mode 100644 index fbede7b..0000000 --- a/crates/fayalite/src/sim/compiler.rs +++ /dev/null @@ -1,5161 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -//! Compiler to Interpreter IR for Fayalite Simulation - -use crate::{ - bundle::{BundleField, BundleType}, - enum_::{EnumType, EnumVariant}, - expr::{ - ExprEnum, Flow, ops, - target::{ - GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, - TargetPathElement, - }, - }, - int::BoolOrIntType, - intern::{Intern, InternSlice, Interned, Memoize}, - memory::PortKind, - module::{ - AnnotatedModuleIO, Block, ExternModuleBody, Id, InstantiatedModule, ModuleBody, NameId, - NormalModuleBody, ScopedNameId, Stmt, StmtConnect, StmtDeclaration, StmtFormal, StmtIf, - StmtInstance, StmtMatch, StmtReg, StmtWire, TargetInInstantiatedModule, - transform::deduce_resets::deduce_resets, - }, - prelude::*, - reset::{ResetType, ResetTypeDispatch}, - sim::{ - ExternModuleSimulation, SimTrace, SimTraceKind, SimTraces, TraceArray, TraceAsyncReset, - TraceBool, TraceBundle, TraceClock, TraceDecl, TraceEnumDiscriminant, TraceEnumWithFields, - TraceFieldlessEnum, TraceInstance, TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, - TraceMemoryLocation, TraceModule, TraceModuleIO, TraceReg, TraceSInt, TraceScalarId, - TraceScope, TraceSimOnly, TraceSyncReset, TraceUInt, TraceWire, - interpreter::{ - Insn, InsnField, InsnFieldKind, InsnFieldType, InsnOrLabel, Insns, InsnsBuilding, - InsnsBuildingDone, InsnsBuildingKind, Label, SmallUInt, StatePartArrayIndex, - StatePartArrayIndexed, - parts::{ - MemoryData, SlotDebugData, StatePartIndex, StatePartIndexRange, StatePartKind, - StatePartKindBigSlots, StatePartKindMemories, StatePartKindSimOnlySlots, - StatePartKindSmallSlots, StatePartLayout, StatePartLen, TypeIndex, TypeIndexRange, - TypeLayout, TypeLen, TypeLenSingle, get_state_part_kinds, - }, - }, - }, - ty::{OpaqueSimValueSize, StaticType}, - util::{HashMap, chain}, -}; -use bitvec::vec::BitVec; -use num_bigint::BigInt; -use petgraph::{ - data::FromElements, - visit::{ - EdgeRef, GraphBase, IntoEdgeReferences, IntoNeighbors, IntoNeighborsDirected, - IntoNodeIdentifiers, IntoNodeReferences, NodeRef, VisitMap, Visitable, - }, -}; -use std::{collections::BTreeSet, fmt, hash::Hash, mem}; - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -enum CondBody { - IfTrue { - cond: CompiledValue, - }, - IfFalse { - cond: CompiledValue, - }, - MatchArm { - discriminant: StatePartIndex, - variant_index: usize, - }, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -struct Cond { - body: CondBody, - source_location: SourceLocation, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -pub(crate) struct CompiledBundleField { - pub(crate) offset: TypeIndex, - pub(crate) ty: CompiledTypeLayout, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -pub(crate) enum CompiledTypeLayoutBody { - Scalar, - Array { - /// debug names are ignored, use parent's layout instead - element: Interned>, - }, - Bundle { - /// debug names are ignored, use parent's layout instead - fields: Interned<[CompiledBundleField]>, - }, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -pub(crate) struct CompiledTypeLayout { - pub(crate) ty: T, - pub(crate) layout: TypeLayout, - pub(crate) body: CompiledTypeLayoutBody, -} - -impl CompiledTypeLayout { - fn with_prefixed_debug_names(self, prefix: &str) -> Self { - let Self { ty, layout, body } = self; - Self { - ty, - layout: layout.with_prefixed_debug_names(prefix), - body, - } - } - fn with_anonymized_debug_info(self) -> Self { - let Self { ty, layout, body } = self; - Self { - ty, - layout: layout.with_anonymized_debug_info(), - body, - } - } - fn get(ty: T) -> Self { - #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] - struct MyMemoize; - impl Memoize for MyMemoize { - type Input = CanonicalType; - type InputOwned = CanonicalType; - type Output = CompiledTypeLayout; - - fn inner(self, input: &Self::Input) -> Self::Output { - match input { - CanonicalType::UInt(_) - | CanonicalType::SInt(_) - | CanonicalType::Bool(_) - | CanonicalType::Enum(_) - | CanonicalType::AsyncReset(_) - | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::Clock(_) => { - let mut layout = TypeLayout::empty(); - let debug_data = SlotDebugData { - name: Interned::default(), - ty: *input, - }; - layout.big_slots = StatePartLayout::scalar(debug_data, ()); - CompiledTypeLayout { - ty: *input, - layout: layout.into(), - body: CompiledTypeLayoutBody::Scalar, - } - } - CanonicalType::Array(array) => { - let mut layout = TypeLayout::empty(); - let element = CompiledTypeLayout::get(array.element()).intern_sized(); - for index in 0..array.len() { - layout.allocate( - &element - .layout - .with_prefixed_debug_names(&format!("[{index}]")), - ); - } - CompiledTypeLayout { - ty: *input, - layout: layout.into(), - body: CompiledTypeLayoutBody::Array { element }, - } - } - CanonicalType::PhantomConst(_) => { - let unit_layout = CompiledTypeLayout::get(()); - CompiledTypeLayout { - ty: *input, - layout: unit_layout.layout, - body: unit_layout.body, - } - } - CanonicalType::Bundle(bundle) => { - let mut layout = TypeLayout::empty(); - let fields = bundle - .fields() - .iter() - .map( - |BundleField { - name, - flipped: _, - ty, - }| { - let ty = CompiledTypeLayout::get(*ty); - let offset = layout - .allocate( - &ty.layout - .with_prefixed_debug_names(&format!(".{name}")), - ) - .start(); - CompiledBundleField { offset, ty } - }, - ) - .collect(); - CompiledTypeLayout { - ty: *input, - layout: layout.into(), - body: CompiledTypeLayoutBody::Bundle { fields }, - } - } - CanonicalType::DynSimOnly(ty) => { - let mut layout = TypeLayout::empty(); - let debug_data = SlotDebugData { - name: Interned::default(), - ty: *input, - }; - layout.sim_only_slots = StatePartLayout::scalar(debug_data, *ty); - CompiledTypeLayout { - ty: *input, - layout: layout.into(), - body: CompiledTypeLayoutBody::Scalar, - } - } - } - } - } - let CompiledTypeLayout { - ty: _, - layout, - body, - } = MyMemoize.get_owned(ty.canonical()); - Self { ty, layout, body } - } -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -pub(crate) struct CompiledValue { - pub(crate) layout: CompiledTypeLayout, - pub(crate) range: TypeIndexRange, - pub(crate) write: Option<(CompiledTypeLayout, TypeIndexRange)>, -} - -impl CompiledValue { - fn write(self) -> (CompiledTypeLayout, TypeIndexRange) { - self.write.unwrap_or((self.layout, self.range)) - } - fn write_value(self) -> Self { - let (layout, range) = self.write(); - Self { - layout, - range, - write: None, - } - } - fn map( - self, - mut f: impl FnMut( - CompiledTypeLayout, - TypeIndexRange, - ) -> (CompiledTypeLayout, TypeIndexRange), - ) -> CompiledValue { - let (layout, range) = f(self.layout, self.range); - CompiledValue { - layout, - range, - write: self.write.map(|(layout, range)| f(layout, range)), - } - } - pub(crate) fn map_ty(self, mut f: impl FnMut(T) -> U) -> CompiledValue { - self.map(|CompiledTypeLayout { ty, layout, body }, range| { - ( - CompiledTypeLayout { - ty: f(ty), - layout, - body, - }, - range, - ) - }) - } -} - -impl CompiledValue { - fn field_by_index(self, field_index: usize) -> CompiledValue { - self.map(|layout, range| { - let CompiledTypeLayout { - ty: _, - layout: _, - body: CompiledTypeLayoutBody::Bundle { fields }, - } = layout - else { - unreachable!(); - }; - ( - fields[field_index].ty, - range.slice(TypeIndexRange::new( - fields[field_index].offset, - fields[field_index].ty.layout.len(), - )), - ) - }) - } - pub(crate) fn field_by_name(self, name: Interned) -> CompiledValue { - self.field_by_index(self.layout.ty.name_indexes()[&name]) - } -} - -impl CompiledValue { - pub(crate) fn element(self, index: usize) -> CompiledValue { - self.map(|layout, range| { - let CompiledTypeLayoutBody::Array { element } = layout.body else { - unreachable!(); - }; - (*element, range.index_array(element.layout.len(), index)) - }) - } - fn element_dyn( - self, - index_slot: StatePartIndex, - ) -> CompiledExpr { - CompiledExpr::from(self).element_dyn(index_slot) - } -} - -macro_rules! make_type_array_indexes { - ( - type_plural_fields = [$($type_plural_field:ident,)*]; - type_kinds = [$($type_kind:ident,)*]; - ) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] - pub(crate) struct TypeArrayIndexes { - $(pub(crate) $type_plural_field: Interned<[StatePartArrayIndex<$type_kind>]>,)* - } - - impl TypeArrayIndexes { - pub(crate) fn as_ref(&self) -> TypeArrayIndexesRef<'_> { - TypeArrayIndexesRef { - $($type_plural_field: &self.$type_plural_field,)* - } - } - #[must_use] - pub(crate) fn join(self, next: TypeArrayIndex) -> TypeArrayIndexes { - TypeArrayIndexes { - $($type_plural_field: Interned::from_iter(self.$type_plural_field.iter().copied().chain([next.$type_plural_field])),)* - } - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct TypeArrayIndex { - $(pub(crate) $type_plural_field: StatePartArrayIndex<$type_kind>,)* - } - - impl TypeArrayIndex { - pub(crate) fn from_parts(index: StatePartIndex, len: usize, stride: TypeLen) -> Self { - Self { - $($type_plural_field: StatePartArrayIndex { - index, - len, - stride: stride.$type_plural_field, - },)* - } - } - pub(crate) fn len(self) -> usize { - let len = self.small_slots.len; - $(assert_eq!(self.$type_plural_field.len, len, "array length mismatch");)* - len - } - pub(crate) fn index(self) -> StatePartIndex { - let index = self.small_slots.index; - $(assert_eq!(self.$type_plural_field.index, index, "array index mismatch");)* - index - } - pub(crate) fn is_empty(self) -> bool { - self.len() == 0 - } - pub(crate) fn stride(self) -> TypeLen { - TypeLen { - $($type_plural_field: self.$type_plural_field.stride,)* - } - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] - pub(crate) struct TypeArrayIndexesRef<'a> { - $(pub(crate) $type_plural_field: &'a [StatePartArrayIndex<$type_kind>],)* - } - - impl<'a> TypeArrayIndexesRef<'a> { - pub(crate) fn len(self) -> usize { - let len = self.small_slots.len(); - $(assert_eq!(self.$type_plural_field.len(), len, "indexes count mismatch");)* - len - } - pub(crate) fn is_empty(self) -> bool { - self.len() == 0 - } - pub(crate) fn iter(self) -> impl Iterator + 'a { - (0..self.len()).map(move |i| TypeArrayIndex { - $($type_plural_field: self.$type_plural_field[i],)* - }) - } - pub(crate) fn for_each_offset( - self, - mut f: impl FnMut(TypeIndex), - ) { - self.for_each_offset2(TypeIndex { - $($type_plural_field: StatePartIndex::new(0),)* - }, &mut f); - } - pub(crate) fn split_first(self) -> Option<(TypeArrayIndex, Self)> { - $(let $type_plural_field = self.$type_plural_field.split_first()?;)* - let next = TypeArrayIndex { - $($type_plural_field: *$type_plural_field.0,)* - }; - let rest = TypeArrayIndexesRef { - $($type_plural_field: $type_plural_field.1,)* - }; - Some((next, rest)) - } - pub(crate) fn for_each_offset2( - self, - base_offset: TypeIndex, - f: &mut (impl FnMut(TypeIndex) + ?Sized), - ) { - if let Some((next, rest)) = self.split_first() { - let stride = next.stride(); - for index in 0..next.len().try_into().expect("array too big") { - let mut offset = TypeIndex { - $($type_plural_field: StatePartIndex::new( - stride - .$type_plural_field - .value - .checked_mul(index) - .expect("array too big"), - ),)* - }; - $(offset.$type_plural_field.value = - base_offset - .$type_plural_field - .value - .checked_add(offset.$type_plural_field.value) - .expect("array too big");)* - rest.for_each_offset2(offset, f); - } - } else { - $(assert!(self.$type_plural_field.is_empty(), "indexes count mismatch");)* - f(base_offset); - } - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct TypeArrayIndexed { - $(pub(crate) $type_plural_field: StatePartArrayIndexed<$type_kind>,)* - } - - impl TypeArrayIndexed { - pub(crate) fn from_parts(base: TypeIndex, indexes: TypeArrayIndexes) -> Self { - Self { - $($type_plural_field: StatePartArrayIndexed { - base: base.$type_plural_field, - indexes: indexes.$type_plural_field, - },)* - } - } - pub(crate) fn base(self) -> TypeIndex { - TypeIndex { - $($type_plural_field: self.$type_plural_field.base,)* - } - } - pub(crate) fn indexes(self) -> TypeArrayIndexes { - TypeArrayIndexes { - $($type_plural_field: self.$type_plural_field.indexes,)* - } - } - } - - impl From for TypeArrayIndexed { - fn from(value: TypeIndex) -> Self { - TypeArrayIndexed { - $($type_plural_field: value.$type_plural_field.into(),)* - } - } - } - }; -} - -get_state_part_kinds! { - make_type_array_indexes! { - type_plural_fields; - type_kinds; - } -} - -#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] -struct CompiledExpr { - static_part: CompiledValue, - indexes: TypeArrayIndexes, -} - -impl From> for CompiledExpr { - fn from(static_part: CompiledValue) -> Self { - Self { - static_part, - indexes: TypeArrayIndexes::default(), - } - } -} - -impl CompiledExpr { - fn map_ty(self, f: impl FnMut(T) -> U) -> CompiledExpr { - let Self { - static_part, - indexes, - } = self; - CompiledExpr { - static_part: static_part.map_ty(f), - indexes, - } - } - fn add_target_without_indexes_to_set(self, inputs: &mut SlotSet) { - let Self { - static_part, - indexes, - } = self; - indexes.as_ref().for_each_offset(|offset| { - inputs.extend([static_part.range.offset(offset)]); - }); - } - fn add_target_and_indexes_to_set(self, inputs: &mut SlotSet) { - let Self { - static_part: _, - indexes, - } = self; - self.add_target_without_indexes_to_set(inputs); - inputs.extend(indexes.as_ref().iter()); - } -} - -impl CompiledExpr { - fn field_by_index(self, field_index: usize) -> CompiledExpr { - CompiledExpr { - static_part: self.static_part.field_by_index(field_index), - indexes: self.indexes, - } - } - fn field_by_name(self, name: Interned) -> CompiledExpr { - CompiledExpr { - static_part: self.static_part.field_by_name(name), - indexes: self.indexes, - } - } -} - -impl CompiledExpr { - fn element(self, index: usize) -> CompiledExpr { - CompiledExpr { - static_part: self.static_part.element(index), - indexes: self.indexes, - } - } - fn element_dyn( - self, - index_slot: StatePartIndex, - ) -> CompiledExpr { - let CompiledTypeLayoutBody::Array { element } = self.static_part.layout.body else { - unreachable!(); - }; - let stride = element.layout.len(); - let indexes = self.indexes.join(TypeArrayIndex::from_parts( - index_slot, - self.static_part.layout.ty.len(), - stride, - )); - CompiledExpr { - static_part: self.static_part.map(|layout, range| { - let CompiledTypeLayoutBody::Array { element } = layout.body else { - unreachable!(); - }; - (*element, range.index_array(stride, 0)) - }), - indexes, - } - } -} - -macro_rules! make_assignment_graph { - ( - type_plural_fields = [$($type_plural_field:ident,)*]; - type_singular_variants = [$($type_singular_variant:ident,)*]; - type_kinds = [$($type_kind:ident,)*]; - array_indexed_variants = [$($array_indexed_variant:ident,)*]; - input_variants = [$($input_variant:ident,)*]; - output_variants = [$($output_variant:ident,)*]; - ) => { - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] - enum AssignmentOrSlotIndex { - AssignmentIndex(usize), - $($type_singular_variant(StatePartIndex<$type_kind>),)* - } - - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] - enum AssignmentIO { - $($input_variant { - assignment_index: usize, - slot: StatePartIndex<$type_kind>, - },)* - $($output_variant { - assignment_index: usize, - slot: StatePartIndex<$type_kind>, - },)* - } - - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] - enum AssignmentsEdge { - IO(AssignmentIO), - AssignmentImmediatePredecessor { - predecessor_assignment_index: usize, - assignment_index: usize, - }, - } - - #[derive(Debug)] - enum Assignments { - Accumulating { - assignments: Vec, - }, - Finalized { - assignments: Box<[Assignment]>, - slots_layout: TypeLayout, - slot_readers: SlotToAssignmentIndexFullMap, - slot_writers: SlotToAssignmentIndexFullMap, - assignment_immediate_predecessors: Box<[Box<[usize]>]>, - assignment_immediate_successors: Box<[Box<[usize]>]>, - }, - } - - impl Default for Assignments { - fn default() -> Self { - Self::Accumulating { - assignments: Vec::new(), - } - } - } - - impl Assignments { - fn finalize(&mut self, slots_layout: TypeLayout) { - let Self::Accumulating { assignments } = self else { - unreachable!("already finalized"); - }; - let assignments = mem::take(assignments).into_boxed_slice(); - let mut slot_readers = SlotToAssignmentIndexFullMap::new(slots_layout.len()); - let mut slot_writers = SlotToAssignmentIndexFullMap::new(slots_layout.len()); - let mut assignment_immediate_predecessors = vec![BTreeSet::new(); assignments.len()]; - let mut assignment_immediate_successors = vec![BTreeSet::new(); assignments.len()]; - for (assignment_index, assignment) in assignments.iter().enumerate() { - slot_readers - .keys_for_assignment(assignment_index) - .extend([&assignment.inputs]); - slot_readers - .keys_for_assignment(assignment_index) - .extend(&assignment.conditions); - $(for &slot in &assignment.outputs.$type_plural_field { - if let Some(&pred) = slot_writers[slot].last() { - assignment_immediate_predecessors[assignment_index].insert(pred); - assignment_immediate_successors[pred].insert(assignment_index); - } - slot_writers[slot].push(assignment_index); - })* - } - *self = Self::Finalized { - assignments, - slots_layout, - slot_readers, - slot_writers, - assignment_immediate_predecessors: assignment_immediate_predecessors - .into_iter() - .map(Box::from_iter) - .collect(), - assignment_immediate_successors: assignment_immediate_successors - .into_iter() - .map(Box::from_iter) - .collect(), - }; - } - fn push(&mut self, v: Assignment) { - let Self::Accumulating { assignments } = self else { - unreachable!("already finalized"); - }; - assignments.push(v); - } - fn assignments(&self) -> &[Assignment] { - let Self::Finalized { assignments, .. } = self else { - unreachable!("Assignments::finalize should have been called"); - }; - assignments - } - fn slots_layout(&self) -> TypeLayout { - let Self::Finalized { slots_layout, .. } = self else { - unreachable!("Assignments::finalize should have been called"); - }; - *slots_layout - } - fn slot_readers(&self) -> &SlotToAssignmentIndexFullMap { - let Self::Finalized { slot_readers, .. } = self else { - unreachable!("Assignments::finalize should have been called"); - }; - slot_readers - } - fn slot_writers(&self) -> &SlotToAssignmentIndexFullMap { - let Self::Finalized { slot_writers, .. } = self else { - unreachable!("Assignments::finalize should have been called"); - }; - slot_writers - } - fn assignment_immediate_predecessors(&self) -> &[Box<[usize]>] { - let Self::Finalized { - assignment_immediate_predecessors, - .. - } = self - else { - unreachable!("Assignments::finalize should have been called"); - }; - assignment_immediate_predecessors - } - fn assignment_immediate_successors(&self) -> &[Box<[usize]>] { - let Self::Finalized { - assignment_immediate_successors, - .. - } = self - else { - unreachable!("Assignments::finalize should have been called"); - }; - assignment_immediate_successors - } - fn elements(&self) -> AssignmentsElements<'_> { - let SlotToAssignmentIndexFullMap { - $($type_plural_field,)* - } = self.slot_readers(); - AssignmentsElements { - node_indexes: HashMap::with_capacity_and_hasher( - self.assignments().len() $(+ $type_plural_field.len())*, - Default::default(), - ), - nodes: self.node_references(), - edges: self.edge_references(), - } - } - } - - impl GraphBase for Assignments { - type EdgeId = AssignmentsEdge; - type NodeId = AssignmentOrSlotIndex; - } - - #[derive(Debug, Clone, Copy)] - enum AssignmentsNodeRef<'a> { - Assignment { - index: usize, - #[allow(dead_code, reason = "used in Debug impl")] - assignment: &'a Assignment, - }, - $($type_singular_variant( - StatePartIndex<$type_kind>, - #[allow(dead_code, reason = "used in Debug impl")] SlotDebugData, - ),)* - } - - impl<'a> NodeRef for AssignmentsNodeRef<'a> { - type NodeId = AssignmentOrSlotIndex; - type Weight = AssignmentsNodeRef<'a>; - - fn id(&self) -> Self::NodeId { - match *self { - AssignmentsNodeRef::Assignment { - index, - assignment: _, - } => AssignmentOrSlotIndex::AssignmentIndex(index), - $(AssignmentsNodeRef::$type_singular_variant(slot, _) => AssignmentOrSlotIndex::$type_singular_variant(slot),)* - } - } - - fn weight(&self) -> &Self::Weight { - self - } - } - - impl<'a> petgraph::visit::Data for &'a Assignments { - type NodeWeight = AssignmentsNodeRef<'a>; - type EdgeWeight = AssignmentsEdge; - } - - struct AssignmentsElements<'a> { - node_indexes: HashMap, - nodes: AssignmentsNodes<'a>, - edges: AssignmentsEdges<'a>, - } - - impl<'a> Iterator for AssignmentsElements<'a> { - type Item = petgraph::data::Element< - <&'a Assignments as petgraph::visit::Data>::NodeWeight, - <&'a Assignments as petgraph::visit::Data>::EdgeWeight, - >; - - fn next(&mut self) -> Option { - let Self { - node_indexes, - nodes, - edges, - } = self; - if let Some(node) = nodes.next() { - node_indexes.insert(node.id(), node_indexes.len()); - return Some(petgraph::data::Element::Node { weight: node }); - } - let edge = edges.next()?; - Some(petgraph::data::Element::Edge { - source: node_indexes[&edge.source()], - target: node_indexes[&edge.target()], - weight: *edge.weight(), - }) - } - } - - #[derive(Clone)] - struct AssignmentsNodeIdentifiers { - assignment_indexes: std::ops::Range, - $($type_plural_field: std::ops::Range,)* - } - - impl AssignmentsNodeIdentifiers { - fn internal_iter<'a>(&'a mut self) -> impl Iterator + 'a { - let Self { - assignment_indexes, - $($type_plural_field,)* - } = self; - assignment_indexes - .map(AssignmentOrSlotIndex::AssignmentIndex) - $(.chain($type_plural_field.map(|value| { - AssignmentOrSlotIndex::$type_singular_variant(StatePartIndex::new(value)) - })))* - } - } - - impl Iterator for AssignmentsNodeIdentifiers { - type Item = AssignmentOrSlotIndex; - fn next(&mut self) -> Option { - self.internal_iter().next() - } - - fn nth(&mut self, n: usize) -> Option { - self.internal_iter().nth(n) - } - } - - impl<'a> IntoNodeIdentifiers for &'a Assignments { - type NodeIdentifiers = AssignmentsNodeIdentifiers; - - fn node_identifiers(self) -> Self::NodeIdentifiers { - let TypeLen { - $($type_plural_field,)* - } = self.slot_readers().len(); - AssignmentsNodeIdentifiers { - assignment_indexes: 0..self.assignments().len(), - $($type_plural_field: 0..$type_plural_field.value,)* - } - } - } - - struct AssignmentsNodes<'a> { - assignments: &'a Assignments, - nodes: AssignmentsNodeIdentifiers, - } - - impl<'a> Iterator for AssignmentsNodes<'a> { - type Item = AssignmentsNodeRef<'a>; - - fn next(&mut self) -> Option { - self.nodes.next().map(|node| match node { - AssignmentOrSlotIndex::AssignmentIndex(index) => AssignmentsNodeRef::Assignment { - index, - assignment: &self.assignments.assignments()[index], - }, - $(AssignmentOrSlotIndex::$type_singular_variant(slot) => AssignmentsNodeRef::$type_singular_variant( - slot, - *self.assignments.slots_layout().$type_plural_field.debug_data(slot), - ),)* - }) - } - } - - impl<'a> IntoNodeReferences for &'a Assignments { - type NodeRef = AssignmentsNodeRef<'a>; - type NodeReferences = AssignmentsNodes<'a>; - - fn node_references(self) -> Self::NodeReferences { - AssignmentsNodes { - assignments: self, - nodes: self.node_identifiers(), - } - } - } - - #[derive(Default)] - struct AssignmentsNeighborsDirected<'a> { - assignment_indexes: std::slice::Iter<'a, usize>, - $($type_plural_field: std::collections::btree_set::Iter<'a, StatePartIndex<$type_kind>>,)* - } - - impl Iterator for AssignmentsNeighborsDirected<'_> { - type Item = AssignmentOrSlotIndex; - fn next(&mut self) -> Option { - let Self { - assignment_indexes, - $($type_plural_field,)* - } = self; - if let retval @ Some(_) = assignment_indexes - .next() - .copied() - .map(AssignmentOrSlotIndex::AssignmentIndex) - { - retval - } $(else if let retval @ Some(_) = $type_plural_field - .next() - .copied() - .map(AssignmentOrSlotIndex::$type_singular_variant) - { - retval - })* else { - None - } - } - } - - impl<'a> IntoNeighbors for &'a Assignments { - type Neighbors = AssignmentsNeighborsDirected<'a>; - - fn neighbors(self, n: Self::NodeId) -> Self::Neighbors { - self.neighbors_directed(n, petgraph::Direction::Outgoing) - } - } - - impl<'a> IntoNeighborsDirected for &'a Assignments { - type NeighborsDirected = AssignmentsNeighborsDirected<'a>; - - fn neighbors_directed( - self, - n: Self::NodeId, - d: petgraph::Direction, - ) -> Self::NeighborsDirected { - use petgraph::Direction::*; - let slot_map = match d { - Outgoing => self.slot_readers(), - Incoming => self.slot_writers(), - }; - match n { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { - let assignment = &self.assignments()[assignment_index]; - let ( - assignment_indexes, - SlotSet { - $($type_plural_field,)* - }, - ) = match d { - Outgoing => ( - &self.assignment_immediate_successors()[assignment_index], - &assignment.outputs, - ), - Incoming => ( - &self.assignment_immediate_predecessors()[assignment_index], - &assignment.inputs, - ), - }; - AssignmentsNeighborsDirected { - assignment_indexes: assignment_indexes.iter(), - $($type_plural_field: $type_plural_field.iter(),)* - } - } - $(AssignmentOrSlotIndex::$type_singular_variant(slot) => AssignmentsNeighborsDirected { - assignment_indexes: slot_map[slot].iter(), - ..Default::default() - },)* - } - } - } - - impl EdgeRef for AssignmentsEdge { - type NodeId = AssignmentOrSlotIndex; - type EdgeId = AssignmentsEdge; - type Weight = AssignmentsEdge; - - fn source(&self) -> Self::NodeId { - match *self { - $(AssignmentsEdge::IO(AssignmentIO::$input_variant { - assignment_index: _, - slot, - }) => AssignmentOrSlotIndex::$type_singular_variant(slot),)* - $(AssignmentsEdge::IO(AssignmentIO::$output_variant { - assignment_index, - slot: _, - }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index),)* - AssignmentsEdge::AssignmentImmediatePredecessor { - predecessor_assignment_index, - assignment_index: _, - } => AssignmentOrSlotIndex::AssignmentIndex(predecessor_assignment_index), - } - } - - fn target(&self) -> Self::NodeId { - match *self { - $(AssignmentsEdge::IO(AssignmentIO::$input_variant { - assignment_index, - slot: _, - }) => AssignmentOrSlotIndex::AssignmentIndex(assignment_index),)* - $(AssignmentsEdge::IO(AssignmentIO::$output_variant { - assignment_index: _, - slot, - }) => AssignmentOrSlotIndex::$type_singular_variant(slot),)* - AssignmentsEdge::AssignmentImmediatePredecessor { - predecessor_assignment_index: _, - assignment_index, - } => AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - } - } - - fn weight(&self) -> &Self::Weight { - self - } - - fn id(&self) -> Self::EdgeId { - *self - } - } - - struct AssignmentsEdges<'a> { - assignments: &'a Assignments, - nodes: AssignmentsNodeIdentifiers, - outgoing_neighbors: Option<(AssignmentOrSlotIndex, AssignmentsNeighborsDirected<'a>)>, - } - - impl Iterator for AssignmentsEdges<'_> { - type Item = AssignmentsEdge; - - fn next(&mut self) -> Option { - loop { - if let Some((node, outgoing_neighbors)) = &mut self.outgoing_neighbors { - if let Some(outgoing_neighbor) = outgoing_neighbors.next() { - return Some(match (*node, outgoing_neighbor) { - ( - $(AssignmentOrSlotIndex::$type_singular_variant(_))|*, - $(AssignmentOrSlotIndex::$type_singular_variant(_))|*, - ) => unreachable!(), - ( - AssignmentOrSlotIndex::AssignmentIndex(predecessor_assignment_index), - AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - ) => AssignmentsEdge::AssignmentImmediatePredecessor { - predecessor_assignment_index, - assignment_index, - }, - $(( - AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - AssignmentOrSlotIndex::$type_singular_variant(slot), - ) => AssignmentsEdge::IO(AssignmentIO::$output_variant { - assignment_index, - slot, - }),)* - $(( - AssignmentOrSlotIndex::$type_singular_variant(slot), - AssignmentOrSlotIndex::AssignmentIndex(assignment_index), - ) => AssignmentsEdge::IO(AssignmentIO::$input_variant { - assignment_index, - slot, - }),)* - }); - } - } - let node = self.nodes.next()?; - self.outgoing_neighbors = Some(( - node, - self.assignments - .neighbors_directed(node, petgraph::Direction::Outgoing), - )); - } - } - } - - impl<'a> IntoEdgeReferences for &'a Assignments { - type EdgeRef = AssignmentsEdge; - type EdgeReferences = AssignmentsEdges<'a>; - - fn edge_references(self) -> Self::EdgeReferences { - AssignmentsEdges { - assignments: self, - nodes: self.node_identifiers(), - outgoing_neighbors: None, - } - } - } - - struct AssignmentsVisitMap { - assignments: Vec, - slots: DenseSlotSet, - } - - impl VisitMap for AssignmentsVisitMap { - fn visit(&mut self, n: AssignmentOrSlotIndex) -> bool { - match n { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { - !mem::replace(&mut self.assignments[assignment_index], true) - } - $(AssignmentOrSlotIndex::$type_singular_variant(slot) => self.slots.insert(slot),)* - } - } - - fn is_visited(&self, n: &AssignmentOrSlotIndex) -> bool { - match *n { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { - self.assignments[assignment_index] - } - $(AssignmentOrSlotIndex::$type_singular_variant(slot) => self.slots.contains(slot),)* - } - } - - fn unvisit(&mut self, n: AssignmentOrSlotIndex) -> bool { - match n { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { - mem::replace(&mut self.assignments[assignment_index], false) - } - $(AssignmentOrSlotIndex::$type_singular_variant(slot) => self.slots.remove(slot),)* - } - } - } - - impl Visitable for Assignments { - type Map = AssignmentsVisitMap; - - fn visit_map(self: &Self) -> Self::Map { - AssignmentsVisitMap { - assignments: vec![false; self.assignments().len()], - slots: DenseSlotSet::new(self.slot_readers().len()), - } - } - - fn reset_map(self: &Self, map: &mut Self::Map) { - let AssignmentsVisitMap { assignments, slots } = map; - assignments.clear(); - assignments.resize(self.assignments().len(), false); - if slots.len() != self.slot_readers().len() { - *slots = DenseSlotSet::new(self.slot_readers().len()); - } else { - slots.clear(); - } - } - } - - #[derive(Debug)] - struct Assignment { - inputs: SlotSet, - outputs: SlotSet, - conditions: Interned<[Cond]>, - insns: Vec, - source_location: SourceLocation, - } - - #[derive(Debug)] - struct SlotToAssignmentIndexFullMap { - $($type_plural_field: Box<[Vec]>,)* - } - - impl SlotToAssignmentIndexFullMap { - fn new(len: TypeLen) -> Self { - Self { - $($type_plural_field: vec![Vec::new(); len.$type_plural_field.value.try_into().expect("length too big")] - .into_boxed_slice(),)* - } - } - fn len(&self) -> TypeLen { - TypeLen { - $($type_plural_field: StatePartLen::new(self.$type_plural_field.len() as _),)* - } - } - fn keys_for_assignment( - &mut self, - assignment_index: usize, - ) -> SlotToAssignmentIndexFullMapKeysForAssignment<'_> { - SlotToAssignmentIndexFullMapKeysForAssignment { - map: self, - assignment_index, - } - } - fn for_each( - &self, - $(mut $type_plural_field: impl FnMut(StatePartIndex<$type_kind>, &[usize]),)* - ) { - $(self.$type_plural_field.iter().enumerate().for_each(|(k, v)| { - $type_plural_field(StatePartIndex::new(k as _), v) - });)* - } - } - - $(impl std::ops::Index> for SlotToAssignmentIndexFullMap { - type Output = Vec; - - fn index(&self, index: StatePartIndex<$type_kind>) -> &Self::Output { - &self.$type_plural_field[index.as_usize()] - } - } - - impl std::ops::IndexMut> for SlotToAssignmentIndexFullMap { - fn index_mut(&mut self, index: StatePartIndex<$type_kind>) -> &mut Self::Output { - &mut self.$type_plural_field[index.as_usize()] - } - })* - - struct SlotToAssignmentIndexFullMapKeysForAssignment<'a> { - map: &'a mut SlotToAssignmentIndexFullMap, - assignment_index: usize, - } - - $(impl<'a> Extend<&'a StatePartIndex<$type_kind>> - for SlotToAssignmentIndexFullMapKeysForAssignment<'_> { - fn extend>>(&mut self, iter: T) { - self.extend(iter.into_iter().copied()); - } - })* - - $(impl Extend> - for SlotToAssignmentIndexFullMapKeysForAssignment<'_> { - fn extend>>(&mut self, iter: T) { - iter.into_iter() - .for_each(|slot| self.map[slot].push(self.assignment_index)); - } - })* - - impl<'a> Extend<&'a SlotSet> for SlotToAssignmentIndexFullMapKeysForAssignment<'_> { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each( - |set| { - $(self.extend(&set.$type_plural_field);)* - }, - ); - } - } - - impl<'a> Extend<&'a Cond> for SlotToAssignmentIndexFullMapKeysForAssignment<'_> { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each(|cond| match cond.body { - CondBody::IfTrue { cond } | CondBody::IfFalse { cond } => { - let CompiledValue { - range, - layout: _, - write: _, - } = cond; - $(self.extend(range.$type_plural_field.iter());)* - } - CondBody::MatchArm { - discriminant, - variant_index: _, - } => self.extend([discriminant]), - }); - } - } - - impl Assignment { - fn new( - conditions: Interned<[Cond]>, - insns: Vec, - source_location: SourceLocation, - ) -> Self { - let mut inputs = SlotSet::default(); - let mut outputs = SlotSet::default(); - for insn in &insns { - let insn = match insn { - InsnOrLabel::Insn(insn) => insn, - InsnOrLabel::Label(_) => continue, - }; - for InsnField { ty, kind } in insn.fields() { - match (kind, ty) { - $((InsnFieldKind::Input, InsnFieldType::$type_singular_variant(&slot)) => { - inputs.extend([slot]); - })* - $(( - InsnFieldKind::Input, - InsnFieldType::$array_indexed_variant(&array_indexed), - ) => { - array_indexed.for_each_target(|slot| inputs.extend([slot])); - inputs.extend(array_indexed.indexes); - })* - $((InsnFieldKind::Output, InsnFieldType::$type_singular_variant(&slot)) => { - outputs.extend([slot]); - })* - $(( - InsnFieldKind::Output, - InsnFieldType::$array_indexed_variant(&array_indexed), - ) => { - array_indexed.for_each_target(|slot| { - outputs.extend([slot]); - }); - inputs.extend(array_indexed.indexes); - })* - ( - _, - InsnFieldType::Memory(_) - | InsnFieldType::SmallUInt(_) - | InsnFieldType::SmallSInt(_) - | InsnFieldType::InternedBigInt(_) - | InsnFieldType::U8(_) - | InsnFieldType::USize(_) - | InsnFieldType::Empty(_), - ) - | ( - InsnFieldKind::Immediate - | InsnFieldKind::Memory - | InsnFieldKind::BranchTarget, - _, - ) => {} - } - } - } - Self { - inputs, - outputs, - conditions, - insns, - source_location, - } - } - } - }; -} - -get_state_part_kinds! { - make_assignment_graph! { - type_plural_fields; - type_singular_variants; - type_kinds; - array_indexed_variants; - #[custom] input_variants = [small_slot = SmallInput, big_slot = BigInput, sim_only_slot = SimOnlyInput,]; - #[custom] output_variants = [small_slot = SmallOutput, big_slot = BigOutput, sim_only_slot = SimOnlyOutput,]; - } -} - -macro_rules! make_dense_slot_set { - ( - type_plural_fields = [$($type_plural_field:ident,)*]; - type_kinds = [$($type_kind:ident,)*]; - ) => { - #[derive(Clone, Debug, PartialEq, Eq, Hash)] - struct DenseSlotSet { - $($type_plural_field: Box<[bool]>,)* - } - - impl DenseSlotSet { - fn new(len: TypeLen) -> Self { - Self { - $($type_plural_field: vec![false; len.$type_plural_field.value.try_into().expect("length too big")] - .into_boxed_slice(),)* - } - } - fn len(&self) -> TypeLen { - TypeLen { - $($type_plural_field: StatePartLen::new(self.$type_plural_field.len() as _),)* - } - } - fn clear(&mut self) { - $(self.$type_plural_field.fill(false);)* - } - } - - trait DenseSlotSetMethods: Extend> { - fn contains(&self, k: StatePartIndex) -> bool; - fn remove(&mut self, k: StatePartIndex) -> bool { - self.take(k).is_some() - } - fn take(&mut self, k: StatePartIndex) -> Option>; - fn replace(&mut self, k: StatePartIndex) -> Option>; - fn insert(&mut self, k: StatePartIndex) -> bool { - self.replace(k).is_none() - } - } - - impl Extend> for DenseSlotSet - where - Self: DenseSlotSetMethods, - { - fn extend>>(&mut self, iter: T) { - iter.into_iter().for_each(|v| { - self.insert(v); - }); - } - } - - $(impl DenseSlotSetMethods<$type_kind> for DenseSlotSet { - fn contains(&self, k: StatePartIndex<$type_kind>) -> bool { - self.$type_plural_field[k.as_usize()] - } - - fn take( - &mut self, - k: StatePartIndex<$type_kind>, - ) -> Option> { - mem::replace(self.$type_plural_field.get_mut(k.as_usize())?, false).then_some(k) - } - - fn replace( - &mut self, - k: StatePartIndex<$type_kind>, - ) -> Option> { - mem::replace(&mut self.$type_plural_field[k.as_usize()], true).then_some(k) - } - })* - }; -} - -get_state_part_kinds! { - make_dense_slot_set! { - type_plural_fields; - type_kinds; - } -} - -macro_rules! make_slot_vec { - ( - type_plural_fields = [$($type_plural_field:ident,)*]; - type_kinds = [$($type_kind:ident,)*]; - ) => { - #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] - struct SlotVec { - $($type_plural_field: Vec>,)* - } - - impl SlotVec { - fn is_empty(&self) -> bool { - true $(&& self.$type_plural_field.is_empty())* - } - } - }; -} - -get_state_part_kinds! { - make_slot_vec! { - type_plural_fields; - type_kinds; - } -} - -macro_rules! make_slot_set { - ( - type_plural_fields = [$($type_plural_field:ident,)*]; - type_kinds = [$($type_kind:ident,)*]; - ) => { - #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] - struct SlotSet { - $($type_plural_field: BTreeSet>,)* - } - - impl SlotSet { - fn is_empty(&self) -> bool { - true $(&& self.$type_plural_field.is_empty())* - } - fn for_each( - &self, - $($type_plural_field: impl FnMut(StatePartIndex<$type_kind>),)* - ) { - $(self.$type_plural_field.iter().copied().for_each($type_plural_field);)* - } - fn all( - &self, - $($type_plural_field: impl FnMut(StatePartIndex<$type_kind>) -> bool,)* - ) -> bool { - true $(&& self.$type_plural_field.iter().copied().all($type_plural_field))* - } - } - - $(impl Extend> for SlotSet { - fn extend>>( - &mut self, - iter: T, - ) { - self.$type_plural_field.extend(iter); - } - })* - - $(impl Extend> for SlotSet { - fn extend>>(&mut self, iter: T) { - self.extend(iter.into_iter().flat_map(|v| v.iter())); - } - })* - - impl Extend for SlotSet { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each( - |range| { - $(self.extend(range.$type_plural_field.iter());)* - }, - ) - } - } - - impl Extend for SlotSet { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each( - |v| { - $(self.extend([v.$type_plural_field]);)* - }, - ) - } - } - - $(impl Extend> for SlotSet { - fn extend>>(&mut self, iter: T) { - self.extend(iter.into_iter().map(|v| v.index)); - } - })* - - impl Extend for SlotSet { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each(|cond_body| match cond_body { - CondBody::IfTrue { cond } | CondBody::IfFalse { cond } => { - self.extend([cond.range]); - } - CondBody::MatchArm { - discriminant, - variant_index: _, - } => self.extend([discriminant]), - }) - } - } - - impl Extend for SlotSet { - fn extend>(&mut self, iter: T) { - self.extend(iter.into_iter().map(|v| v.body)) - } - } - }; -} - -get_state_part_kinds! { - make_slot_set! { - type_plural_fields; - type_kinds; - } -} - -#[derive(Debug)] -struct RegisterReset { - is_async: bool, - init: CompiledValue, - rst: StatePartIndex, -} - -#[derive(Debug, Clone, Copy)] -struct ClockTrigger { - last_clk_was_low: StatePartIndex, - clk: StatePartIndex, - clk_triggered: StatePartIndex, - source_location: SourceLocation, -} - -#[derive(Debug)] -struct Register { - value: CompiledValue, - clk_triggered: StatePartIndex, - reset: Option, - source_location: SourceLocation, -} - -#[derive(Debug)] - -struct MemoryPort { - clk_triggered: StatePartIndex, - addr_delayed: Vec>, - en_delayed: Vec>, - #[allow(dead_code, reason = "used in Debug impl")] - data_layout: CompiledTypeLayout, - read_data_delayed: Vec, - write_data_delayed: Vec, - write_mask_delayed: Vec, - write_mode_delayed: Vec>, - write_insns: Vec, -} - -struct MemoryPortReadInsns<'a> { - addr: StatePartIndex, - en: StatePartIndex, - write_mode: Option>, - data: TypeIndexRange, - insns: &'a mut Vec, -} - -struct MemoryPortWriteInsns<'a> { - addr: StatePartIndex, - en: StatePartIndex, - write_mode: Option>, - data: TypeIndexRange, - mask: TypeIndexRange, - insns: &'a mut Vec, -} - -#[derive(Debug)] -struct Memory { - mem: Mem, - memory: StatePartIndex, - trace: TraceMem, - ports: Vec, -} - -#[derive(Copy, Clone)] -enum MakeTraceDeclTarget { - Expr(Expr), - Memory { - id: TraceMemoryId, - depth: usize, - stride: usize, - start: usize, - ty: CanonicalType, - }, -} - -impl MakeTraceDeclTarget { - fn flow(self) -> Flow { - match self { - MakeTraceDeclTarget::Expr(expr) => Expr::flow(expr), - MakeTraceDeclTarget::Memory { .. } => Flow::Duplex, - } - } - fn ty(self) -> CanonicalType { - match self { - MakeTraceDeclTarget::Expr(expr) => Expr::ty(expr), - MakeTraceDeclTarget::Memory { ty, .. } => ty, - } - } -} - -struct DebugOpaque(T); - -impl fmt::Debug for DebugOpaque { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("<...>") - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub(crate) struct CompiledExternModule { - pub(crate) module_io_targets: Interned<[Target]>, - pub(crate) module_io: Interned<[CompiledValue]>, - pub(crate) simulation: ExternModuleSimulation, -} - -#[derive(Debug)] -pub struct Compiler { - insns: Insns, - original_base_module: Interned>, - base_module: Interned>, - modules: HashMap, - extern_modules: Vec, - compiled_values: HashMap>, - compiled_exprs: HashMap, CompiledExpr>, - compiled_exprs_to_values: HashMap, CompiledValue>, - decl_conditions: HashMap>, - compiled_values_to_dyn_array_indexes: - HashMap, StatePartIndex>, - compiled_value_bool_dest_is_small_map: - HashMap, StatePartIndex>, - assignments: Assignments, - clock_triggers: Vec, - compiled_value_to_clock_trigger_map: HashMap, ClockTrigger>, - enum_discriminants: HashMap, StatePartIndex>, - registers: Vec, - traces: SimTraces>>, - memories: Vec, - dump_assignments_dot: Option>>, -} - -macro_rules! impl_compiler { - ( - type_plural_fields = [$($type_plural_field:ident,)*]; - type_singular_fields = [$($type_singular_field:ident,)*]; - type_singular_variants = [$($type_singular_variant:ident,)*]; - type_kinds = [$($type_kind:ident,)*]; - copy_insns = [$($copy_insn:ident,)*]; - read_indexed_insns = [$($read_indexed_insn:ident,)*]; - write_indexed_insns = [$($write_indexed_insn:ident,)*]; - ) => { - impl Compiler { - fn make_trace_scalar_helper( - &mut self, - instantiated_module: InstantiatedModule, - target: MakeTraceDeclTarget, - source_location: SourceLocation, - $($type_singular_field: impl FnOnce(StatePartIndex<$type_kind>) -> SimTraceKind,)* - ) -> TraceLocation { - match target { - MakeTraceDeclTarget::Expr(target) => { - let compiled_value = self.compile_expr(instantiated_module, target); - let compiled_value = self.compiled_expr_to_value(compiled_value, source_location); - TraceLocation::Scalar(self.new_sim_trace(match compiled_value.range.len().as_single() { - $(Some(TypeLenSingle::$type_singular_variant) => { - $type_singular_field(compiled_value.range.$type_plural_field.start) - })* - None => unreachable!(), - })) - } - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start, - ty, - } => TraceLocation::Memory(TraceMemoryLocation { - id, - depth, - stride, - start, - len: ty.bit_width(), - }), - } - } - fn make_trace_scalar( - &mut self, - instantiated_module: InstantiatedModule, - target: MakeTraceDeclTarget, - name: Interned, - source_location: SourceLocation, - ) -> TraceDecl { - let flow = target.flow(); - match target.ty() { - CanonicalType::UInt(ty) => TraceUInt { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallUInt { index, ty }, - |index| SimTraceKind::BigUInt { index, ty }, - |_| unreachable!(""), - ), - name, - ty, - flow, - } - .into(), - CanonicalType::SInt(ty) => TraceSInt { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallSInt { index, ty }, - |index| SimTraceKind::BigSInt { index, ty }, - |_| unreachable!(""), - ), - name, - ty, - flow, - } - .into(), - CanonicalType::Bool(_) => TraceBool { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallBool { index }, - |index| SimTraceKind::BigBool { index }, - |_| unreachable!(""), - ), - name, - flow, - } - .into(), - CanonicalType::Array(_) => unreachable!(), - CanonicalType::Enum(ty) => { - assert_eq!(ty.discriminant_bit_width(), ty.type_properties().bit_width); - let location = match target { - MakeTraceDeclTarget::Expr(target) => { - let compiled_value = self.compile_expr(instantiated_module, target); - let compiled_value = - self.compiled_expr_to_value(compiled_value, source_location); - let discriminant = self.compile_enum_discriminant( - compiled_value.map_ty(Enum::from_canonical), - source_location, - ); - TraceLocation::Scalar(self.new_sim_trace(SimTraceKind::EnumDiscriminant { - index: discriminant, - ty, - })) - } - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start, - ty: _, - } => TraceLocation::Memory(TraceMemoryLocation { - id, - depth, - stride, - start, - len: ty.type_properties().bit_width, - }), - }; - TraceFieldlessEnum { - location, - name, - ty, - flow, - } - .into() - } - CanonicalType::Bundle(_) | CanonicalType::PhantomConst(_) => unreachable!(), - CanonicalType::AsyncReset(_) => TraceAsyncReset { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallAsyncReset { index }, - |index| SimTraceKind::BigAsyncReset { index }, - |_| unreachable!(""), - ), - name, - flow, - } - .into(), - CanonicalType::SyncReset(_) => TraceSyncReset { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallSyncReset { index }, - |index| SimTraceKind::BigSyncReset { index }, - |_| unreachable!(""), - ), - name, - flow, - } - .into(), - CanonicalType::Reset(_) => unreachable!(), - CanonicalType::Clock(_) => TraceClock { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |index| SimTraceKind::SmallClock { index }, - |index| SimTraceKind::BigClock { index }, - |_| unreachable!(""), - ), - name, - flow, - } - .into(), - CanonicalType::DynSimOnly(ty) => TraceSimOnly { - location: self.make_trace_scalar_helper( - instantiated_module, - target, - source_location, - |_| unreachable!(""), - |_| unreachable!(""), - |index| SimTraceKind::SimOnly { index, ty }, - ), - name, - ty, - flow, - } - .into(), - } - } - fn compiled_expr_to_value( - &mut self, - expr: CompiledExpr, - source_location: SourceLocation, - ) -> CompiledValue { - if let Some(&retval) = self.compiled_exprs_to_values.get(&expr) { - return retval; - } - assert!( - expr.static_part.layout.ty.is_passive(), - "invalid expression passed to compiled_expr_to_value -- type must be passive", - ); - let CompiledExpr { - static_part, - indexes, - } = expr; - let retval = if indexes.as_ref().is_empty() { - CompiledValue { - layout: static_part.layout, - range: static_part.range, - write: None, - } - } else { - let layout = static_part.layout.with_anonymized_debug_info(); - let retval = CompiledValue { - layout, - range: self.insns.allocate_variable(&layout.layout), - write: None, - }; - let TypeIndexRange { - $($type_plural_field,)* - } = retval.range; - self.add_assignment( - Interned::default(), - chain!( - $($type_plural_field - .iter() - .zip(static_part.range.$type_plural_field.iter()) - .map(|(dest, base)| Insn::$read_indexed_insn { - dest, - src: StatePartArrayIndexed { - base, - indexes: indexes.$type_plural_field, - }, - }),)* - ), - source_location, - ); - retval - }; - self.compiled_exprs_to_values.insert(expr, retval); - retval - } - fn compile_simple_connect( - &mut self, - conditions: Interned<[Cond]>, - lhs: CompiledExpr, - rhs: CompiledValue, - source_location: SourceLocation, - ) { - let CompiledExpr { - static_part: lhs_static_part, - indexes, - } = lhs; - let (lhs_layout, lhs_range) = lhs_static_part.write(); - assert!( - lhs_layout.ty.is_passive(), - "invalid expression passed to compile_simple_connect -- type must be passive", - ); - self.add_assignment( - conditions, - chain!( - $(lhs_range.$type_plural_field - .iter() - .zip(rhs.range.$type_plural_field.iter()) - .map(|(base, src)| { - if indexes.$type_plural_field.is_empty() { - Insn::$copy_insn { dest: base, src } - } else { - Insn::$write_indexed_insn { - dest: StatePartArrayIndexed { - base, - indexes: indexes.$type_plural_field, - }, - src, - } - } - }),)* - ), - source_location, - ); - } - fn process_assignments(&mut self) { - self.assignments - .finalize(self.insns.state_layout().ty.clone().into()); - if let Some(DebugOpaque(dump_assignments_dot)) = &self.dump_assignments_dot { - let graph = - petgraph::graph::DiGraph::<_, _, usize>::from_elements(self.assignments.elements()); - dump_assignments_dot(&petgraph::dot::Dot::new(&graph)); - } - let assignments_order: Vec<_> = match petgraph::algo::toposort(&self.assignments, None) { - Ok(nodes) => nodes - .into_iter() - .filter_map(|n| match n { - AssignmentOrSlotIndex::AssignmentIndex(v) => Some(v), - _ => None, - }) - .collect(), - Err(e) => match e.node_id() { - AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => panic!( - "combinatorial logic cycle detected at: {}", - self.assignments.assignments()[assignment_index].source_location, - ), - $(AssignmentOrSlotIndex::$type_singular_variant(slot) => panic!( - "combinatorial logic cycle detected through: {}", - self.insns.state_layout().ty.$type_plural_field.debug_data[slot.as_usize()].name, - ),)* - }, - }; - struct CondStackEntry<'a> { - cond: &'a Cond, - end_label: Label, - } - let mut cond_stack = Vec::>::new(); - for assignment_index in assignments_order { - let Assignment { - inputs: _, - outputs: _, - conditions, - insns, - source_location, - } = &self.assignments.assignments()[assignment_index]; - let mut same_len = 0; - for (index, (entry, cond)) in cond_stack.iter().zip(conditions).enumerate() { - if entry.cond != cond { - break; - } - same_len = index + 1; - } - while cond_stack.len() > same_len { - let CondStackEntry { cond: _, end_label } = - cond_stack.pop().expect("just checked len"); - self.insns.define_label_at_next_insn(end_label); - } - for cond in &conditions[cond_stack.len()..] { - let end_label = self.insns.new_label(); - match cond.body { - CondBody::IfTrue { cond: cond_value } - | CondBody::IfFalse { cond: cond_value } => { - let (branch_if_zero, branch_if_non_zero) = match cond_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => ( - Insn::BranchIfSmallZero { - target: end_label.0, - value: cond_value.range.small_slots.start, - }, - Insn::BranchIfSmallNonZero { - target: end_label.0, - value: cond_value.range.small_slots.start, - }, - ), - Some(TypeLenSingle::BigSlot) => ( - Insn::BranchIfZero { - target: end_label.0, - value: cond_value.range.big_slots.start, - }, - Insn::BranchIfNonZero { - target: end_label.0, - value: cond_value.range.big_slots.start, - }, - ), - Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(), - }; - self.insns.push( - if let CondBody::IfTrue { .. } = cond.body { - branch_if_zero - } else { - branch_if_non_zero - }, - cond.source_location, - ); - } - CondBody::MatchArm { - discriminant, - variant_index, - } => { - self.insns.push( - Insn::BranchIfSmallNeImmediate { - target: end_label.0, - lhs: discriminant, - rhs: variant_index as _, - }, - cond.source_location, - ); - } - } - cond_stack.push(CondStackEntry { cond, end_label }); - } - self.insns.extend(insns.iter().copied(), *source_location); - } - for CondStackEntry { cond: _, end_label } in cond_stack { - self.insns.define_label_at_next_insn(end_label); - } - } - } - }; -} - -get_state_part_kinds! { - impl_compiler! { - type_plural_fields; - type_singular_fields; - type_singular_variants; - type_kinds; - copy_insns; - read_indexed_insns; - write_indexed_insns; - } -} - -impl Compiler { - pub fn new(base_module: Interned>) -> Self { - let original_base_module = base_module; - let base_module = deduce_resets(base_module, true) - .unwrap_or_else(|e| panic!("failed to deduce reset types: {e}")); - Self { - insns: Insns::new(), - original_base_module, - base_module, - modules: HashMap::default(), - extern_modules: Vec::new(), - compiled_values: HashMap::default(), - compiled_exprs: HashMap::default(), - compiled_exprs_to_values: HashMap::default(), - decl_conditions: HashMap::default(), - compiled_values_to_dyn_array_indexes: HashMap::default(), - compiled_value_bool_dest_is_small_map: HashMap::default(), - assignments: Assignments::default(), - clock_triggers: Vec::new(), - compiled_value_to_clock_trigger_map: HashMap::default(), - enum_discriminants: HashMap::default(), - registers: Vec::new(), - traces: SimTraces(Vec::new()), - memories: Vec::new(), - dump_assignments_dot: None, - } - } - #[doc(hidden)] - /// This is explicitly unstable and may be changed/removed at any time - pub fn dump_assignments_dot(&mut self, callback: Box) { - self.dump_assignments_dot = Some(DebugOpaque(callback)); - } - fn new_sim_trace(&mut self, kind: SimTraceKind) -> TraceScalarId { - let id = TraceScalarId(self.traces.0.len()); - self.traces.0.push(SimTrace { - kind, - state: (), - last_state: (), - }); - id - } - fn make_trace_decl_child( - &mut self, - instantiated_module: InstantiatedModule, - target: MakeTraceDeclTarget, - name: Interned, - source_location: SourceLocation, - ) -> TraceDecl { - match target.ty() { - CanonicalType::Array(ty) => { - let elements = Interned::from_iter((0..ty.len()).map(|index| { - self.make_trace_decl_child( - instantiated_module, - match target { - MakeTraceDeclTarget::Expr(target) => MakeTraceDeclTarget::Expr( - Expr::::from_canonical(target)[index], - ), - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start, - ty: _, - } => MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start: start + ty.element().bit_width() * index, - ty: ty.element(), - }, - }, - Intern::intern_owned(format!("[{index}]")), - source_location, - ) - })); - TraceArray { - name, - elements, - ty, - flow: target.flow(), - } - .into() - } - CanonicalType::Enum(ty) => { - if ty.variants().iter().all(|v| v.ty.is_none()) { - self.make_trace_scalar(instantiated_module, target, name, source_location) - } else { - let flow = target.flow(); - let location = match target { - MakeTraceDeclTarget::Expr(target) => { - let compiled_value = self.compile_expr(instantiated_module, target); - let compiled_value = - self.compiled_expr_to_value(compiled_value, source_location); - let discriminant = self.compile_enum_discriminant( - compiled_value.map_ty(Enum::from_canonical), - source_location, - ); - TraceLocation::Scalar(self.new_sim_trace( - SimTraceKind::EnumDiscriminant { - index: discriminant, - ty, - }, - )) - } - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start, - ty: _, - } => TraceLocation::Memory(TraceMemoryLocation { - id, - depth, - stride, - start, - len: ty.discriminant_bit_width(), - }), - }; - let discriminant = TraceEnumDiscriminant { - location, - name: "$tag".intern(), - ty, - flow, - }; - let non_empty_fields = - Interned::from_iter(ty.variants().into_iter().enumerate().flat_map( - |(variant_index, variant)| { - variant.ty.map(|variant_ty| { - self.make_trace_decl_child( - instantiated_module, - match target { - MakeTraceDeclTarget::Expr(target) => { - MakeTraceDeclTarget::Expr( - ops::VariantAccess::new_by_index( - Expr::::from_canonical(target), - variant_index, - ) - .to_expr(), - ) - } - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start, - ty: _, - } => MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start: start + ty.discriminant_bit_width(), - ty: variant_ty, - }, - }, - variant.name, - source_location, - ) - }) - }, - )); - TraceEnumWithFields { - name, - discriminant, - non_empty_fields, - ty, - flow, - } - .into() - } - } - CanonicalType::Bundle(ty) => { - let fields = Interned::from_iter(ty.fields().iter().zip(ty.field_offsets()).map( - |(field, field_offset)| { - self.make_trace_decl_child( - instantiated_module, - match target { - MakeTraceDeclTarget::Expr(target) => { - MakeTraceDeclTarget::Expr(Expr::field( - Expr::::from_canonical(target), - &field.name, - )) - } - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start, - ty: _, - } => { - let Some(bit_width) = field_offset.only_bit_width() else { - todo!("memory containing sim-only values"); - }; - MakeTraceDeclTarget::Memory { - id, - depth, - stride, - start: start + bit_width, - ty: field.ty, - } - } - }, - field.name, - source_location, - ) - }, - )); - TraceBundle { - name, - fields, - ty, - flow: target.flow(), - } - .into() - } - CanonicalType::UInt(_) - | CanonicalType::SInt(_) - | CanonicalType::Bool(_) - | CanonicalType::AsyncReset(_) - | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::Clock(_) - | CanonicalType::DynSimOnly(_) => { - self.make_trace_scalar(instantiated_module, target, name, source_location) - } - CanonicalType::PhantomConst(_) => TraceBundle { - name, - fields: Interned::default(), - ty: Bundle::new(Interned::default()), - flow: target.flow(), - } - .into(), - } - } - fn make_trace_decl( - &mut self, - instantiated_module: InstantiatedModule, - target_base: TargetBase, - ) -> TraceDecl { - let target = MakeTraceDeclTarget::Expr(target_base.to_expr()); - match target_base { - TargetBase::ModuleIO(module_io) => TraceModuleIO { - name: module_io.name(), - child: self - .make_trace_decl_child( - instantiated_module, - target, - module_io.name(), - module_io.source_location(), - ) - .intern(), - ty: module_io.ty(), - flow: module_io.flow(), - } - .into(), - TargetBase::MemPort(mem_port) => { - let name = Intern::intern_owned(mem_port.port_name().to_string()); - let TraceDecl::Scope(TraceScope::Bundle(bundle)) = self.make_trace_decl_child( - instantiated_module, - target, - name, - mem_port.source_location(), - ) else { - unreachable!() - }; - TraceMemPort { - name, - bundle, - ty: mem_port.ty(), - } - .into() - } - TargetBase::Reg(reg) => TraceReg { - name: reg.name(), - child: self - .make_trace_decl_child( - instantiated_module, - target, - reg.name(), - reg.source_location(), - ) - .intern(), - ty: reg.ty(), - } - .into(), - TargetBase::RegSync(reg) => TraceReg { - name: reg.name(), - child: self - .make_trace_decl_child( - instantiated_module, - target, - reg.name(), - reg.source_location(), - ) - .intern(), - ty: reg.ty(), - } - .into(), - TargetBase::RegAsync(reg) => TraceReg { - name: reg.name(), - child: self - .make_trace_decl_child( - instantiated_module, - target, - reg.name(), - reg.source_location(), - ) - .intern(), - ty: reg.ty(), - } - .into(), - TargetBase::Wire(wire) => TraceWire { - name: wire.name(), - child: self - .make_trace_decl_child( - instantiated_module, - target, - wire.name(), - wire.source_location(), - ) - .intern(), - ty: wire.ty(), - } - .into(), - TargetBase::Instance(instance) => { - let TraceDecl::Scope(TraceScope::Bundle(instance_io)) = self.make_trace_decl_child( - instantiated_module, - target, - instance.name(), - instance.source_location(), - ) else { - unreachable!() - }; - let compiled_module = &self.modules[&InstantiatedModule::Child { - parent: instantiated_module.intern(), - instance: instance.intern(), - }]; - TraceInstance { - name: instance.name(), - instance_io, - module: compiled_module.trace_decls, - ty: instance.ty(), - } - .into() - } - } - } - fn compile_value( - &mut self, - target: TargetInInstantiatedModule, - ) -> CompiledValue { - if let Some(&retval) = self.compiled_values.get(&target) { - return retval; - } - let retval = match target.target { - Target::Base(base) => { - let unprefixed_layout = CompiledTypeLayout::get(base.canonical_ty()); - let layout = unprefixed_layout.with_prefixed_debug_names(&format!( - "{:?}.{:?}", - target.instantiated_module, - base.target_name() - )); - let range = self.insns.allocate_variable(&layout.layout); - let write = match *base { - TargetBase::ModuleIO(_) - | TargetBase::MemPort(_) - | TargetBase::Wire(_) - | TargetBase::Instance(_) => None, - TargetBase::Reg(_) | TargetBase::RegSync(_) | TargetBase::RegAsync(_) => { - let write_layout = unprefixed_layout.with_prefixed_debug_names(&format!( - "{:?}.{:?}$next", - target.instantiated_module, - base.target_name() - )); - Some(( - write_layout, - self.insns.allocate_variable(&write_layout.layout), - )) - } - }; - CompiledValue { - range, - layout, - write, - } - } - Target::Child(target_child) => { - let parent = self.compile_value(TargetInInstantiatedModule { - instantiated_module: target.instantiated_module, - target: *target_child.parent(), - }); - match *target_child.path_element() { - TargetPathElement::BundleField(TargetPathBundleField { name }) => { - parent.map_ty(Bundle::from_canonical).field_by_name(name) - } - TargetPathElement::ArrayElement(TargetPathArrayElement { index }) => { - parent.map_ty(Array::from_canonical).element(index) - } - TargetPathElement::DynArrayElement(_) => unreachable!(), - } - } - }; - self.compiled_values.insert(target, retval); - retval - } - fn add_assignment>( - &mut self, - conditions: Interned<[Cond]>, - insns: impl IntoIterator, - source_location: SourceLocation, - ) { - let insns = Vec::from_iter(insns.into_iter().map(Into::into)); - self.assignments - .push(Assignment::new(conditions, insns, source_location)); - } - fn simple_big_expr_input( - &mut self, - instantiated_module: InstantiatedModule, - input: Expr, - ) -> StatePartIndex { - let input = self.compile_expr(instantiated_module, input); - let input = - self.compiled_expr_to_value(input, instantiated_module.leaf_module().source_location()); - assert_eq!(input.range.len(), TypeLen::big_slot()); - input.range.big_slots.start - } - fn compile_expr_helper( - &mut self, - instantiated_module: InstantiatedModule, - dest_ty: CanonicalType, - make_insns: impl FnOnce(&mut Self, TypeIndexRange) -> Vec, - ) -> CompiledValue { - let layout = CompiledTypeLayout::get(dest_ty); - let range = self.insns.allocate_variable(&layout.layout); - let retval = CompiledValue { - layout, - range, - write: None, - }; - let insns = make_insns(self, range); - self.add_assignment( - Interned::default(), - insns, - instantiated_module.leaf_module().source_location(), - ); - retval - } - fn simple_nary_big_expr_helper( - &mut self, - instantiated_module: InstantiatedModule, - dest_ty: CanonicalType, - make_insns: impl FnOnce(StatePartIndex) -> Vec, - ) -> CompiledValue { - self.compile_expr_helper(instantiated_module, dest_ty, |_, dest| { - assert_eq!(dest.len(), TypeLen::big_slot()); - make_insns(dest.big_slots.start) - }) - } - fn simple_nary_big_expr( - &mut self, - instantiated_module: InstantiatedModule, - dest_ty: CanonicalType, - inputs: [Expr; N], - make_insns: impl FnOnce( - StatePartIndex, - [StatePartIndex; N], - ) -> Vec, - ) -> CompiledValue { - let inputs = inputs.map(|input| self.simple_big_expr_input(instantiated_module, input)); - self.simple_nary_big_expr_helper(instantiated_module, dest_ty, |dest| { - make_insns(dest, inputs) - }) - } - fn compiled_value_to_dyn_array_index( - &mut self, - compiled_value: CompiledValue, - source_location: SourceLocation, - ) -> StatePartIndex { - if let Some(&retval) = self - .compiled_values_to_dyn_array_indexes - .get(&compiled_value) - { - return retval; - } - let mut ty = compiled_value.layout.ty; - ty.width = ty.width.min(SmallUInt::BITS as usize); - let retval = match compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => compiled_value.range.small_slots.start, - Some(TypeLenSingle::BigSlot) => { - let debug_data = SlotDebugData { - name: Interned::default(), - ty: ty.canonical(), - }; - let dest = self - .insns - .allocate_variable(&TypeLayout { - small_slots: StatePartLayout::scalar(debug_data, ()), - ..TypeLayout::empty() - }) - .small_slots - .start; - self.add_assignment( - Interned::default(), - vec![Insn::CastBigToArrayIndex { - dest, - src: compiled_value.range.big_slots.start, - }], - source_location, - ); - dest - } - Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(), - }; - self.compiled_values_to_dyn_array_indexes - .insert(compiled_value, retval); - retval - } - fn compiled_value_bool_dest_is_small( - &mut self, - compiled_value: CompiledValue, - source_location: SourceLocation, - ) -> StatePartIndex { - if let Some(&retval) = self - .compiled_value_bool_dest_is_small_map - .get(&compiled_value) - { - return retval; - } - let retval = match compiled_value.range.len().as_single() { - Some(TypeLenSingle::SmallSlot) => compiled_value.range.small_slots.start, - Some(TypeLenSingle::BigSlot) => { - let debug_data = SlotDebugData { - name: Interned::default(), - ty: Bool.canonical(), - }; - let dest = self - .insns - .allocate_variable(&TypeLayout { - small_slots: StatePartLayout::scalar(debug_data, ()), - ..TypeLayout::empty() - }) - .small_slots - .start; - self.add_assignment( - Interned::default(), - vec![Insn::IsNonZeroDestIsSmall { - dest, - src: compiled_value.range.big_slots.start, - }], - source_location, - ); - dest - } - Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(), - }; - self.compiled_value_bool_dest_is_small_map - .insert(compiled_value, retval); - retval - } - fn compile_cast_scalar_to_bits( - &mut self, - instantiated_module: InstantiatedModule, - arg: Expr, - cast_fn: impl FnOnce(Expr) -> Expr, - ) -> CompiledValue { - let arg = Expr::::from_canonical(arg); - let retval = cast_fn(arg); - let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); - let retval = self - .compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()); - retval.map_ty(UInt::from_canonical) - } - fn compile_cast_aggregate_to_bits( - &mut self, - instantiated_module: InstantiatedModule, - parts: impl IntoIterator>, - ) -> CompiledValue { - let retval = parts - .into_iter() - .map(|part| part.cast_to_bits()) - .reduce(|accumulator, part| accumulator | (part << Expr::ty(accumulator).width)) - .unwrap_or_else(|| UInt[0].zero().to_expr()); - let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); - let retval = self - .compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()); - retval.map_ty(UInt::from_canonical) - } - fn compile_cast_to_bits( - &mut self, - instantiated_module: InstantiatedModule, - expr: ops::CastToBits, - ) -> CompiledValue { - match Expr::ty(expr.arg()) { - CanonicalType::UInt(_) => { - self.compile_cast_scalar_to_bits(instantiated_module, expr.arg(), |arg| arg) - } - CanonicalType::SInt(ty) => self.compile_cast_scalar_to_bits( - instantiated_module, - expr.arg(), - |arg: Expr| arg.cast_to(ty.as_same_width_uint()), - ), - CanonicalType::Bool(_) - | CanonicalType::AsyncReset(_) - | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::Clock(_) => self.compile_cast_scalar_to_bits( - instantiated_module, - expr.arg(), - |arg: Expr| arg.cast_to(UInt[1]), - ), - CanonicalType::Array(ty) => self.compile_cast_aggregate_to_bits( - instantiated_module, - (0..ty.len()).map(|index| Expr::::from_canonical(expr.arg())[index]), - ), - CanonicalType::Enum(ty) => self - .simple_nary_big_expr( - instantiated_module, - UInt[ty.type_properties().bit_width].canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| vec![Insn::Copy { dest, src }], - ) - .map_ty(UInt::from_canonical), - CanonicalType::Bundle(ty) => self.compile_cast_aggregate_to_bits( - instantiated_module, - ty.fields().iter().map(|field| { - Expr::field(Expr::::from_canonical(expr.arg()), &field.name) - }), - ), - CanonicalType::PhantomConst(_) | CanonicalType::DynSimOnly(_) => { - self.compile_cast_aggregate_to_bits(instantiated_module, []) - } - } - } - fn compile_cast_bits_to_or_uninit( - &mut self, - instantiated_module: InstantiatedModule, - arg: Option>, - ty: CanonicalType, - ) -> CompiledValue { - let retval = match ty { - CanonicalType::UInt(ty) => Expr::canonical(arg.unwrap_or_else(|| ty.zero().to_expr())), - CanonicalType::SInt(ty) => { - Expr::canonical(arg.map_or_else(|| ty.zero().to_expr(), |arg| arg.cast_to(ty))) - } - CanonicalType::Bool(ty) => { - Expr::canonical(arg.map_or_else(|| false.to_expr(), |arg| arg.cast_to(ty))) - } - CanonicalType::Array(ty) => { - let stride = ty.element().bit_width(); - Expr::::canonical(match arg { - Some(arg) => ops::ArrayLiteral::new( - ty.element(), - Interned::from_iter((0..ty.len()).map(|index| { - let start = stride * index; - let end = start + stride; - arg[start..end].cast_bits_to(ty.element()) - })), - ) - .to_expr(), - None => repeat(ty.element().uninit(), ty.len()), - }) - } - ty @ CanonicalType::Enum(_) => { - return self.simple_nary_big_expr( - instantiated_module, - ty, - [Expr::canonical(arg.unwrap_or_else(|| { - UInt::new_dyn(ty.bit_width()).zero().to_expr() - }))], - |dest, [src]| vec![Insn::Copy { dest, src }], - ); - } - CanonicalType::Bundle(ty) => Expr::canonical( - ops::BundleLiteral::new( - ty, - Interned::from_iter(ty.field_offsets().iter().zip(&ty.fields()).map( - |(&offset, &field)| { - let OpaqueSimValueSize { - bit_width: offset, - sim_only_values_len: 0, - } = offset - else { - unreachable!(); - }; - let end = offset + field.ty.bit_width(); - match arg { - Some(arg) => arg[offset..end].cast_bits_to(field.ty), - None => field.ty.uninit(), - } - }, - )), - ) - .to_expr(), - ), - CanonicalType::AsyncReset(ty) => Expr::canonical( - arg.unwrap_or_else(|| UInt::new_dyn(1).zero().to_expr()) - .cast_to(ty), - ), - CanonicalType::SyncReset(ty) => Expr::canonical( - arg.unwrap_or_else(|| UInt::new_dyn(1).zero().to_expr()) - .cast_to(ty), - ), - CanonicalType::Reset(_) => unreachable!(), - CanonicalType::Clock(ty) => Expr::canonical( - arg.unwrap_or_else(|| UInt::new_dyn(1).zero().to_expr()) - .cast_to(ty), - ), - CanonicalType::PhantomConst(ty) => { - if let Some(arg) = arg { - let _ = self.compile_expr(instantiated_module, Expr::canonical(arg)); - } - Expr::canonical(ty.to_expr()) - } - CanonicalType::DynSimOnly(ty) => { - assert!(arg.is_none(), "can't cast bits to SimOnly"); - return self.compile_expr_helper(instantiated_module, ty.canonical(), |_, dest| { - assert_eq!(dest.len(), TypeLen::sim_only_slot()); - vec![] - }); - } - }; - let retval = self.compile_expr(instantiated_module, Expr::canonical(retval)); - self.compiled_expr_to_value(retval, instantiated_module.leaf_module().source_location()) - } - fn compile_aggregate_literal( - &mut self, - instantiated_module: InstantiatedModule, - dest_ty: CanonicalType, - inputs: Interned<[Expr]>, - ) -> CompiledValue { - self.compile_expr_helper(instantiated_module, dest_ty, |this, dest| { - let mut insns = Vec::new(); - let mut offset = TypeIndex::ZERO; - for input in inputs { - let input = this.compile_expr(instantiated_module, input); - let input = this - .compiled_expr_to_value( - input, - instantiated_module.leaf_module().source_location(), - ) - .range; - insns.extend( - input.insns_for_copy_to(dest.slice(TypeIndexRange::new(offset, input.len()))), - ); - offset = offset.offset(input.len().as_index()); - } - insns - }) - } - fn compile_expr( - &mut self, - instantiated_module: InstantiatedModule, - expr: Expr, - ) -> CompiledExpr { - if let Some(&retval) = self.compiled_exprs.get(&expr) { - return retval; - } - let mut cast_bit = |arg: Expr| { - let src_signed = match Expr::ty(arg) { - CanonicalType::UInt(_) => false, - CanonicalType::SInt(_) => true, - CanonicalType::Bool(_) => false, - CanonicalType::Array(_) => unreachable!(), - CanonicalType::Enum(_) => unreachable!(), - CanonicalType::Bundle(_) => unreachable!(), - CanonicalType::AsyncReset(_) => false, - CanonicalType::SyncReset(_) => false, - CanonicalType::Reset(_) => false, - CanonicalType::Clock(_) => false, - CanonicalType::PhantomConst(_) => unreachable!(), - CanonicalType::DynSimOnly(_) => unreachable!(), - }; - let dest_signed = match Expr::ty(expr) { - CanonicalType::UInt(_) => false, - CanonicalType::SInt(_) => true, - CanonicalType::Bool(_) => false, - CanonicalType::Array(_) => unreachable!(), - CanonicalType::Enum(_) => unreachable!(), - CanonicalType::Bundle(_) => unreachable!(), - CanonicalType::AsyncReset(_) => false, - CanonicalType::SyncReset(_) => false, - CanonicalType::Reset(_) => false, - CanonicalType::Clock(_) => false, - CanonicalType::PhantomConst(_) => unreachable!(), - CanonicalType::DynSimOnly(_) => unreachable!(), - }; - self.simple_nary_big_expr(instantiated_module, Expr::ty(expr), [arg], |dest, [src]| { - match (src_signed, dest_signed) { - (false, false) | (true, true) => { - vec![Insn::Copy { dest, src }] - } - (false, true) => vec![Insn::CastToSInt { - dest, - src, - dest_width: 1, - }], - (true, false) => vec![Insn::CastToUInt { - dest, - src, - dest_width: 1, - }], - } - }) - .into() - }; - let retval: CompiledExpr<_> = match *Expr::expr_enum(expr) { - ExprEnum::UIntLiteral(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [], - |dest, []| { - vec![Insn::Const { - dest, - value: expr.to_bigint().intern_sized(), - }] - }, - ) - .into(), - ExprEnum::SIntLiteral(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [], - |dest, []| { - vec![Insn::Const { - dest, - value: expr.to_bigint().intern_sized(), - }] - }, - ) - .into(), - ExprEnum::BoolLiteral(expr) => self - .simple_nary_big_expr(instantiated_module, Bool.canonical(), [], |dest, []| { - vec![Insn::Const { - dest, - value: BigInt::from(expr).intern_sized(), - }] - }) - .into(), - ExprEnum::PhantomConst(_) => self - .compile_aggregate_literal(instantiated_module, Expr::ty(expr), Interned::default()) - .into(), - ExprEnum::BundleLiteral(literal) => self - .compile_aggregate_literal( - instantiated_module, - Expr::ty(expr), - literal.field_values(), - ) - .into(), - ExprEnum::ArrayLiteral(literal) => self - .compile_aggregate_literal( - instantiated_module, - Expr::ty(expr), - literal.element_values(), - ) - .into(), - ExprEnum::EnumLiteral(expr) => { - let enum_bits_ty = UInt[expr.ty().type_properties().bit_width]; - let enum_bits = if let Some(variant_value) = expr.variant_value() { - ( - UInt[expr.ty().discriminant_bit_width()] - .from_int_wrapping(expr.variant_index()), - variant_value, - ) - .cast_to_bits() - .cast_to(enum_bits_ty) - } else { - enum_bits_ty - .from_int_wrapping(expr.variant_index()) - .to_expr() - }; - self.compile_expr( - instantiated_module, - enum_bits.cast_bits_to(expr.ty().canonical()), - ) - } - ExprEnum::Uninit(expr) => self - .compile_cast_bits_to_or_uninit(instantiated_module, None, expr.ty()) - .into(), - ExprEnum::NotU(expr) => self - .simple_nary_big_expr( - instantiated_module, - Expr::ty(expr.arg()).canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::NotU { - dest, - src, - width: Expr::ty(expr.arg()).width(), - }] - }, - ) - .into(), - ExprEnum::NotS(expr) => self - .simple_nary_big_expr( - instantiated_module, - Expr::ty(expr.arg()).canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| vec![Insn::NotS { dest, src }], - ) - .into(), - ExprEnum::NotB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Expr::ty(expr.arg()).canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::NotU { - dest, - src, - width: 1, - }] - }, - ) - .into(), - ExprEnum::Neg(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| vec![Insn::Neg { dest, src }], - ) - .into(), - ExprEnum::BitAndU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitAndS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitAndB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::And { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitOrU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitOrS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitOrB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Or { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitXorU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitXorS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], - ) - .into(), - ExprEnum::BitXorB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Xor { dest, lhs, rhs }], - ) - .into(), - ExprEnum::AddU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Add { dest, lhs, rhs }], - ) - .into(), - ExprEnum::AddS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Add { dest, lhs, rhs }], - ) - .into(), - ExprEnum::SubU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| { - vec![Insn::SubU { - dest, - lhs, - rhs, - dest_width: expr.ty().width(), - }] - }, - ) - .into(), - ExprEnum::SubS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::SubS { dest, lhs, rhs }], - ) - .into(), - ExprEnum::MulU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Mul { dest, lhs, rhs }], - ) - .into(), - ExprEnum::MulS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Mul { dest, lhs, rhs }], - ) - .into(), - ExprEnum::DivU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Div { dest, lhs, rhs }], - ) - .into(), - ExprEnum::DivS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Div { dest, lhs, rhs }], - ) - .into(), - ExprEnum::RemU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Rem { dest, lhs, rhs }], - ) - .into(), - ExprEnum::RemS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::Rem { dest, lhs, rhs }], - ) - .into(), - ExprEnum::DynShlU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::DynShl { dest, lhs, rhs }], - ) - .into(), - ExprEnum::DynShlS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::DynShl { dest, lhs, rhs }], - ) - .into(), - ExprEnum::DynShrU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::DynShr { dest, lhs, rhs }], - ) - .into(), - ExprEnum::DynShrS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::DynShr { dest, lhs, rhs }], - ) - .into(), - ExprEnum::FixedShlU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs())], - |dest, [lhs]| { - vec![Insn::Shl { - dest, - lhs, - rhs: expr.rhs(), - }] - }, - ) - .into(), - ExprEnum::FixedShlS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs())], - |dest, [lhs]| { - vec![Insn::Shl { - dest, - lhs, - rhs: expr.rhs(), - }] - }, - ) - .into(), - ExprEnum::FixedShrU(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs())], - |dest, [lhs]| { - vec![Insn::Shr { - dest, - lhs, - rhs: expr.rhs(), - }] - }, - ) - .into(), - ExprEnum::FixedShrS(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.lhs())], - |dest, [lhs]| { - vec![Insn::Shr { - dest, - lhs, - rhs: expr.rhs(), - }] - }, - ) - .into(), - ExprEnum::CmpLtB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpLeB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpGtB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - // swap both comparison direction and lhs/rhs - [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpGeB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - // swap both comparison direction and lhs/rhs - [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpEqB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpNeB(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpLtU(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpLeU(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpGtU(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - // swap both comparison direction and lhs/rhs - [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpGeU(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - // swap both comparison direction and lhs/rhs - [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpEqU(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpNeU(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpLtS(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpLeS(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpGtS(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - // swap both comparison direction and lhs/rhs - [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLt { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpGeS(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - // swap both comparison direction and lhs/rhs - [Expr::canonical(expr.rhs()), Expr::canonical(expr.lhs())], - |dest, [lhs, rhs]| vec![Insn::CmpLe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpEqS(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpEq { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CmpNeS(expr) => self - .simple_nary_big_expr( - instantiated_module, - Bool.canonical(), - [Expr::canonical(expr.lhs()), Expr::canonical(expr.rhs())], - |dest, [lhs, rhs]| vec![Insn::CmpNe { dest, lhs, rhs }], - ) - .into(), - ExprEnum::CastUIntToUInt(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::CastToUInt { - dest, - src, - dest_width: expr.ty().width(), - }] - }, - ) - .into(), - ExprEnum::CastUIntToSInt(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::CastToSInt { - dest, - src, - dest_width: expr.ty().width(), - }] - }, - ) - .into(), - ExprEnum::CastSIntToUInt(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::CastToUInt { - dest, - src, - dest_width: expr.ty().width(), - }] - }, - ) - .into(), - ExprEnum::CastSIntToSInt(expr) => self - .simple_nary_big_expr( - instantiated_module, - expr.ty().canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::CastToSInt { - dest, - src, - dest_width: expr.ty().width(), - }] - }, - ) - .into(), - ExprEnum::CastBoolToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastBoolToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastUIntToBool(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSIntToBool(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastBoolToSyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastUIntToSyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSIntToSyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastBoolToAsyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastUIntToAsyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSIntToAsyncReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSyncResetToBool(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSyncResetToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSyncResetToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSyncResetToReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastAsyncResetToBool(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastAsyncResetToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastAsyncResetToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastAsyncResetToReset(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastResetToBool(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastResetToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastResetToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastBoolToClock(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastUIntToClock(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastSIntToClock(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastClockToBool(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastClockToUInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::CastClockToSInt(expr) => cast_bit(Expr::canonical(expr.arg())), - ExprEnum::FieldAccess(expr) => self - .compile_expr(instantiated_module, Expr::canonical(expr.base())) - .map_ty(Bundle::from_canonical) - .field_by_index(expr.field_index()), - ExprEnum::VariantAccess(variant_access) => { - let start = Expr::ty(variant_access.base()).discriminant_bit_width(); - let len = Expr::ty(expr).bit_width(); - self.compile_expr( - instantiated_module, - variant_access.base().cast_to_bits()[start..start + len] - .cast_bits_to(Expr::ty(expr)), - ) - } - ExprEnum::ArrayIndex(expr) => self - .compile_expr(instantiated_module, Expr::canonical(expr.base())) - .map_ty(Array::from_canonical) - .element(expr.element_index()), - ExprEnum::DynArrayIndex(expr) => { - let element_index = - self.compile_expr(instantiated_module, Expr::canonical(expr.element_index())); - let element_index = self.compiled_expr_to_value( - element_index, - instantiated_module.leaf_module().source_location(), - ); - let index_slot = self.compiled_value_to_dyn_array_index( - element_index.map_ty(UInt::from_canonical), - instantiated_module.leaf_module().source_location(), - ); - self.compile_expr(instantiated_module, Expr::canonical(expr.base())) - .map_ty(Array::from_canonical) - .element_dyn(index_slot) - } - ExprEnum::ReduceBitAndU(expr) => if Expr::ty(expr.arg()).width() == 0 { - self.compile_expr(instantiated_module, Expr::canonical(true.to_expr())) - } else { - self.compile_expr( - instantiated_module, - Expr::canonical( - expr.arg() - .cmp_eq(Expr::ty(expr.arg()).from_int_wrapping(-1)), - ), - ) - } - .into(), - ExprEnum::ReduceBitAndS(expr) => if Expr::ty(expr.arg()).width() == 0 { - self.compile_expr(instantiated_module, Expr::canonical(true.to_expr())) - } else { - self.compile_expr( - instantiated_module, - Expr::canonical( - expr.arg() - .cmp_eq(Expr::ty(expr.arg()).from_int_wrapping(-1)), - ), - ) - } - .into(), - ExprEnum::ReduceBitOrU(expr) => if Expr::ty(expr.arg()).width() == 0 { - self.compile_expr(instantiated_module, Expr::canonical(false.to_expr())) - } else { - self.compile_expr( - instantiated_module, - Expr::canonical(expr.arg().cmp_ne(Expr::ty(expr.arg()).from_int_wrapping(0))), - ) - } - .into(), - ExprEnum::ReduceBitOrS(expr) => if Expr::ty(expr.arg()).width() == 0 { - self.compile_expr(instantiated_module, Expr::canonical(false.to_expr())) - } else { - self.compile_expr( - instantiated_module, - Expr::canonical(expr.arg().cmp_ne(Expr::ty(expr.arg()).from_int_wrapping(0))), - ) - } - .into(), - ExprEnum::ReduceBitXorU(expr) => self - .simple_nary_big_expr( - instantiated_module, - UInt::<1>::TYPE.canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::ReduceBitXor { - dest, - src, - input_width: Expr::ty(expr.arg()).width(), - }] - }, - ) - .into(), - ExprEnum::ReduceBitXorS(expr) => self - .simple_nary_big_expr( - instantiated_module, - UInt::<1>::TYPE.canonical(), - [Expr::canonical(expr.arg())], - |dest, [src]| { - vec![Insn::ReduceBitXor { - dest, - src, - input_width: Expr::ty(expr.arg()).width(), - }] - }, - ) - .into(), - ExprEnum::SliceUInt(expr) => self - .simple_nary_big_expr( - instantiated_module, - UInt::new_dyn(expr.range().len()).canonical(), - [Expr::canonical(expr.base())], - |dest, [src]| { - vec![Insn::SliceInt { - dest, - src, - start: expr.range().start, - len: expr.range().len(), - }] - }, - ) - .into(), - ExprEnum::SliceSInt(expr) => self - .simple_nary_big_expr( - instantiated_module, - UInt::new_dyn(expr.range().len()).canonical(), - [Expr::canonical(expr.base())], - |dest, [src]| { - vec![Insn::SliceInt { - dest, - src, - start: expr.range().start, - len: expr.range().len(), - }] - }, - ) - .into(), - ExprEnum::CastToBits(expr) => self - .compile_cast_to_bits(instantiated_module, expr) - .map_ty(CanonicalType::UInt) - .into(), - ExprEnum::CastBitsTo(expr) => self - .compile_cast_bits_to_or_uninit(instantiated_module, Some(expr.arg()), expr.ty()) - .into(), - ExprEnum::ModuleIO(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) - .into(), - ExprEnum::Instance(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) - .into(), - ExprEnum::Wire(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) - .into(), - ExprEnum::Reg(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) - .into(), - ExprEnum::RegSync(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) - .into(), - ExprEnum::RegAsync(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) - .into(), - ExprEnum::MemPort(expr) => self - .compile_value(TargetInInstantiatedModule { - instantiated_module, - target: expr.into(), - }) - .into(), - }; - self.compiled_exprs.insert(expr, retval); - retval - } - fn compile_connect( - &mut self, - lhs_instantiated_module: InstantiatedModule, - lhs_conditions: Interned<[Cond]>, - lhs: Expr, - rhs_instantiated_module: InstantiatedModule, - rhs_conditions: Interned<[Cond]>, - mut rhs: Expr, - source_location: SourceLocation, - ) { - if Expr::ty(lhs) != Expr::ty(rhs) || !Expr::ty(lhs).is_passive() { - match Expr::ty(lhs) { - CanonicalType::UInt(lhs_ty) => { - rhs = Expr::canonical(Expr::::from_canonical(rhs).cast_to(lhs_ty)); - } - CanonicalType::SInt(lhs_ty) => { - rhs = Expr::canonical(Expr::::from_canonical(rhs).cast_to(lhs_ty)); - } - CanonicalType::Bool(_) => unreachable!(), - CanonicalType::Array(lhs_ty) => { - let CanonicalType::Array(rhs_ty) = Expr::ty(rhs) else { - unreachable!(); - }; - assert_eq!(lhs_ty.len(), rhs_ty.len()); - let lhs = Expr::::from_canonical(lhs); - let rhs = Expr::::from_canonical(rhs); - for index in 0..lhs_ty.len() { - self.compile_connect( - lhs_instantiated_module, - lhs_conditions, - lhs[index], - rhs_instantiated_module, - rhs_conditions, - rhs[index], - source_location, - ); - } - return; - } - CanonicalType::Enum(lhs_ty) => { - let CanonicalType::Enum(rhs_ty) = Expr::ty(rhs) else { - unreachable!(); - }; - todo!("handle connect with different enum types"); - } - CanonicalType::Bundle(lhs_ty) => { - let CanonicalType::Bundle(rhs_ty) = Expr::ty(rhs) else { - unreachable!(); - }; - assert_eq!(lhs_ty.fields().len(), rhs_ty.fields().len()); - let lhs = Expr::::from_canonical(lhs); - let rhs = Expr::::from_canonical(rhs); - for ( - field_index, - ( - BundleField { - name, - flipped, - ty: _, - }, - rhs_field, - ), - ) in lhs_ty.fields().into_iter().zip(rhs_ty.fields()).enumerate() - { - assert_eq!(name, rhs_field.name); - assert_eq!(flipped, rhs_field.flipped); - let lhs_expr = ops::FieldAccess::new_by_index(lhs, field_index).to_expr(); - let rhs_expr = ops::FieldAccess::new_by_index(rhs, field_index).to_expr(); - if flipped { - // swap lhs/rhs - self.compile_connect( - rhs_instantiated_module, - rhs_conditions, - rhs_expr, - lhs_instantiated_module, - lhs_conditions, - lhs_expr, - source_location, - ); - } else { - self.compile_connect( - lhs_instantiated_module, - lhs_conditions, - lhs_expr, - rhs_instantiated_module, - rhs_conditions, - rhs_expr, - source_location, - ); - } - } - return; - } - CanonicalType::AsyncReset(_) => unreachable!(), - CanonicalType::SyncReset(_) => unreachable!(), - CanonicalType::Reset(_) => unreachable!(), - CanonicalType::Clock(_) => unreachable!(), - CanonicalType::PhantomConst(_) => unreachable!("PhantomConst mismatch"), - CanonicalType::DynSimOnly(_) => { - unreachable!("DynSimOnly mismatch"); - } - } - } - let Some(target) = lhs.target() else { - unreachable!("connect lhs must have target"); - }; - let lhs_decl_conditions = self.decl_conditions[&TargetInInstantiatedModule { - instantiated_module: lhs_instantiated_module, - target: target.base().into(), - }]; - let lhs = self.compile_expr(lhs_instantiated_module, lhs); - let rhs = self.compile_expr(rhs_instantiated_module, rhs); - let rhs = self.compiled_expr_to_value(rhs, source_location); - self.compile_simple_connect( - lhs_conditions[lhs_decl_conditions.len()..].intern(), - lhs, - rhs, - source_location, - ); - } - fn compile_clock( - &mut self, - clk: CompiledValue, - source_location: SourceLocation, - ) -> ClockTrigger { - if let Some(&retval) = self.compiled_value_to_clock_trigger_map.get(&clk) { - return retval; - } - let mut alloc_small_slot = |part_name: &str| { - self.insns - .state_layout - .ty - .small_slots - .allocate(&StatePartLayout::scalar( - SlotDebugData { - name: Interned::default(), - ty: Bool.canonical(), - }, - (), - )) - .start - }; - let last_clk_was_low = alloc_small_slot("last_clk_was_low"); - let clk_triggered = alloc_small_slot("clk_triggered"); - let retval = ClockTrigger { - last_clk_was_low, - clk: self.compiled_value_bool_dest_is_small( - clk.map_ty(CanonicalType::Clock), - source_location, - ), - clk_triggered, - source_location, - }; - self.add_assignment( - Interned::default(), - [Insn::AndSmall { - dest: clk_triggered, - lhs: retval.clk, - rhs: last_clk_was_low, - }], - source_location, - ); - self.clock_triggers.push(retval); - self.compiled_value_to_clock_trigger_map.insert(clk, retval); - retval - } - fn compile_enum_discriminant( - &mut self, - enum_value: CompiledValue, - source_location: SourceLocation, - ) -> StatePartIndex { - if let Some(&retval) = self.enum_discriminants.get(&enum_value) { - return retval; - } - let retval_ty = Enum::new( - enum_value - .layout - .ty - .variants() - .iter() - .map(|variant| EnumVariant { - name: variant.name, - ty: None, - }) - .collect(), - ); - let retval = if retval_ty == enum_value.layout.ty - && enum_value.range.len() == TypeLen::small_slot() - { - enum_value.range.small_slots.start - } else { - let retval = self - .insns - .state_layout - .ty - .small_slots - .allocate(&StatePartLayout::scalar( - SlotDebugData { - name: Interned::default(), - ty: retval_ty.canonical(), - }, - (), - )) - .start; - let discriminant_bit_width = enum_value.layout.ty.discriminant_bit_width(); - let discriminant_mask = !(!0u64 << discriminant_bit_width); - let insn = match enum_value.range.len().as_single() { - Some(TypeLenSingle::BigSlot) => Insn::AndBigWithSmallImmediate { - dest: retval, - lhs: enum_value.range.big_slots.start, - rhs: discriminant_mask, - }, - Some(TypeLenSingle::SmallSlot) => { - if discriminant_bit_width == enum_value.layout.ty.type_properties().bit_width { - Insn::CopySmall { - dest: retval, - src: enum_value.range.small_slots.start, - } - } else { - Insn::AndSmallImmediate { - dest: retval, - lhs: enum_value.range.small_slots.start, - rhs: discriminant_mask, - } - } - } - Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(), - }; - self.add_assignment(Interned::default(), [insn], source_location); - retval - }; - self.enum_discriminants.insert(enum_value, retval); - retval - } - fn compile_stmt_reg( - &mut self, - stmt_reg: StmtReg, - instantiated_module: InstantiatedModule, - value: CompiledValue, - ) { - let StmtReg { annotations, reg } = stmt_reg; - let clk = self.compile_expr(instantiated_module, Expr::canonical(reg.clock_domain().clk)); - let clk = self - .compiled_expr_to_value(clk, reg.source_location()) - .map_ty(Clock::from_canonical); - let clk = self.compile_clock(clk, reg.source_location()); - struct Dispatch; - impl ResetTypeDispatch for Dispatch { - type Input = (); - - type Output = bool; - - fn reset(self, _input: Self::Input) -> Self::Output { - unreachable!() - } - - fn sync_reset(self, _input: Self::Input) -> Self::Output { - false - } - - fn async_reset(self, _input: Self::Input) -> Self::Output { - true - } - } - let reset = if let Some(init) = reg.init() { - let init = self.compile_expr(instantiated_module, init); - let init = self.compiled_expr_to_value(init, reg.source_location()); - let rst = - self.compile_expr(instantiated_module, Expr::canonical(reg.clock_domain().rst)); - let rst = self.compiled_expr_to_value(rst, reg.source_location()); - let rst = self.compiled_value_bool_dest_is_small(rst, reg.source_location()); - let is_async = R::dispatch((), Dispatch); - if is_async { - let cond = Expr::canonical(reg.clock_domain().rst.cast_to(Bool)); - let cond = self.compile_expr(instantiated_module, cond); - let cond = self.compiled_expr_to_value(cond, reg.source_location()); - let cond = cond.map_ty(Bool::from_canonical); - // write to the register's current value since asynchronous reset is combinational - let lhs = CompiledValue { - layout: value.layout, - range: value.range, - write: None, - } - .into(); - self.compile_simple_connect( - [Cond { - body: CondBody::IfTrue { cond }, - source_location: reg.source_location(), - }] - .intern_slice(), - lhs, - init, - reg.source_location(), - ); - } - Some(RegisterReset { - is_async, - init, - rst, - }) - } else { - None - }; - self.registers.push(Register { - value, - clk_triggered: clk.clk_triggered, - reset, - source_location: reg.source_location(), - }); - } - fn compile_declaration( - &mut self, - declaration: StmtDeclaration, - parent_module: Interned, - conditions: Interned<[Cond]>, - ) -> TraceDecl { - let target_base: TargetBase = match &declaration { - StmtDeclaration::Wire(v) => v.wire.into(), - StmtDeclaration::Reg(v) => v.reg.into(), - StmtDeclaration::RegSync(v) => v.reg.into(), - StmtDeclaration::RegAsync(v) => v.reg.into(), - StmtDeclaration::Instance(v) => v.instance.into(), - }; - let target = TargetInInstantiatedModule { - instantiated_module: *parent_module, - target: target_base.into(), - }; - self.decl_conditions.insert(target, conditions); - let compiled_value = self.compile_value(target); - match declaration { - StmtDeclaration::Wire(StmtWire { annotations, wire }) => {} - StmtDeclaration::Reg(_) => { - unreachable!("Reset types were already replaced by SyncReset or AsyncReset"); - } - StmtDeclaration::RegSync(stmt_reg) => { - self.compile_stmt_reg(stmt_reg, *parent_module, compiled_value) - } - StmtDeclaration::RegAsync(stmt_reg) => { - self.compile_stmt_reg(stmt_reg, *parent_module, compiled_value) - } - StmtDeclaration::Instance(StmtInstance { - annotations, - instance, - }) => { - let inner_instantiated_module = InstantiatedModule::Child { - parent: parent_module, - instance: instance.intern_sized(), - } - .intern_sized(); - let instance_expr = instance.to_expr(); - self.compile_module(inner_instantiated_module); - for (field_index, module_io) in - instance.instantiated().module_io().into_iter().enumerate() - { - let instance_field = - ops::FieldAccess::new_by_index(instance_expr, field_index).to_expr(); - match Expr::flow(instance_field) { - Flow::Source => { - // we need to supply the value to the instance since the - // parent module expects to read from the instance - self.compile_connect( - *parent_module, - conditions, - instance_field, - *inner_instantiated_module, - Interned::default(), - module_io.module_io.to_expr(), - instance.source_location(), - ); - } - Flow::Sink => { - // we need to take the value from the instance since the - // parent module expects to write to the instance - self.compile_connect( - *inner_instantiated_module, - Interned::default(), - module_io.module_io.to_expr(), - *parent_module, - conditions, - instance_field, - instance.source_location(), - ); - } - Flow::Duplex => unreachable!(), - } - } - } - } - self.make_trace_decl(*parent_module, target_base) - } - fn allocate_delay_chain( - &mut self, - len: usize, - layout: &TypeLayout, - first: Option, - last: Option, - mut from_allocation: impl FnMut(TypeIndexRange) -> T, - ) -> Vec { - match (len, first, last) { - (0, _, _) => Vec::new(), - (1, Some(v), _) | (1, None, Some(v)) => vec![v], - (2, Some(first), Some(last)) => vec![first, last], - (len, first, last) => { - let inner_len = len - first.is_some() as usize - last.is_some() as usize; - first - .into_iter() - .chain( - (0..inner_len) - .map(|_| from_allocation(self.insns.allocate_variable(layout))), - ) - .chain(last) - .collect() - } - } - } - fn allocate_delay_chain_small( - &mut self, - len: usize, - ty: CanonicalType, - first: Option>, - last: Option>, - ) -> Vec> { - self.allocate_delay_chain( - len, - &TypeLayout { - small_slots: StatePartLayout::scalar( - SlotDebugData { - name: Interned::default(), - ty, - }, - (), - ), - ..TypeLayout::empty() - }, - first, - last, - |range| range.small_slots.start, - ) - } - fn compile_memory_port_rw_helper( - &mut self, - memory: StatePartIndex, - stride: usize, - mut start: usize, - data_layout: CompiledTypeLayout, - mask_layout: CompiledTypeLayout, - mut read: Option>, - mut write: Option>, - ) { - match data_layout.body { - CompiledTypeLayoutBody::Scalar => { - let CompiledTypeLayoutBody::Scalar = mask_layout.body else { - unreachable!(); - }; - let signed = match data_layout.ty { - CanonicalType::UInt(_) => false, - CanonicalType::SInt(_) => true, - CanonicalType::Bool(_) => false, - CanonicalType::Array(_) => unreachable!(), - CanonicalType::Enum(_) => false, - CanonicalType::Bundle(_) => unreachable!(), - CanonicalType::AsyncReset(_) => false, - CanonicalType::SyncReset(_) => false, - CanonicalType::Reset(_) => false, - CanonicalType::Clock(_) => false, - CanonicalType::PhantomConst(_) => unreachable!(), - CanonicalType::DynSimOnly(_) => false, - }; - let width = data_layout.ty.bit_width(); - if let Some(MemoryPortReadInsns { - addr, - en: _, - write_mode: _, - data, - insns, - }) = read - { - insns.push( - match data.len().as_single() { - Some(TypeLenSingle::BigSlot) => { - let dest = data.big_slots.start; - if signed { - Insn::MemoryReadSInt { - dest, - memory, - addr, - stride, - start, - width, - } - } else { - Insn::MemoryReadUInt { - dest, - memory, - addr, - stride, - start, - width, - } - } - } - Some(TypeLenSingle::SmallSlot) => { - let _dest = data.small_slots.start; - todo!("memory ports' data are always big for now"); - } - Some(TypeLenSingle::SimOnlySlot) => { - todo!("memory containing sim-only values"); - } - None => unreachable!(), - } - .into(), - ); - } - if let Some(MemoryPortWriteInsns { - addr, - en: _, - write_mode: _, - data, - mask, - insns, - }) = write - { - let end_label = self.insns.new_label(); - insns.push( - match mask.len().as_single() { - Some(TypeLenSingle::BigSlot) => Insn::BranchIfZero { - target: end_label.0, - value: mask.big_slots.start, - }, - Some(TypeLenSingle::SmallSlot) => Insn::BranchIfSmallZero { - target: end_label.0, - value: mask.small_slots.start, - }, - Some(TypeLenSingle::SimOnlySlot) | None => unreachable!(), - } - .into(), - ); - insns.push( - match data.len().as_single() { - Some(TypeLenSingle::BigSlot) => { - let value = data.big_slots.start; - if signed { - Insn::MemoryWriteSInt { - value, - memory, - addr, - stride, - start, - width, - } - } else { - Insn::MemoryWriteUInt { - value, - memory, - addr, - stride, - start, - width, - } - } - } - Some(TypeLenSingle::SmallSlot) => { - let _value = data.small_slots.start; - todo!("memory ports' data are always big for now"); - } - Some(TypeLenSingle::SimOnlySlot) => { - todo!("memory containing sim-only values"); - } - None => unreachable!(), - } - .into(), - ); - insns.push(end_label.into()); - } - } - CompiledTypeLayoutBody::Array { element } => { - let CompiledTypeLayoutBody::Array { - element: mask_element, - } = mask_layout.body - else { - unreachable!(); - }; - let ty = ::from_canonical(data_layout.ty); - let element_bit_width = ty.element().bit_width(); - let element_size = element.layout.len(); - let mask_element_size = mask_element.layout.len(); - for element_index in 0..ty.len() { - self.compile_memory_port_rw_helper( - memory, - stride, - start, - *element, - *mask_element, - read.as_mut().map( - |MemoryPortReadInsns { - addr, - en, - write_mode, - data, - insns, - }| MemoryPortReadInsns { - addr: *addr, - en: *en, - write_mode: *write_mode, - data: data.index_array(element_size, element_index), - insns, - }, - ), - write.as_mut().map( - |MemoryPortWriteInsns { - addr, - en, - write_mode, - data, - mask, - insns, - }| { - MemoryPortWriteInsns { - addr: *addr, - en: *en, - write_mode: *write_mode, - data: data.index_array(element_size, element_index), - mask: mask.index_array(mask_element_size, element_index), - insns, - } - }, - ), - ); - start += element_bit_width; - } - } - CompiledTypeLayoutBody::Bundle { fields } => { - let CompiledTypeLayoutBody::Bundle { - fields: mask_fields, - } = mask_layout.body - else { - unreachable!(); - }; - assert_eq!(fields.len(), mask_fields.len()); - for (field, mask_field) in fields.into_iter().zip(mask_fields) { - let field_index_range = - TypeIndexRange::new(field.offset, field.ty.layout.len()); - let mask_field_index_range = - TypeIndexRange::new(mask_field.offset, mask_field.ty.layout.len()); - self.compile_memory_port_rw_helper( - memory, - stride, - start, - field.ty, - mask_field.ty, - read.as_mut().map( - |MemoryPortReadInsns { - addr, - en, - write_mode, - data, - insns, - }| MemoryPortReadInsns { - addr: *addr, - en: *en, - write_mode: *write_mode, - data: data.slice(field_index_range), - insns, - }, - ), - write.as_mut().map( - |MemoryPortWriteInsns { - addr, - en, - write_mode, - data, - mask, - insns, - }| { - MemoryPortWriteInsns { - addr: *addr, - en: *en, - write_mode: *write_mode, - data: data.slice(field_index_range), - mask: mask.slice(mask_field_index_range), - insns, - } - }, - ), - ); - start = start + field.ty.ty.bit_width(); - } - } - } - } - fn compile_memory_port_rw( - &mut self, - memory: StatePartIndex, - data_layout: CompiledTypeLayout, - mask_layout: CompiledTypeLayout, - mut read: Option>, - mut write: Option>, - ) { - let read_else_label = read.as_mut().map( - |MemoryPortReadInsns { - addr: _, - en, - write_mode, - data: _, - insns, - }| { - let else_label = self.insns.new_label(); - insns.push( - Insn::BranchIfSmallZero { - target: else_label.0, - value: *en, - } - .into(), - ); - if let Some(write_mode) = *write_mode { - insns.push( - Insn::BranchIfSmallNonZero { - target: else_label.0, - value: write_mode, - } - .into(), - ); - } - else_label - }, - ); - let write_end_label = write.as_mut().map( - |MemoryPortWriteInsns { - addr: _, - en, - write_mode, - data: _, - mask: _, - insns, - }| { - let end_label = self.insns.new_label(); - insns.push( - Insn::BranchIfSmallZero { - target: end_label.0, - value: *en, - } - .into(), - ); - if let Some(write_mode) = *write_mode { - insns.push( - Insn::BranchIfSmallZero { - target: end_label.0, - value: write_mode, - } - .into(), - ); - } - end_label - }, - ); - self.compile_memory_port_rw_helper( - memory, - data_layout.ty.bit_width(), - 0, - data_layout, - mask_layout, - read.as_mut().map( - |MemoryPortReadInsns { - addr, - en, - write_mode, - data, - insns, - }| MemoryPortReadInsns { - addr: *addr, - en: *en, - write_mode: *write_mode, - data: *data, - insns: *insns, - }, - ), - write.as_mut().map( - |MemoryPortWriteInsns { - addr, - en, - write_mode, - data, - mask, - insns, - }| MemoryPortWriteInsns { - addr: *addr, - en: *en, - write_mode: *write_mode, - data: *data, - mask: *mask, - insns: *insns, - }, - ), - ); - if let ( - Some(else_label), - Some(MemoryPortReadInsns { - addr: _, - en: _, - write_mode: _, - data, - insns, - }), - ) = (read_else_label, read) - { - let end_label = self.insns.new_label(); - insns.push( - Insn::Branch { - target: end_label.0, - } - .into(), - ); - insns.push(else_label.into()); - let TypeIndexRange { - small_slots, - big_slots, - sim_only_slots, - } = data; - for dest in small_slots.iter() { - insns.push(Insn::ConstSmall { dest, value: 0 }.into()); - } - for dest in big_slots.iter() { - insns.push( - Insn::Const { - dest, - value: BigInt::ZERO.intern_sized(), - } - .into(), - ); - } - for _dest in sim_only_slots.iter() { - todo!("memory containing sim-only values"); - } - insns.push(end_label.into()); - } - if let (Some(end_label), Some(write)) = (write_end_label, write) { - write.insns.push(end_label.into()); - } - } - fn compile_memory( - &mut self, - mem: Mem, - instantiated_module: InstantiatedModule, - conditions: Interned<[Cond]>, - trace_decls: &mut Vec, - ) { - let data_layout = CompiledTypeLayout::get(mem.array_type().element()); - let mask_layout = CompiledTypeLayout::get(mem.array_type().element().mask_type()); - let read_latency_plus_1 = mem - .read_latency() - .checked_add(1) - .expect("read latency too big"); - let write_latency_plus_1 = mem - .write_latency() - .get() - .checked_add(1) - .expect("write latency too big"); - let read_cycle = match mem.read_under_write() { - ReadUnderWrite::Old => 0, - ReadUnderWrite::New => mem.read_latency(), - ReadUnderWrite::Undefined => mem.read_latency() / 2, // something other than Old or New - }; - let memory = self - .insns - .state_layout - .memories - .allocate(&StatePartLayout::scalar( - (), - MemoryData { - array_type: mem.array_type(), - data: mem.initial_value().unwrap_or_else(|| { - Intern::intern_owned(BitVec::repeat( - false, - mem.array_type().type_properties().bit_width, - )) - }), - }, - )) - .start; - let (ports, trace_ports) = mem - .ports() - .iter() - .map(|&port| { - let target_base = TargetBase::MemPort(port); - let target = TargetInInstantiatedModule { - instantiated_module, - target: target_base.into(), - }; - self.decl_conditions.insert(target, conditions); - let TraceDecl::Scope(TraceScope::MemPort(trace_port)) = - self.make_trace_decl(instantiated_module, target_base) - else { - unreachable!(); - }; - let clk = Expr::field(port.to_expr(), "clk"); - let clk = self.compile_expr(instantiated_module, clk); - let clk = self.compiled_expr_to_value(clk, mem.source_location()); - let clk_triggered = self - .compile_clock(clk.map_ty(Clock::from_canonical), mem.source_location()) - .clk_triggered; - let en = Expr::field(port.to_expr(), "en"); - let en = self.compile_expr(instantiated_module, en); - let en = self.compiled_expr_to_value(en, mem.source_location()); - let en = self.compiled_value_bool_dest_is_small(en, mem.source_location()); - let addr = Expr::field(port.to_expr(), "addr"); - let addr = self.compile_expr(instantiated_module, addr); - let addr = self.compiled_expr_to_value(addr, mem.source_location()); - let addr_ty = addr.layout.ty; - let addr = self.compiled_value_to_dyn_array_index( - addr.map_ty(UInt::from_canonical), - mem.source_location(), - ); - let read_data = port.port_kind().rdata_name().map(|name| { - let read_data = - self.compile_expr(instantiated_module, Expr::field(port.to_expr(), name)); - let read_data = self.compiled_expr_to_value(read_data, mem.source_location()); - read_data.range - }); - let write_data = port.port_kind().wdata_name().map(|name| { - let write_data = - self.compile_expr(instantiated_module, Expr::field(port.to_expr(), name)); - let write_data = self.compiled_expr_to_value(write_data, mem.source_location()); - write_data.range - }); - let write_mask = port.port_kind().wmask_name().map(|name| { - let write_mask = - self.compile_expr(instantiated_module, Expr::field(port.to_expr(), name)); - let write_mask = self.compiled_expr_to_value(write_mask, mem.source_location()); - write_mask.range - }); - let write_mode = port.port_kind().wmode_name().map(|name| { - let write_mode = - self.compile_expr(instantiated_module, Expr::field(port.to_expr(), name)); - let write_mode = self.compiled_expr_to_value(write_mode, mem.source_location()); - self.compiled_value_bool_dest_is_small(write_mode, mem.source_location()) - }); - struct PortParts { - en_delayed_len: usize, - addr_delayed_len: usize, - read_data_delayed_len: usize, - write_data_delayed_len: usize, - write_mask_delayed_len: usize, - write_mode_delayed_len: usize, - read_cycle: Option, - write_cycle: Option, - } - let PortParts { - en_delayed_len, - addr_delayed_len, - read_data_delayed_len, - write_data_delayed_len, - write_mask_delayed_len, - write_mode_delayed_len, - read_cycle, - write_cycle, - } = match port.port_kind() { - PortKind::ReadOnly => PortParts { - en_delayed_len: read_cycle + 1, - addr_delayed_len: read_cycle + 1, - read_data_delayed_len: read_latency_plus_1 - read_cycle, - write_data_delayed_len: 0, - write_mask_delayed_len: 0, - write_mode_delayed_len: 0, - read_cycle: Some(read_cycle), - write_cycle: None, - }, - PortKind::WriteOnly => PortParts { - en_delayed_len: write_latency_plus_1, - addr_delayed_len: write_latency_plus_1, - read_data_delayed_len: 0, - write_data_delayed_len: write_latency_plus_1, - write_mask_delayed_len: write_latency_plus_1, - write_mode_delayed_len: 0, - read_cycle: None, - write_cycle: Some(mem.write_latency().get()), - }, - PortKind::ReadWrite => { - let can_rw_at_end = match mem.read_under_write() { - ReadUnderWrite::Old => false, - ReadUnderWrite::New | ReadUnderWrite::Undefined => true, - }; - let latency_plus_1 = read_latency_plus_1; - if latency_plus_1 != write_latency_plus_1 || !can_rw_at_end { - todo!( - "not sure what to do, issue: \ - https://github.com/chipsalliance/firrtl-spec/issues/263" - ); - } - PortParts { - en_delayed_len: latency_plus_1, - addr_delayed_len: latency_plus_1, - read_data_delayed_len: 1, - write_data_delayed_len: latency_plus_1, - write_mask_delayed_len: latency_plus_1, - write_mode_delayed_len: latency_plus_1, - read_cycle: Some(latency_plus_1 - 1), - write_cycle: Some(latency_plus_1 - 1), - } - } - }; - let addr_delayed = self.allocate_delay_chain_small( - addr_delayed_len, - addr_ty.canonical(), - Some(addr), - None, - ); - let en_delayed = self.allocate_delay_chain_small( - en_delayed_len, - Bool.canonical(), - Some(en), - None, - ); - let read_data_delayed = self.allocate_delay_chain( - read_data_delayed_len, - &data_layout.layout, - None, - read_data, - |v| v, - ); - let write_data_delayed = self.allocate_delay_chain( - write_data_delayed_len, - &data_layout.layout, - write_data, - None, - |v| v, - ); - let write_mask_delayed = self.allocate_delay_chain( - write_mask_delayed_len, - &mask_layout.layout, - write_mask, - None, - |v| v, - ); - let write_mode_delayed = self.allocate_delay_chain_small( - write_mode_delayed_len, - Bool.canonical(), - write_mode, - None, - ); - let mut read_insns = Vec::new(); - let mut write_insns = Vec::new(); - self.compile_memory_port_rw( - memory, - data_layout, - mask_layout, - read_cycle.map(|read_cycle| MemoryPortReadInsns { - addr: addr_delayed[read_cycle], - en: en_delayed[read_cycle], - write_mode: write_mode_delayed.get(read_cycle).copied(), - data: read_data_delayed[0], - insns: &mut read_insns, - }), - write_cycle.map(|write_cycle| MemoryPortWriteInsns { - addr: addr_delayed[write_cycle], - en: en_delayed[write_cycle], - write_mode: write_mode_delayed.get(write_cycle).copied(), - data: write_data_delayed[write_cycle], - mask: write_mask_delayed[write_cycle], - insns: &mut write_insns, - }), - ); - self.add_assignment(Interned::default(), read_insns, mem.source_location()); - ( - MemoryPort { - clk_triggered, - addr_delayed, - en_delayed, - data_layout, - read_data_delayed, - write_data_delayed, - write_mask_delayed, - write_mode_delayed, - write_insns, - }, - trace_port, - ) - }) - .unzip(); - let name = mem.scoped_name().1.0; - let id = TraceMemoryId(self.memories.len()); - let stride = mem.array_type().element().bit_width(); - let trace = TraceMem { - id, - name, - stride, - element_type: self - .make_trace_decl_child( - instantiated_module, - MakeTraceDeclTarget::Memory { - id, - depth: mem.array_type().len(), - stride, - start: 0, - ty: mem.array_type().element(), - }, - name, - mem.source_location(), - ) - .intern_sized(), - ports: Intern::intern_owned(trace_ports), - array_type: mem.array_type(), - }; - trace_decls.push(trace.into()); - self.memories.push(Memory { - mem, - memory, - trace, - ports, - }); - } - fn compile_block( - &mut self, - parent_module: Interned, - block: Block, - conditions: Interned<[Cond]>, - trace_decls: &mut Vec, - ) { - let Block { memories, stmts } = block; - for memory in memories { - self.compile_memory(memory, *parent_module, conditions, trace_decls); - } - for stmt in stmts { - match stmt { - Stmt::Connect(StmtConnect { - lhs, - rhs, - source_location, - }) => self.compile_connect( - *parent_module, - conditions, - lhs, - *parent_module, - conditions, - rhs, - source_location, - ), - Stmt::Formal(StmtFormal { .. }) => todo!("implement simulating formal statements"), - Stmt::If(StmtIf { - cond, - source_location, - blocks: [then_block, else_block], - }) => { - let cond = self.compile_expr(*parent_module, Expr::canonical(cond)); - let cond = self.compiled_expr_to_value(cond, source_location); - let cond = cond.map_ty(Bool::from_canonical); - self.compile_block( - parent_module, - then_block, - Interned::from_iter(conditions.iter().copied().chain([Cond { - body: CondBody::IfTrue { cond }, - source_location, - }])), - trace_decls, - ); - self.compile_block( - parent_module, - else_block, - Interned::from_iter(conditions.iter().copied().chain([Cond { - body: CondBody::IfFalse { cond }, - source_location, - }])), - trace_decls, - ); - } - Stmt::Match(StmtMatch { - expr, - source_location, - blocks, - }) => { - let enum_expr = self.compile_expr(*parent_module, Expr::canonical(expr)); - let enum_expr = self.compiled_expr_to_value(enum_expr, source_location); - let enum_expr = enum_expr.map_ty(Enum::from_canonical); - let discriminant = self.compile_enum_discriminant(enum_expr, source_location); - for (variant_index, block) in blocks.into_iter().enumerate() { - self.compile_block( - parent_module, - block, - Interned::from_iter(conditions.iter().copied().chain([Cond { - body: CondBody::MatchArm { - discriminant, - variant_index, - }, - source_location, - }])), - trace_decls, - ); - } - } - Stmt::Declaration(declaration) => { - trace_decls.push(self.compile_declaration( - declaration, - parent_module, - conditions, - )); - } - } - } - } - fn compile_module(&mut self, module: Interned) -> &CompiledModule { - let mut trace_decls = Vec::new(); - let module_io = module - .leaf_module() - .module_io() - .iter() - .map( - |&AnnotatedModuleIO { - annotations: _, - module_io, - }| { - let target = TargetInInstantiatedModule { - instantiated_module: *module, - target: Target::from(module_io), - }; - self.decl_conditions.insert(target, Interned::default()); - trace_decls.push(self.make_trace_decl(*module, module_io.into())); - self.compile_value(target) - }, - ) - .collect(); - match module.leaf_module().body() { - ModuleBody::Normal(NormalModuleBody { body }) => { - self.compile_block(module, body, Interned::default(), &mut trace_decls); - } - ModuleBody::Extern(ExternModuleBody { - verilog_name: _, - parameters: _, - simulation, - }) => { - let Some(simulation) = simulation else { - panic!( - "can't simulate extern module without extern_module_simulation: {}", - module.leaf_module().source_location() - ); - }; - let module_io_targets = module - .leaf_module() - .module_io() - .iter() - .map(|v| { - Target::from(*simulation.sim_io_to_generator_map[&v.module_io.intern()]) - }) - .collect(); - self.extern_modules.push(CompiledExternModule { - module_io_targets, - module_io, - simulation, - }); - } - } - let hashbrown::hash_map::Entry::Vacant(entry) = self.modules.entry(*module) else { - unreachable!("compiled same instantiated module twice"); - }; - entry.insert(CompiledModule { - module_io, - trace_decls: TraceModule { - name: module.leaf_module().name(), - children: Intern::intern_owned(trace_decls), - }, - }) - } - fn process_clocks(&mut self) -> Interned<[StatePartIndex]> { - mem::take(&mut self.clock_triggers) - .into_iter() - .map( - |ClockTrigger { - last_clk_was_low, - clk, - clk_triggered, - source_location, - }| { - self.insns.push( - Insn::XorSmallImmediate { - dest: last_clk_was_low, - lhs: clk, - rhs: 1, - }, - source_location, - ); - clk_triggered - }, - ) - .collect() - } - fn process_registers(&mut self) { - for Register { - value, - clk_triggered, - reset, - source_location, - } in mem::take(&mut self.registers) - { - match reset { - Some(RegisterReset { - is_async, - init, - rst, - }) => { - let reg_end = self.insns.new_label(); - let reg_reset = self.insns.new_label(); - let branch_if_reset = Insn::BranchIfSmallNonZero { - target: reg_reset.0, - value: rst, - }; - let branch_if_not_triggered = Insn::BranchIfSmallZero { - target: reg_end.0, - value: clk_triggered, - }; - if is_async { - self.insns.push(branch_if_reset, source_location); - self.insns.push(branch_if_not_triggered, source_location); - } else { - self.insns.push(branch_if_not_triggered, source_location); - self.insns.push(branch_if_reset, source_location); - } - self.insns.extend( - value.range.insns_for_copy_from(value.write_value().range), - source_location, - ); - self.insns - .push(Insn::Branch { target: reg_end.0 }, source_location); - self.insns.define_label_at_next_insn(reg_reset); - self.insns - .extend(value.range.insns_for_copy_from(init.range), source_location); - self.insns.define_label_at_next_insn(reg_end); - } - None => { - let reg_end = self.insns.new_label(); - self.insns.push( - Insn::BranchIfSmallZero { - target: reg_end.0, - value: clk_triggered, - }, - source_location, - ); - self.insns.extend( - value.range.insns_for_copy_from(value.write_value().range), - source_location, - ); - self.insns.define_label_at_next_insn(reg_end); - } - } - } - } - fn process_memories(&mut self) { - for memory_index in 0..self.memories.len() { - let Memory { - mem, - memory: _, - trace: _, - ref mut ports, - } = self.memories[memory_index]; - for MemoryPort { - clk_triggered, - addr_delayed, - en_delayed, - data_layout: _, - read_data_delayed, - write_data_delayed, - write_mask_delayed, - write_mode_delayed, - write_insns, - } in mem::take(ports) - { - let port_end = self.insns.new_label(); - let small_shift_reg = - |this: &mut Self, values: &[StatePartIndex]| { - for pair in values.windows(2).rev() { - this.insns.push( - Insn::CopySmall { - dest: pair[1], - src: pair[0], - }, - mem.source_location(), - ); - } - }; - let shift_reg = |this: &mut Self, values: &[TypeIndexRange]| { - for pair in values.windows(2).rev() { - this.insns - .extend(pair[0].insns_for_copy_to(pair[1]), mem.source_location()); - } - }; - self.insns.push( - Insn::BranchIfSmallZero { - target: port_end.0, - value: clk_triggered, - }, - mem.source_location(), - ); - small_shift_reg(self, &addr_delayed); - small_shift_reg(self, &en_delayed); - shift_reg(self, &write_data_delayed); - shift_reg(self, &write_mask_delayed); - small_shift_reg(self, &write_mode_delayed); - shift_reg(self, &read_data_delayed); - self.insns.extend(write_insns, mem.source_location()); - self.insns.define_label_at_next_insn(port_end); - } - } - } - pub fn compile(mut self) -> Compiled { - let base_module = - *self.compile_module(InstantiatedModule::Base(self.base_module).intern_sized()); - self.process_assignments(); - self.process_registers(); - self.process_memories(); - let clocks_triggered = self.process_clocks(); - self.insns - .push(Insn::Return, self.base_module.source_location()); - Compiled { - insns: Insns::from(self.insns).intern_sized(), - base_module, - extern_modules: Intern::intern_owned(self.extern_modules), - io: Instance::new_unchecked( - ScopedNameId( - NameId("".intern(), Id::new()), - self.original_base_module.name_id(), - ), - self.original_base_module, - self.original_base_module.source_location(), - ), - traces: SimTraces(Intern::intern_owned(self.traces.0)), - trace_memories: Interned::from_iter(self.memories.iter().map( - |&Memory { - mem: _, - memory, - trace, - ports: _, - }| (memory, trace), - )), - clocks_triggered, - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub(crate) struct CompiledModule { - pub(crate) module_io: Interned<[CompiledValue]>, - pub(crate) trace_decls: TraceModule, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct Compiled { - pub(crate) insns: Interned>, - pub(crate) base_module: CompiledModule, - pub(crate) extern_modules: Interned<[CompiledExternModule]>, - pub(crate) io: Instance, - pub(crate) traces: SimTraces]>>, - pub(crate) trace_memories: Interned<[(StatePartIndex, TraceMem)]>, - pub(crate) clocks_triggered: Interned<[StatePartIndex]>, -} - -impl Compiled { - pub fn new(module: Interned>) -> Self { - Self::from_canonical(Compiler::new(module.canonical().intern()).compile()) - } - pub fn canonical(self) -> Compiled { - let Self { - insns, - base_module, - extern_modules, - io, - traces, - trace_memories, - clocks_triggered, - } = self; - Compiled { - insns, - base_module, - extern_modules, - io: Instance::from_canonical(io.canonical()), - traces, - trace_memories, - clocks_triggered, - } - } - pub fn from_canonical(canonical: Compiled) -> Self { - let Compiled { - insns, - base_module, - extern_modules, - io, - traces, - trace_memories, - clocks_triggered, - } = canonical; - Self { - insns, - base_module, - extern_modules, - io: Instance::from_canonical(io.canonical()), - traces, - trace_memories, - clocks_triggered, - } - } -} diff --git a/crates/fayalite/src/sim/interpreter.rs b/crates/fayalite/src/sim/interpreter.rs index 1a6c269..22f6f5f 100644 --- a/crates/fayalite/src/sim/interpreter.rs +++ b/crates/fayalite/src/sim/interpreter.rs @@ -2,31 +2,28 @@ // See Notices.txt for copyright information use crate::{ + array::Array, int::{BoolOrIntType, SInt, UInt}, intern::{Intern, Interned, Memoize}, - sim::interpreter::parts::{ - StateLayout, StatePartIndex, StatePartKind, StatePartKindBigSlots, StatePartKindMemories, - StatePartKindSimOnlySlots, StatePartKindSmallSlots, StatePartLen, TypeIndexRange, - TypeLayout, get_state_part_kinds, - }, source_location::SourceLocation, - util::{HashMap, HashSet}, + ty::CanonicalType, + util::get_many_mut, }; -use bitvec::slice::BitSlice; +use bitvec::{boxed::BitBox, slice::BitSlice}; +use hashbrown::{HashMap, HashSet}; use num_bigint::BigInt; use num_traits::{One, Signed, ToPrimitive, Zero}; use std::{ + any::TypeId, borrow::BorrowMut, convert::Infallible, fmt::{self, Write}, - hash::Hash, + hash::{Hash, Hasher}, marker::PhantomData, ops::{ControlFlow, Deref, DerefMut, Index, IndexMut}, }; use vec_map::VecMap; -pub(crate) mod parts; - pub(crate) type SmallUInt = u64; pub(crate) type SmallSInt = i64; pub(crate) const MIN_BITS_FOR_NEEDING_BIG: usize = SmallUInt::BITS as usize + 1; @@ -114,33 +111,19 @@ macro_rules! insn_field_enum { }; } -macro_rules! insn_field_enum2 { - ( - type_singular_variants = [$($type_singular_variant:ident,)*]; - array_indexed_variants = [$($array_indexed_variant:ident,)*]; - type_kinds = [$($type_kind:ident,)*]; - ) => { - insn_field_enum! { - pub(crate) enum InsnFieldType { - Memory(Transform::Type>), - $($type_singular_variant(Transform::Type>),)* - $($array_indexed_variant(Transform::Type>),)* - SmallUInt(Transform::Type), - SmallSInt(Transform::Type), - InternedBigInt(Transform::Type>), - U8(Transform::Type), - USize(Transform::Type), - Empty(Transform::Type<[(); 0]>), - } - } - }; -} - -get_state_part_kinds! { - insn_field_enum2! { - type_singular_variants; - array_indexed_variants; - type_kinds; +insn_field_enum! { + pub(crate) enum InsnFieldType { + Memory(Transform::Type>), + SmallSlot(Transform::Type>), + BigSlot(Transform::Type>), + SmallSlotArrayIndexed(Transform::Type>), + BigSlotArrayIndexed(Transform::Type>), + SmallUInt(Transform::Type), + SmallSInt(Transform::Type), + InternedBigInt(Transform::Type>), + U8(Transform::Type), + USize(Transform::Type), + Empty(Transform::Type<[(); 0]>), } } @@ -269,10 +252,8 @@ impl Insn { InsnFieldType::Memory(_) | InsnFieldType::SmallSlot(_) | InsnFieldType::BigSlot(_) - | InsnFieldType::SimOnlySlot(_) | InsnFieldType::SmallSlotArrayIndexed(_) | InsnFieldType::BigSlotArrayIndexed(_) - | InsnFieldType::SimOnlySlotArrayIndexed(_) | InsnFieldType::SmallUInt(_) | InsnFieldType::SmallSInt(_) | InsnFieldType::InternedBigInt(_) @@ -299,18 +280,12 @@ impl Insn { InsnFieldType::BigSlot(v) => { debug_fmt_state_part!(v)?; } - InsnFieldType::SimOnlySlot(v) => { - debug_fmt_state_part!(v)?; - } InsnFieldType::SmallSlotArrayIndexed(v) => { debug_fmt_state_part!(v)?; } InsnFieldType::BigSlotArrayIndexed(v) => { debug_fmt_state_part!(v)?; } - InsnFieldType::SimOnlySlotArrayIndexed(v) => { - debug_fmt_state_part!(v)?; - } InsnFieldType::SmallUInt(v) => write!(f, "{v:#x}")?, InsnFieldType::SmallSInt(v) => write!(f, "{v:#x}")?, InsnFieldType::InternedBigInt(v) => write!(f, "{v:#x}")?, @@ -800,6 +775,911 @@ impl fmt::Debug for Insns { } } +pub(crate) trait StatePartKind: + Send + Sync + Ord + Hash + fmt::Debug + 'static + Copy + Default +{ + const NAME: &'static str; + type DebugData: Send + Sync + Eq + Hash + fmt::Debug + 'static + Copy; + type LayoutData: Send + Sync + Eq + Hash + fmt::Debug + 'static + Copy; + type State: fmt::Debug + 'static + Clone; + type BorrowedState<'a>: 'a; + fn new_state(layout_data: &[Self::LayoutData]) -> Self::State; + fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a>; + fn part_debug_data( + state_layout: &StateLayout, + part_index: StatePartIndex, + ) -> Option<&Self::DebugData>; + fn debug_fmt_state_value( + state: &State, + index: StatePartIndex, + f: &mut impl fmt::Write, + ) -> fmt::Result; +} + +pub(crate) trait StatePartsValue { + type Value; +} + +macro_rules! impl_state_parts_traits { + ( + struct $Struct:ident<$V:ident: $StatePartsValue:ident> { + $(#[flatten] + $flattened_field:ident: $flattened_field_ty:ty, + $(#[field_in_flattened] + $field_in_flattened:ident: $field_in_flattened_ty:ty,)* + )? + $($field:ident: $field_ty:ty,)* + } + ) => { + impl<$V: $StatePartsValue> Copy for $Struct<$V> + where + $($flattened_field_ty: Copy,)? + $($field_ty: Copy,)* + { + } + + impl<$V: $StatePartsValue> Clone for $Struct<$V> + where + $($flattened_field_ty: Clone,)? + $($field_ty: Clone,)* + { + fn clone(&self) -> Self { + Self { + $($flattened_field: self.$flattened_field.clone(),)? + $($field: self.$field.clone(),)* + } + } + } + + impl<$V: $StatePartsValue> fmt::Debug for $Struct<$V> + where + $($($field_in_flattened_ty: fmt::Debug,)*)? + $($field_ty: fmt::Debug,)* + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(stringify!($Struct)) + $($(.field(stringify!($field_in_flattened), &self.$flattened_field.$field_in_flattened))*)? + $(.field(stringify!($field), &self.$field))* + .finish() + } + } + + impl<$V: $StatePartsValue> PartialEq for $Struct<$V> + where + $($flattened_field_ty: PartialEq,)? + $($field_ty: PartialEq,)* + { + fn eq(&self, other: &Self) -> bool { + true $(&& self.$flattened_field == other.$flattened_field)? $(&& self.$field == other.$field)* + } + } + + impl<$V: $StatePartsValue> Eq for $Struct<$V> + where + $($flattened_field_ty: Eq,)? + $($field_ty: Eq,)* + { + } + + impl<$V: $StatePartsValue> Hash for $Struct<$V> + where + $($flattened_field_ty: Hash,)? + $($field_ty: Hash,)* + { + fn hash(&self, h: &mut H) { + $(self.$flattened_field.hash(h);)? + $(self.$field.hash(h);)* + } + } + + impl<$V: $StatePartsValue> Default for $Struct<$V> + where + $($flattened_field_ty: Default,)? + $($field_ty: Default,)* + { + fn default() -> Self { + Self { + $($flattened_field: Default::default(),)? + $($field: Default::default(),)* + } + } + } + }; +} + +macro_rules! make_state_part_kinds { + ( + $( + #[state, field = $state_field:ident] + impl $StateStatePartKind:ident for $StateKind:ident $state_impl_body:tt + )* + $( + #[type, field = $type_field:ident] + impl $TypeStatePartKind:ident for $TypeKind:ident $type_impl_body:tt + )* + ) => { + $( + #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy, Default)] + pub(crate) struct $StateKind; + + impl $StateStatePartKind for $StateKind $state_impl_body + )* + + $( + #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy, Default)] + pub(crate) struct $TypeKind; + + impl $TypeStatePartKind for $TypeKind $type_impl_body + )* + + pub(crate) struct StateParts { + pub(crate) ty: TypeParts, + $(pub(crate) $state_field: V::Value<$StateKind>,)* + } + + impl_state_parts_traits! { + struct StateParts { + #[flatten] + ty: TypeParts, + $(#[field_in_flattened] + $type_field: V::Value<$TypeKind>,)* + $($state_field: V::Value<$StateKind>,)* + } + } + + pub(crate) struct TypeParts { + $(pub(crate) $type_field: V::Value<$TypeKind>,)* + } + + impl_state_parts_traits! { + struct TypeParts { + $($type_field: V::Value<$TypeKind>,)* + } + } + + #[derive(Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct StateLayout { + pub(crate) ty: TypeLayout, + $(pub(crate) $state_field: StatePartLayout<$StateKind, BK>,)* + } + + impl Copy for StateLayout {} + + impl StateLayout { + pub(crate) fn len(&self) -> StateLen { + StateLen { + ty: self.ty.len(), + $($state_field: self.$state_field.len(),)* + } + } + pub(crate) fn is_empty(&self) -> bool { + self.ty.is_empty() $(&& self.$state_field.is_empty())* + } + pub(crate) fn empty() -> Self { + Self { + ty: TypeLayout::empty(), + $($state_field: StatePartLayout::empty(),)* + } + } + } + + impl StateLayout { + pub(crate) fn next_index(&self) -> StateIndex { + StateIndex { + ty: self.ty.next_index(), + $($state_field: self.$state_field.next_index(),)* + } + } + pub(crate) fn allocate( + &mut self, + layout: &StateLayout, + ) -> StateIndexRange { + StateIndexRange { + ty: self.ty.allocate(&layout.ty), + $($state_field: self.$state_field.allocate(&layout.$state_field),)* + } + } + } + + impl From> for StateLayout { + fn from(v: StateLayout) -> Self { + Self { + ty: v.ty.into(), + $($state_field: v.$state_field.into(),)* + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct StateIndexRange { + pub(crate) ty: TypeIndexRange, + $(pub(crate) $state_field: StatePartIndexRange<$StateKind>,)* + } + + impl StateIndexRange { + pub(crate) fn start(self) -> StateIndex { + StateIndex { + ty: self.ty.start(), + $($state_field: self.$state_field.start(),)* + } + } + pub(crate) fn len(self) -> StateLen { + StateLen { + ty: self.ty.len(), + $($state_field: self.$state_field.len(),)* + } + } + pub(crate) fn is_empty(self) -> bool { + self.ty.is_empty() $(&& self.$state_field.is_empty())* + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct StateLen { + pub(crate) ty: TypeLen, + $(pub(crate) $state_field: StatePartLen<$StateKind>,)* + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct StateIndex { + pub(crate) ty: TypeIndex, + $(pub(crate) $state_field: StatePartIndex<$StateKind>,)* + } + + #[derive(Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct TypeLayout { + $(pub(crate) $type_field: StatePartLayout<$TypeKind, BK>,)* + } + + impl Copy for TypeLayout {} + + impl TypeLayout { + pub(crate) fn len(&self) -> TypeLen { + TypeLen { + $($type_field: self.$type_field.len(),)* + } + } + pub(crate) fn is_empty(&self) -> bool { + $(self.$type_field.is_empty())&&+ + } + pub(crate) fn empty() -> Self { + Self { + $($type_field: StatePartLayout::empty(),)* + } + } + } + + impl TypeLayout { + pub(crate) fn next_index(&self) -> TypeIndex { + TypeIndex { + $($type_field: self.$type_field.next_index(),)* + } + } + pub(crate) fn allocate( + &mut self, + layout: &TypeLayout, + ) -> TypeIndexRange { + TypeIndexRange { + $($type_field: self.$type_field.allocate(&layout.$type_field),)* + } + } + } + + impl From> for TypeLayout { + fn from(v: TypeLayout) -> Self { + Self { + $($type_field: v.$type_field.into(),)* + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct TypeIndexRange { + $(pub(crate) $type_field: StatePartIndexRange<$TypeKind>,)* + } + + impl TypeIndexRange { + pub(crate) fn new(start: TypeIndex, len: TypeLen) -> Self { + Self { + $($type_field: StatePartIndexRange { + start: start.$type_field, + len: len.$type_field, + },)* + } + } + pub(crate) fn start(self) -> TypeIndex { + TypeIndex { + $($type_field: self.$type_field.start(),)* + } + } + pub(crate) fn len(self) -> TypeLen { + TypeLen { + $($type_field: self.$type_field.len(),)* + } + } + pub(crate) fn is_empty(self) -> bool { + $(self.$type_field.is_empty()) &&+ + } + pub(crate) fn slice(self, index: TypeIndexRange) -> Self { + Self { + $($type_field: self.$type_field.slice(index.$type_field),)* + } + } + pub(crate) fn index_array(self, element_size: TypeLen, index: usize) -> Self { + Self { + $($type_field: self.$type_field.index_array(element_size.$type_field, index),)* + } + } + pub(crate) fn offset(self, offset: TypeIndex) -> Self { + Self { + $($type_field: self.$type_field.offset(offset.$type_field),)* + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct TypeLen { + $(pub(crate) $type_field: StatePartLen<$TypeKind>,)* + } + + impl TypeLen { + pub(crate) const fn as_index(self) -> TypeIndex { + TypeIndex { + $($type_field: self.$type_field.as_index(),)* + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct TypeIndex { + $(pub(crate) $type_field: StatePartIndex<$TypeKind>,)* + } + + impl TypeIndex { + pub(crate) const ZERO: Self = Self { + $($type_field: StatePartIndex::ZERO,)* + }; + pub(crate) fn offset(self, offset: TypeIndex) -> Self { + Self { + $($type_field: self.$type_field.offset(offset.$type_field),)* + } + } + } + + pub(crate) struct State { + pub(crate) insns: Interned>, + pub(crate) pc: usize, + pub(crate) memory_write_log: Vec<(StatePartIndex, usize)>, + $(pub(crate) $state_field: StatePart<$StateKind>,)* + $(pub(crate) $type_field: StatePart<$TypeKind>,)* + } + + impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + insns: _, + pc, + memory_write_log, + $($state_field,)* + $($type_field,)* + } = self; + f.debug_struct("State") + .field("insns", &InsnsOfState(self)) + .field("pc", pc) + .field("memory_write_log", memory_write_log) + $(.field(stringify!($state_field), $state_field))* + $(.field(stringify!($type_field), $type_field))* + .finish() + } + } + + impl State { + pub(crate) fn new(insns: Interned>) -> Self { + Self { + insns, + pc: 0, + memory_write_log: Vec::with_capacity(32), + $($state_field: StatePart::new(&insns.state_layout.$state_field.layout_data),)* + $($type_field: StatePart::new(&insns.state_layout.ty.$type_field.layout_data),)* + } + } + pub(crate) fn borrow(&mut self) -> BorrowedState<'_> { + BorrowedState { + orig_insns: self.insns, + insns: &self.insns.insns, + pc: self.pc, + orig_pc: &mut self.pc, + memory_write_log: &mut self.memory_write_log, + $($state_field: self.$state_field.borrow(),)* + $($type_field: self.$type_field.borrow(),)* + } + } + } + + #[derive(Debug)] + pub(crate) struct BorrowedState<'a> { + pub(crate) orig_insns: Interned>, + pub(crate) insns: &'a [Insn], + pub(crate) orig_pc: &'a mut usize, + pub(crate) pc: usize, + pub(crate) memory_write_log: &'a mut Vec<(StatePartIndex, usize)>, + $(pub(crate) $state_field: BorrowedStatePart<'a, $StateKind>,)* + $(pub(crate) $type_field: BorrowedStatePart<'a, $TypeKind>,)* + } + + impl Drop for BorrowedState<'_> { + fn drop(&mut self) { + *self.orig_pc = self.pc; + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] + pub(crate) struct TypeArrayIndexes { + $(pub(crate) $type_field: Interned<[StatePartArrayIndex<$TypeKind>]>,)* + } + + impl TypeArrayIndexes { + pub(crate) fn as_ref(&self) -> TypeArrayIndexesRef<'_> { + TypeArrayIndexesRef { + $($type_field: &self.$type_field,)* + } + } + #[must_use] + pub(crate) fn join(self, next: TypeArrayIndex) -> TypeArrayIndexes { + TypeArrayIndexes { + $($type_field: Interned::from_iter(self.$type_field.iter().copied().chain([next.$type_field])),)* + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct TypeArrayIndex { + $(pub(crate) $type_field: StatePartArrayIndex<$TypeKind>,)* + } + + impl TypeArrayIndex { + pub(crate) fn from_parts(index: StatePartIndex, len: usize, stride: TypeLen) -> Self { + Self { + $($type_field: StatePartArrayIndex { + index, + len, + stride: stride.$type_field, + },)* + } + } + pub(crate) fn len(self) -> usize { + let len = self.small_slots.len; + $(assert_eq!(self.$type_field.len, len, "array length mismatch");)* + len + } + pub(crate) fn index(self) -> StatePartIndex { + let index = self.small_slots.index; + $(assert_eq!(self.$type_field.index, index, "array index mismatch");)* + index + } + pub(crate) fn is_empty(self) -> bool { + self.len() == 0 + } + pub(crate) fn stride(self) -> TypeLen { + TypeLen { + $($type_field: self.$type_field.stride,)* + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] + pub(crate) struct TypeArrayIndexesRef<'a> { + $(pub(crate) $type_field: &'a [StatePartArrayIndex<$TypeKind>],)* + } + + impl<'a> TypeArrayIndexesRef<'a> { + pub(crate) fn len(self) -> usize { + let len = self.small_slots.len(); + $(assert_eq!(self.$type_field.len(), len, "indexes count mismatch");)* + len + } + pub(crate) fn is_empty(self) -> bool { + self.len() == 0 + } + pub(crate) fn iter(self) -> impl Iterator + 'a { + (0..self.len()).map(move |i| TypeArrayIndex { + $($type_field: self.$type_field[i],)* + }) + } + pub(crate) fn for_each_offset( + self, + mut f: impl FnMut(TypeIndex), + ) { + self.for_each_offset2(TypeIndex { + $($type_field: StatePartIndex { + value: 0, + _phantom: PhantomData, + },)* + }, &mut f); + } + pub(crate) fn split_first(self) -> Option<(TypeArrayIndex, Self)> { + $(let $type_field = self.$type_field.split_first()?;)* + let next = TypeArrayIndex { + $($type_field: *$type_field.0,)* + }; + let rest = TypeArrayIndexesRef { + $($type_field: $type_field.1,)* + }; + Some((next, rest)) + } + pub(crate) fn for_each_offset2( + self, + base_offset: TypeIndex, + f: &mut (impl FnMut(TypeIndex) + ?Sized), + ) { + if let Some((next, rest)) = self.split_first() { + let stride = next.stride(); + for index in 0..next.len().try_into().expect("array too big") { + let mut offset = TypeIndex { + $($type_field: StatePartIndex { + value: stride + .$type_field + .value + .checked_mul(index) + .expect("array too big"), + _phantom: PhantomData, + },)* + }; + $(offset.$type_field.value = + base_offset + .$type_field + .value + .checked_add(offset.$type_field.value) + .expect("array too big");)* + rest.for_each_offset2(offset, f); + } + } else { + $(assert!(self.$type_field.is_empty(), "indexes count mismatch");)* + f(base_offset); + } + } + } + + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] + pub(crate) struct TypeArrayIndexed { + $(pub(crate) $type_field: StatePartArrayIndexed<$TypeKind>,)* + } + + impl TypeArrayIndexed { + pub(crate) fn from_parts(base: TypeIndex, indexes: TypeArrayIndexes) -> Self { + Self { + $($type_field: StatePartArrayIndexed { + base: base.$type_field, + indexes: indexes.$type_field, + },)* + } + } + pub(crate) fn base(self) -> TypeIndex { + TypeIndex { + $($type_field: self.$type_field.base,)* + } + } + pub(crate) fn indexes(self) -> TypeArrayIndexes { + TypeArrayIndexes { + $($type_field: self.$type_field.indexes,)* + } + } + } + + impl From for TypeArrayIndexed { + fn from(value: TypeIndex) -> Self { + TypeArrayIndexed { + $($type_field: value.$type_field.into(),)* + } + } + } + }; +} + +#[derive(Copy, Clone, Hash, PartialEq, Eq)] +pub(crate) struct MemoryData> { + pub(crate) array_type: Array, + pub(crate) data: T, +} + +impl> fmt::Debug for MemoryData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { array_type, data } = self; + f.debug_struct("MemoryData") + .field("array_type", array_type) + .field( + "data", + &crate::memory::DebugMemoryData::from_bit_slice(*array_type, data), + ) + .finish() + } +} + +make_state_part_kinds! { + /*#[state, field = small_stack] + impl StatePartKind for StatePartKindSmallStack { + const NAME: &'static str = "SmallStack"; + type DebugData = (); + type LayoutData = (); + type State = Stack; + type BorrowedState<'a> = BorrowedStack<'a, SmallUInt>; + fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { + Stack::new(layout_data.len()) + } + fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { + state.borrow() + } + fn part_debug_data( + state_layout: &StateLayout, + part_index: StatePartIndex, + ) -> Option<&Self::DebugData> { + state_layout.small_stack.debug_data.get(part_index.as_usize()) + } + } + #[state, field = big_stack] + impl StatePartKind for StatePartKindBigStack { + const NAME: &'static str = "BigStack"; + type DebugData = (); + type LayoutData = (); + type State = Stack; + type BorrowedState<'a> = BorrowedStack<'a, BigInt>; + fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { + Stack::new(layout_data.len()) + } + fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { + state.borrow() + } + fn part_debug_data( + state_layout: &StateLayout, + part_index: StatePartIndex, + ) -> Option<&Self::DebugData> { + state_layout.big_stack.debug_data.get(part_index.as_usize()) + } + }*/ + #[state, field = memories] + impl StatePartKind for StatePartKindMemories { + const NAME: &'static str = "Memories"; + type DebugData = (); + type LayoutData = MemoryData>; + type State = Box<[MemoryData]>; + type BorrowedState<'a> = &'a mut [MemoryData]; + fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { + layout_data.iter().map(|MemoryData { array_type, data }| MemoryData { + array_type: *array_type, + data: BitBox::from_bitslice(data), + }).collect() + } + fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { + state + } + fn part_debug_data( + state_layout: &StateLayout, + part_index: StatePartIndex, + ) -> Option<&Self::DebugData> { + state_layout.memories.debug_data.get(part_index.as_usize()) + } + fn debug_fmt_state_value( + state: &State, + index: StatePartIndex, + f: &mut impl fmt::Write, + ) -> fmt::Result { + write!(f, "{:#?}", &state.memories[index]) + } + } + #[type, field = small_slots] + impl StatePartKind for StatePartKindSmallSlots { + const NAME: &'static str = "SmallSlots"; + type DebugData = SlotDebugData; + type LayoutData = (); + type State = Box<[SmallUInt]>; + type BorrowedState<'a> = &'a mut [SmallUInt]; + fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { + vec![0; layout_data.len()].into_boxed_slice() + } + fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { + state + } + fn part_debug_data( + state_layout: &StateLayout, + part_index: StatePartIndex, + ) -> Option<&Self::DebugData> { + state_layout.ty.small_slots.debug_data.get(part_index.as_usize()) + } + fn debug_fmt_state_value( + state: &State, + index: StatePartIndex, + f: &mut impl fmt::Write, + ) -> fmt::Result { + let value = state.small_slots[index]; + write!(f, "{value:#x} {}", value as SmallSInt)?; + Ok(()) + } + } + #[type, field = big_slots] + impl StatePartKind for StatePartKindBigSlots { + const NAME: &'static str = "BigSlots"; + type DebugData = SlotDebugData; + type LayoutData = (); + type State = Box<[BigInt]>; + type BorrowedState<'a> = &'a mut [BigInt]; + fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { + layout_data.iter().map(|_| BigInt::default()).collect() + } + fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { + state + } + fn part_debug_data( + state_layout: &StateLayout, + part_index: StatePartIndex, + ) -> Option<&Self::DebugData> { + state_layout.ty.big_slots.debug_data.get(part_index.as_usize()) + } + fn debug_fmt_state_value( + state: &State, + index: StatePartIndex, + f: &mut impl fmt::Write, + ) -> fmt::Result { + write!(f, "{:#x}", state.big_slots[index]) + } + } +} + +impl TypeLen { + pub(crate) fn only_small(self) -> Option> { + let Self { + small_slots, + big_slots: + StatePartLen { + value: 0, + _phantom: _, + }, + } = self + else { + return None; + }; + Some(small_slots) + } + pub(crate) const A_SMALL_SLOT: Self = TypeLen { + small_slots: StatePartLen { + value: 1, + _phantom: PhantomData, + }, + big_slots: StatePartLen { + value: 0, + _phantom: PhantomData, + }, + }; + pub(crate) const A_BIG_SLOT: Self = TypeLen { + small_slots: StatePartLen { + value: 0, + _phantom: PhantomData, + }, + big_slots: StatePartLen { + value: 1, + _phantom: PhantomData, + }, + }; +} + +#[derive(Debug, Clone)] +pub(crate) struct Stack { + storage: Box<[T]>, + cur_len: usize, +} + +impl Stack { + pub(crate) fn new(len: usize) -> Self + where + T: Default, + { + Self { + storage: std::iter::repeat_with(T::default).take(len).collect(), + cur_len: 0, + } + } + pub(crate) fn borrow(&mut self) -> BorrowedStack<'_, T> { + BorrowedStack { + storage: &mut self.storage, + cur_len: self.cur_len, + stack_cur_len: &mut self.cur_len, + } + } + pub(crate) fn clear(&mut self) { + self.cur_len = 0; + } +} + +#[derive(Debug)] +pub(crate) struct BorrowedStack<'a, T> { + storage: &'a mut [T], + cur_len: usize, + stack_cur_len: &'a mut usize, +} + +impl<'a, T> BorrowedStack<'a, T> { + pub(crate) fn push(&mut self, value: T) { + self.storage[self.cur_len] = value; + self.cur_len += 1; + } + pub(crate) fn pop(&mut self) -> T + where + T: Default, + { + self.cur_len -= 1; + std::mem::take(&mut self.storage[self.cur_len]) + } +} + +impl Drop for BorrowedStack<'_, T> { + fn drop(&mut self) { + *self.stack_cur_len = self.cur_len; + } +} + +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub(crate) struct SlotDebugData { + pub(crate) name: Interned, + pub(crate) ty: CanonicalType, +} + +impl SlotDebugData { + pub(crate) fn with_prefixed_debug_names(&self, prefix: &str) -> Self { + let mut name = String::with_capacity(self.name.len() + prefix.len()); + name.push_str(prefix); + name.push_str(&self.name); + Self { + name: Intern::intern_owned(name), + ty: self.ty, + } + } + pub(crate) fn with_anonymized_debug_info(&self) -> Self { + Self { + name: Interned::default(), + ty: self.ty, + } + } +} + +impl, BK: InsnsBuildingKind> StatePartLayout { + pub(crate) fn with_prefixed_debug_names(&self, prefix: &str) -> Self { + Self { + debug_data: self + .debug_data + .iter() + .map(|v| v.with_prefixed_debug_names(prefix)) + .collect(), + layout_data: self.layout_data.clone(), + _phantom: PhantomData, + } + } + pub(crate) fn with_anonymized_debug_info(&self) -> Self { + Self { + debug_data: self + .debug_data + .iter() + .map(|v| v.with_anonymized_debug_info()) + .collect(), + layout_data: self.layout_data.clone(), + _phantom: PhantomData, + } + } +} + +impl TypeLayout { + pub(crate) fn with_prefixed_debug_names(&self, prefix: &str) -> Self { + Self { + small_slots: self.small_slots.with_prefixed_debug_names(prefix), + big_slots: self.big_slots.with_prefixed_debug_names(prefix), + } + } + pub(crate) fn with_anonymized_debug_info(&self) -> Self { + Self { + small_slots: self.small_slots.with_anonymized_debug_info(), + big_slots: self.big_slots.with_anonymized_debug_info(), + } + } +} + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub(crate) struct StatePartArrayIndex { pub(crate) index: StatePartIndex, @@ -871,11 +1751,13 @@ impl StatePartArrayIndexed { if let [next, rest @ ..] = indexes { for i in 0..next.len.try_into().expect("array too big") { Self::for_each_target2( - StatePartIndex::new( - base.value + StatePartIndex { + value: base + .value .checked_add(next.stride.value.checked_mul(i).expect("array too big")) .expect("array too big"), - ), + _phantom: PhantomData, + }, rest, f, ); @@ -889,6 +1771,285 @@ impl StatePartArrayIndexed { } } +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) struct StatePartIndex { + pub(crate) value: u32, + pub(crate) _phantom: PhantomData, +} + +impl StatePartIndex { + pub(crate) const ZERO: Self = Self { + value: 0, + _phantom: PhantomData, + }; + pub(crate) fn as_usize(self) -> usize { + self.value.try_into().expect("index too big") + } + pub(crate) fn offset(self, offset: StatePartIndex) -> Self { + Self { + value: self + .value + .checked_add(offset.value) + .expect("offset too big"), + _phantom: PhantomData, + } + } + pub(crate) fn debug_fmt( + &self, + f: &mut impl fmt::Write, + before_debug_info_text: &str, + comment_start: &str, + comment_line_start: &str, + comment_end: &str, + state_layout: Option<&StateLayout>, + state: Option<&State>, + ) -> fmt::Result { + write!(f, "StatePartIndex<{}>({})", K::NAME, self.value)?; + f.write_str(before_debug_info_text)?; + let debug_data = + state_layout.and_then(|state_layout| K::part_debug_data(state_layout, *self)); + if state.is_some() || debug_data.is_some() { + f.write_str(comment_start)?; + } + let mut f = PrefixLinesWrapper { + writer: f, + at_beginning_of_line: false, + blank_line_prefix: comment_line_start.trim_end(), + line_prefix: comment_line_start, + }; + if let Some(state) = state { + f.write_str("(")?; + K::debug_fmt_state_value(state, *self, &mut f)?; + f.write_str(")")?; + } + if state.is_some() && debug_data.is_some() { + f.write_str(" ")?; + } + if let Some(debug_data) = debug_data { + write!(f, "{debug_data:?}")?; + } + if state.is_some() || debug_data.is_some() { + f.writer.write_str(comment_end)?; + } + Ok(()) + } +} + +impl fmt::Debug for StatePartIndex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.debug_fmt::(f, "", "", "", "", None, None) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) struct StatePartLen { + pub(crate) value: u32, + pub(crate) _phantom: PhantomData, +} + +impl StatePartLen { + pub(crate) const fn new(value: u32) -> Self { + Self { + value, + _phantom: PhantomData, + } + } + pub(crate) const fn as_index(self) -> StatePartIndex { + StatePartIndex { + value: self.value, + _phantom: PhantomData, + } + } +} + +impl fmt::Debug for StatePartLen { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "StatePartLen<{}>({})", K::NAME, self.value) + } +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub(crate) struct StatePartLayout { + pub(crate) debug_data: BK::Vec, + pub(crate) layout_data: BK::Vec, + pub(crate) _phantom: PhantomData, +} + +impl Copy for StatePartLayout {} + +impl StatePartLayout { + pub(crate) fn len(&self) -> StatePartLen { + StatePartLen::new( + self.debug_data + .len() + .try_into() + .expect("state part allocation layout is too big"), + ) + } + pub(crate) fn is_empty(&self) -> bool { + self.debug_data.is_empty() + } + pub(crate) fn empty() -> Self { + Self { + debug_data: Default::default(), + layout_data: Default::default(), + _phantom: PhantomData, + } + } + pub(crate) fn debug_data(&self, index: StatePartIndex) -> &K::DebugData { + &self.debug_data[index.as_usize()] + } +} + +impl From> + for StatePartLayout +{ + fn from(value: StatePartLayout) -> Self { + Self { + debug_data: Intern::intern_owned(value.debug_data), + layout_data: Intern::intern_owned(value.layout_data), + _phantom: PhantomData, + } + } +} + +impl StatePartLayout { + pub(crate) fn scalar(debug_data: K::DebugData, layout_data: K::LayoutData) -> Self { + Self { + debug_data: vec![debug_data], + layout_data: vec![layout_data], + _phantom: PhantomData, + } + } + pub(crate) fn next_index(&self) -> StatePartIndex { + StatePartIndex { + value: self.len().value, + _phantom: PhantomData, + } + } + pub(crate) fn allocate( + &mut self, + layout: &StatePartLayout, + ) -> StatePartIndexRange { + let start = self.next_index(); + let len = layout.len(); + let Self { + debug_data, + layout_data, + _phantom: _, + } = self; + debug_data.extend_from_slice(&layout.debug_data); + layout_data.extend_from_slice(&layout.layout_data); + StatePartIndexRange { start, len } + } +} + +impl fmt::Debug for StatePartLayout { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + debug_data, + layout_data, + _phantom: _, + } = self; + write!(f, "StatePartLayout<{}>", K::NAME)?; + let mut debug_struct = f.debug_struct(""); + debug_struct + .field("len", &debug_data.len()) + .field("debug_data", debug_data); + if TypeId::of::() != TypeId::of::<()>() { + debug_struct.field("layout_data", layout_data); + } + debug_struct.finish_non_exhaustive() + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub(crate) struct StatePartIndexRange { + pub(crate) start: StatePartIndex, + pub(crate) len: StatePartLen, +} + +impl StatePartIndexRange { + pub(crate) fn start(self) -> StatePartIndex { + self.start + } + pub(crate) fn end(self) -> StatePartIndex { + StatePartIndex { + value: self + .start + .value + .checked_add(self.len.value) + .expect("state part allocation layout is too big"), + _phantom: PhantomData, + } + } + pub(crate) fn len(self) -> StatePartLen { + self.len + } + pub(crate) fn is_empty(self) -> bool { + self.len.value == 0 + } + pub(crate) fn iter(self) -> impl Iterator> { + (self.start.value..self.end().value).map(|value| StatePartIndex { + value, + _phantom: PhantomData, + }) + } + pub(crate) fn offset(self, offset: StatePartIndex) -> Self { + self.end().offset(offset); // check for overflow + Self { + start: self.start.offset(offset), + len: self.len, + } + } + pub(crate) fn slice(self, index: StatePartIndexRange) -> Self { + assert!(index.end().value <= self.len.value, "index out of range"); + Self { + start: StatePartIndex { + value: self.start.value + index.start.value, + _phantom: PhantomData, + }, + len: index.len, + } + } + pub(crate) fn index_array(self, element_size: StatePartLen, index: usize) -> Self { + if element_size.value == 0 { + assert_eq!( + self.len.value, 0, + "array with zero-sized element must also be zero-sized", + ); + return self; + } + assert!( + self.len.value % element_size.value == 0, + "array's size must be a multiple of its element size", + ); + self.slice(StatePartIndexRange { + start: StatePartIndex { + value: index + .try_into() + .ok() + .and_then(|index| element_size.value.checked_mul(index)) + .expect("index out of range"), + _phantom: PhantomData, + }, + len: element_size, + }) + } +} + +impl fmt::Debug for StatePartIndexRange { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "StatePartIndexRange<{}> {{ start: {}, len: {} }}", + K::NAME, + self.start.value, + self.len.value + ) + } +} + #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub(crate) struct StatePart { pub(crate) value: K::State, @@ -913,21 +2074,21 @@ pub(crate) struct BorrowedStatePart<'a, K: StatePartKind> { } impl< - 'a, - K: StatePartKind< - BorrowedState<'a>: DerefMut + BorrowMut<[T]>>, - >, - T, -> BorrowedStatePart<'a, K> + 'a, + K: StatePartKind< + BorrowedState<'a>: DerefMut + BorrowMut<[T]>>, + >, + T, + > BorrowedStatePart<'a, K> { - pub(crate) fn get_disjoint_mut( + pub(crate) fn get_many_mut( &mut self, indexes: [StatePartIndex; N], ) -> [&mut T; N] { - (*self.value) - .borrow_mut() - .get_disjoint_mut(indexes.map(|v| v.value as usize)) - .expect("indexes are disjoint") + get_many_mut( + (*self.value).borrow_mut(), + indexes.map(|v| v.value as usize), + ) } } @@ -965,84 +2126,17 @@ impl<'a, K: StatePartKind: DerefMut { - pub(crate) struct State { - pub(crate) insns: Interned>, - pub(crate) pc: usize, - pub(crate) memory_write_log: Vec<(StatePartIndex, usize)>, - $(pub(crate) $state_plural_field: StatePart<$state_kind>,)* - $(pub(crate) $type_plural_field: StatePart<$type_kind>,)* - } - - impl fmt::Debug for State { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - insns: _, - pc, - memory_write_log, - $($state_plural_field,)* - $($type_plural_field,)* - } = self; - f.debug_struct("State") - .field("insns", &InsnsOfState(self)) - .field("pc", pc) - .field("memory_write_log", memory_write_log) - $(.field(stringify!($state_plural_field), $state_plural_field))* - $(.field(stringify!($type_plural_field), $type_plural_field))* - .finish() - } - } - - impl State { - pub(crate) fn new(insns: Interned>) -> Self { - Self { - insns, - pc: 0, - memory_write_log: Vec::with_capacity(32), - $($state_plural_field: StatePart::new(&insns.state_layout.$state_plural_field.layout_data),)* - $($type_plural_field: StatePart::new(&insns.state_layout.ty.$type_plural_field.layout_data),)* - } - } - pub(crate) fn borrow(&mut self) -> BorrowedState<'_> { - BorrowedState { - orig_insns: self.insns, - insns: &self.insns.insns, - pc: self.pc, - orig_pc: &mut self.pc, - memory_write_log: &mut self.memory_write_log, - $($state_plural_field: self.$state_plural_field.borrow(),)* - $($type_plural_field: self.$type_plural_field.borrow(),)* - } - } - } - - #[derive(Debug)] - pub(crate) struct BorrowedState<'a> { - pub(crate) orig_insns: Interned>, - pub(crate) insns: &'a [Insn], - pub(crate) orig_pc: &'a mut usize, - pub(crate) pc: usize, - pub(crate) memory_write_log: &'a mut Vec<(StatePartIndex, usize)>, - $(pub(crate) $state_plural_field: BorrowedStatePart<'a, $state_kind>,)* - $(pub(crate) $type_plural_field: BorrowedStatePart<'a, $type_kind>,)* - } - - impl Drop for BorrowedState<'_> { - fn drop(&mut self) { - *self.orig_pc = self.pc; - } - } - }; -} - -get_state_part_kinds! { - make_state! { - state_plural_fields; - state_kinds; +impl<'a, K: StatePartKind = BorrowedStack<'a, T>>, T: 'a> + BorrowedStatePart<'a, K> +{ + pub(crate) fn push(&mut self, value: T) { + self.value.push(value) + } + pub(crate) fn pop(&mut self) -> T + where + T: Default, + { + self.value.pop() } } @@ -1079,7 +2173,10 @@ impl StatePartIndexMap { self.map.get_mut(key.as_usize()) } pub(crate) fn keys(&self) -> impl Iterator> + '_ { - self.map.keys().map(|v| StatePartIndex::new(v as _)) + self.map.keys().map(|k| StatePartIndex { + value: k as u32, + _phantom: PhantomData, + }) } pub(crate) fn values(&self) -> vec_map::Values<'_, V> { self.map.values() @@ -1088,14 +2185,26 @@ impl StatePartIndexMap { self.map.values_mut() } pub(crate) fn iter(&self) -> impl Iterator, &V)> + '_ { - self.map - .iter() - .map(|(k, v)| (StatePartIndex::new(k as u32), v)) + self.map.iter().map(|(k, v)| { + ( + StatePartIndex { + value: k as u32, + _phantom: PhantomData, + }, + v, + ) + }) } pub(crate) fn iter_mut(&mut self) -> impl Iterator, &mut V)> + '_ { - self.map - .iter_mut() - .map(|(k, v)| (StatePartIndex::new(k as u32), v)) + self.map.iter_mut().map(|(k, v)| { + ( + StatePartIndex { + value: k as u32, + _phantom: PhantomData, + }, + v, + ) + }) } pub(crate) fn len(&self) -> usize { self.map.len() @@ -1250,10 +2359,8 @@ impl From> for Insns { InsnFieldType::Memory(_) | InsnFieldType::SmallSlot(_) | InsnFieldType::BigSlot(_) - | InsnFieldType::SimOnlySlot(_) | InsnFieldType::SmallSlotArrayIndexed(_) | InsnFieldType::BigSlotArrayIndexed(_) - | InsnFieldType::SimOnlySlotArrayIndexed(_) | InsnFieldType::SmallUInt(_) | InsnFieldType::SmallSInt(_) | InsnFieldType::InternedBigInt(_) @@ -1287,7 +2394,6 @@ impl State { memories: _, small_slots: _, big_slots: _, - sim_only_slots: _, } = self; *pc = entry_pc; } @@ -1325,6 +2431,31 @@ impl BorrowedState<'_> { } } +impl TypeIndexRange { + #[must_use] + pub(crate) fn insns_for_copy_to(self, dest: TypeIndexRange) -> impl Iterator { + assert_eq!(self.len(), dest.len()); + let Self { + small_slots, + big_slots, + } = self; + small_slots + .iter() + .zip(dest.small_slots.iter()) + .map(|(src, dest)| Insn::CopySmall { dest, src }) + .chain( + big_slots + .iter() + .zip(dest.big_slots.iter()) + .map(|(src, dest)| Insn::Copy { dest, src }), + ) + } + #[must_use] + pub(crate) fn insns_for_copy_from(self, src: TypeIndexRange) -> impl Iterator { + src.insns_for_copy_to(self) + } +} + fn bigint_pow2(width: usize) -> Interned { #[derive(Copy, Clone, PartialEq, Eq, Hash)] struct MyMemoize; @@ -1431,6 +2562,18 @@ impl_insns! { main_loop!(); cleanup! {} } + Copy { + #[kind = Output] + dest: StatePartIndex, + #[kind = Input] + src: StatePartIndex, + } => { + if dest != src { + let [dest, src] = state.big_slots.get_many_mut([dest, src]); + dest.clone_from(src); + } + next!(); + } CopySmall { #[kind = Output] dest: StatePartIndex, @@ -1440,27 +2583,19 @@ impl_insns! { state.small_slots[dest] = state.small_slots[src]; next!(); } - Copy { + ReadIndexed { #[kind = Output] dest: StatePartIndex, #[kind = Input] - src: StatePartIndex, + src: StatePartArrayIndexed, } => { - if dest != src { - let [dest, src] = state.big_slots.get_disjoint_mut([dest, src]); - dest.clone_from(src); - } - next!(); - } - CloneSimOnly { - #[kind = Output] - dest: StatePartIndex, - #[kind = Input] - src: StatePartIndex, - } => { - if dest != src { - let [dest, src] = state.sim_only_slots.get_disjoint_mut([dest, src]); - dest.clone_from(src); + if let Some(src) = state.eval_array_indexed(src) { + if dest != src { + let [dest, src] = state.big_slots.get_many_mut([dest, src]); + dest.clone_from(src); + } + } else { + state.big_slots[dest] = BigInt::ZERO; } next!(); } @@ -1477,35 +2612,17 @@ impl_insns! { } next!(); } - ReadIndexed { + WriteIndexed { #[kind = Output] - dest: StatePartIndex, + dest: StatePartArrayIndexed, #[kind = Input] - src: StatePartArrayIndexed, + src: StatePartIndex, } => { - if let Some(src) = state.eval_array_indexed(src) { + if let Some(dest) = state.eval_array_indexed(dest) { if dest != src { - let [dest, src] = state.big_slots.get_disjoint_mut([dest, src]); + let [dest, src] = state.big_slots.get_many_mut([dest, src]); dest.clone_from(src); } - } else { - state.big_slots[dest] = BigInt::ZERO; - } - next!(); - } - ReadSimOnlyIndexed { - #[kind = Output] - dest: StatePartIndex, - #[kind = Input] - src: StatePartArrayIndexed, - } => { - if let Some(src) = state.eval_array_indexed(src) { - if dest != src { - let [dest, src] = state.sim_only_slots.get_disjoint_mut([dest, src]); - dest.clone_from(src); - } - } else { - state.sim_only_slots[dest] = state.sim_only_slots[dest].ty().default_value(); } next!(); } @@ -1520,34 +2637,6 @@ impl_insns! { } next!(); } - WriteIndexed { - #[kind = Output] - dest: StatePartArrayIndexed, - #[kind = Input] - src: StatePartIndex, - } => { - if let Some(dest) = state.eval_array_indexed(dest) { - if dest != src { - let [dest, src] = state.big_slots.get_disjoint_mut([dest, src]); - dest.clone_from(src); - } - } - next!(); - } - WriteSimOnlyIndexed { - #[kind = Output] - dest: StatePartArrayIndexed, - #[kind = Input] - src: StatePartIndex, - } => { - if let Some(dest) = state.eval_array_indexed(dest) { - if dest != src { - let [dest, src] = state.sim_only_slots.get_disjoint_mut([dest, src]); - dest.clone_from(src); - } - } - next!(); - } CastBigToArrayIndex { #[kind = Output] dest: StatePartIndex, diff --git a/crates/fayalite/src/sim/interpreter/parts.rs b/crates/fayalite/src/sim/interpreter/parts.rs deleted file mode 100644 index 8732146..0000000 --- a/crates/fayalite/src/sim/interpreter/parts.rs +++ /dev/null @@ -1,1052 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - array::Array, - intern::{Intern, Interned}, - sim::{ - interpreter::{ - Insn, InsnsBuilding, InsnsBuildingDone, InsnsBuildingKind, PrefixLinesWrapper, - SmallSInt, SmallUInt, State, - }, - value::{DynSimOnlyValue, DynSimOnly}, - }, - ty::CanonicalType, - util::{chain, const_str_cmp}, -}; -use bitvec::{boxed::BitBox, slice::BitSlice}; -use num_bigint::BigInt; -use std::{ - any::TypeId, - fmt::{self, Write}, - hash::Hash, - marker::PhantomData, - ops::Deref, -}; - -#[rustfmt::skip] -macro_rules! make_get_state_part_kinds { - ( - #![dollar = $d:tt] - $(state_part! { - singular_field = $state_singular_fields:ident; - plural_field = $state_plural_fields:ident; - kind = $state_kinds:ident; - singular_variant = $state_singular_variants:ident; - plural_variant = $state_plural_variants:ident; - })* - $(type_part! { - singular_field = $type_singular_fields:ident; - plural_field = $type_plural_fields:ident; - kind = $type_kinds:ident; - singular_variant = $type_singular_variants:ident; - plural_variant = $type_plural_variants:ident; - copy_insn = $copy_insn:ident; - read_indexed_insn = $read_indexed_insn:ident; - write_indexed_insn = $write_indexed_insn:ident; - array_indexed_variant = $array_indexed_variants:ident; - })* - ) => { - make_get_state_part_kinds! { - #![dollar = $d] - parts! { - #![part_names = [$(#[state] $state_singular_fields,)* $(#[type] $type_singular_fields,)*]] - [$(state_singular_fields = (#[state] $state_singular_fields),)* $(state_singular_fields = (#[type] $type_singular_fields),)*]; - [$(type_singular_fields = ($type_singular_fields),)*]; - [$(state_plural_fields = (#[state] $state_plural_fields),)* $(state_plural_fields = (#[type] $type_plural_fields),)*]; - [$(type_plural_fields = ($type_plural_fields),)*]; - [$(state_kinds = (#[state] $state_kinds),)* $(state_kinds = (#[type] $type_kinds),)*]; - [$(type_kinds = ($type_kinds),)*]; - [$(state_singular_variants = (#[state] $state_singular_variants),)* $(state_singular_variants = (#[type] $type_singular_variants),)*]; - [$(type_singular_variants = ($type_singular_variants),)*]; - [$(state_plural_variants = (#[state] $state_plural_variants),)* $(state_plural_variants = (#[type] $type_plural_variants),)*]; - [$(type_plural_variants = ($type_plural_variants),)*]; - [$(copy_insns = ($copy_insn),)*]; - [$(read_indexed_insns = ($read_indexed_insn),)*]; - [$(write_indexed_insns = ($write_indexed_insn),)*]; - [$(array_indexed_variants = ($array_indexed_variants),)*]; - } - } - }; - ( - #![dollar = $d:tt] - parts! { - #![part_names = [$(#[state] $state_part_name:ident,)* $(#[type] $type_part_name:ident,)*]] - $([ - $first_name:ident = ($($first_value:tt)*), - $($name:ident = ($($value:tt)*),)* - ];)* - } - ) => { - const _: () = { - $($(assert!(const_str_cmp(stringify!($first_name), stringify!($name)).is_eq());)*)* - }; - macro_rules! get_state_part_kinds { - ($d macro_ident:ident! {$d ($d args:tt)*}) => { - get_state_part_kinds! { - @expand - $d macro_ident! {} - ($d ($d args)*) - () - } - }; - ($d macro_ident:ident!($d ($d args:tt)*)) => { - get_state_part_kinds! { - @expand - $d macro_ident!() - ($d ($d args)*) - () - } - }; - ( - @expand - $d macro_ident:ident! {} - () - ($d ($d args:tt)*) - ) => { - $d macro_ident! { - $d ($d args)* - } - }; - ( - @expand - $d macro_ident:ident!() - () - ($d ($d args:tt)*) - ) => { - $d macro_ident!( - $d ($d args)* - ) - }; - ( - @expand - $d macro_ident:ident! $d group:tt - (, $d ($d rest:tt)*) - ($d ($d prev_args:tt)*) - ) => { - get_state_part_kinds! { - @expand - $d macro_ident! $d group - ($d ($d rest)*) - ($d ($d prev_args)*,) - } - }; - ( - @expand - $d macro_ident:ident! $d group:tt - (; $d ($d rest:tt)*) - ($d ($d prev_args:tt)*) - ) => { - get_state_part_kinds! { - @expand - $d macro_ident! $d group - ($d ($d rest)*) - ($d ($d prev_args)*;) - } - }; - ( - @expand - $d macro_ident:ident! $d group:tt - (#[custom] $d name:ident = [ - $d ($($state_part_name = $d $state_part_name:tt,)*)? - $($type_part_name = $d $type_part_name:tt,)* - ] - $d ($d rest:tt)* - ) - ($d ($d prev_args:tt)*) - ) => { - get_state_part_kinds! { - @expand - $d macro_ident! $d group - ($d ($d rest)*) - ($d ($d prev_args)* $d name = [ - $d ($($d $state_part_name,)*)? - $($d $type_part_name,)* - ]) - } - }; - $(( - @expand - $d macro_ident:ident! $d group:tt - ($first_name $d ($d rest:tt)*) - ($d ($d prev_args:tt)*) - ) => { - get_state_part_kinds! { - @expand - $d macro_ident! $d group - ($d ($d rest)*) - ($d ($d prev_args)* $first_name = [$($first_value)*, $($($value)*,)*]) - } - };)* - } - - pub(crate) use get_state_part_kinds; - }; -} - -make_get_state_part_kinds! { - #![dollar = $] - state_part! { - singular_field = memory; - plural_field = memories; - kind = StatePartKindMemories; - singular_variant = Memory; - plural_variant = Memories; - } - type_part! { - singular_field = small_slot; - plural_field = small_slots; - kind = StatePartKindSmallSlots; - singular_variant = SmallSlot; - plural_variant = SmallSlots; - copy_insn = CopySmall; - read_indexed_insn = ReadSmallIndexed; - write_indexed_insn = WriteSmallIndexed; - array_indexed_variant = SmallSlotArrayIndexed; - } - type_part! { - singular_field = big_slot; - plural_field = big_slots; - kind = StatePartKindBigSlots; - singular_variant = BigSlot; - plural_variant = BigSlots; - copy_insn = Copy; - read_indexed_insn = ReadIndexed; - write_indexed_insn = WriteIndexed; - array_indexed_variant = BigSlotArrayIndexed; - } - type_part! { - singular_field = sim_only_slot; - plural_field = sim_only_slots; - kind = StatePartKindSimOnlySlots; - singular_variant = SimOnlySlot; - plural_variant = SimOnlySlots; - copy_insn = CloneSimOnly; - read_indexed_insn = ReadSimOnlyIndexed; - write_indexed_insn = WriteSimOnlyIndexed; - array_indexed_variant = SimOnlySlotArrayIndexed; - } -} - -pub(crate) trait StatePartKind: - Send + Sync + Ord + Hash + fmt::Debug + 'static + Copy + Default -{ - const NAME: &'static str; - type DebugData: Send + Sync + Eq + Hash + fmt::Debug + 'static + Copy; - type LayoutData: Send + Sync + Eq + Hash + fmt::Debug + 'static + Copy; - type State: fmt::Debug + 'static + Clone; - type BorrowedState<'a>: 'a; - fn new_state(layout_data: &[Self::LayoutData]) -> Self::State; - fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a>; - fn part_debug_data( - state_layout: &StateLayout, - part_index: StatePartIndex, - ) -> Option<&Self::DebugData>; - fn debug_fmt_state_value( - state: &State, - index: StatePartIndex, - f: &mut impl fmt::Write, - ) -> fmt::Result; -} - -macro_rules! make_state_part_kinds { - ( - state_kinds = [$(#[$kind_attr:ident] $kind:ident,)*]; - ) => { - $( - #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy, Default)] - pub(crate) struct $kind; - )* - }; -} - -get_state_part_kinds! { - make_state_part_kinds! { - state_kinds; - } -} - -impl StatePartKind for StatePartKindMemories { - const NAME: &'static str = "Memories"; - type DebugData = (); - type LayoutData = MemoryData>; - type State = Box<[MemoryData]>; - type BorrowedState<'a> = &'a mut [MemoryData]; - fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { - layout_data - .iter() - .map(|MemoryData { array_type, data }| MemoryData { - array_type: *array_type, - data: BitBox::from_bitslice(data), - }) - .collect() - } - fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { - state - } - fn part_debug_data( - state_layout: &StateLayout, - part_index: StatePartIndex, - ) -> Option<&Self::DebugData> { - state_layout.memories.debug_data.get(part_index.as_usize()) - } - fn debug_fmt_state_value( - state: &State, - index: StatePartIndex, - f: &mut impl fmt::Write, - ) -> fmt::Result { - write!(f, "{:#?}", &state.memories[index]) - } -} - -impl StatePartKind for StatePartKindSmallSlots { - const NAME: &'static str = "SmallSlots"; - type DebugData = SlotDebugData; - type LayoutData = (); - type State = Box<[SmallUInt]>; - type BorrowedState<'a> = &'a mut [SmallUInt]; - fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { - vec![0; layout_data.len()].into_boxed_slice() - } - fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { - state - } - fn part_debug_data( - state_layout: &StateLayout, - part_index: StatePartIndex, - ) -> Option<&Self::DebugData> { - state_layout - .ty - .small_slots - .debug_data - .get(part_index.as_usize()) - } - fn debug_fmt_state_value( - state: &State, - index: StatePartIndex, - f: &mut impl fmt::Write, - ) -> fmt::Result { - let value = state.small_slots[index]; - write!(f, "{value:#x} {}", value as SmallSInt)?; - Ok(()) - } -} - -impl StatePartKind for StatePartKindBigSlots { - const NAME: &'static str = "BigSlots"; - type DebugData = SlotDebugData; - type LayoutData = (); - type State = Box<[BigInt]>; - type BorrowedState<'a> = &'a mut [BigInt]; - fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { - layout_data.iter().map(|_| BigInt::default()).collect() - } - fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { - state - } - fn part_debug_data( - state_layout: &StateLayout, - part_index: StatePartIndex, - ) -> Option<&Self::DebugData> { - state_layout - .ty - .big_slots - .debug_data - .get(part_index.as_usize()) - } - fn debug_fmt_state_value( - state: &State, - index: StatePartIndex, - f: &mut impl fmt::Write, - ) -> fmt::Result { - write!(f, "{:#x}", state.big_slots[index]) - } -} - -impl StatePartKind for StatePartKindSimOnlySlots { - const NAME: &'static str = "SimOnlySlots"; - type DebugData = SlotDebugData; - type LayoutData = DynSimOnly; - type State = Box<[DynSimOnlyValue]>; - type BorrowedState<'a> = &'a mut [DynSimOnlyValue]; - fn new_state(layout_data: &[Self::LayoutData]) -> Self::State { - layout_data.iter().map(|ty| ty.default_value()).collect() - } - fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { - state - } - fn part_debug_data( - state_layout: &StateLayout, - part_index: StatePartIndex, - ) -> Option<&Self::DebugData> { - state_layout - .ty - .sim_only_slots - .debug_data - .get(part_index.as_usize()) - } - fn debug_fmt_state_value( - state: &State, - index: StatePartIndex, - f: &mut impl fmt::Write, - ) -> fmt::Result { - write!(f, "{:?}", state.sim_only_slots[index]) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) struct StatePartIndex { - pub(crate) value: u32, - pub(crate) _phantom: PhantomData, -} - -impl StatePartIndex { - pub(crate) const ZERO: Self = Self::new(0); - pub(crate) const fn new(value: u32) -> Self { - Self { - value, - _phantom: PhantomData, - } - } - pub(crate) fn as_usize(self) -> usize { - self.value.try_into().expect("index too big") - } - pub(crate) fn offset(self, offset: StatePartIndex) -> Self { - Self::new( - self.value - .checked_add(offset.value) - .expect("offset too big"), - ) - } - pub(crate) fn debug_fmt( - &self, - f: &mut impl fmt::Write, - before_debug_info_text: &str, - comment_start: &str, - comment_line_start: &str, - comment_end: &str, - state_layout: Option<&StateLayout>, - state: Option<&State>, - ) -> fmt::Result { - write!(f, "StatePartIndex<{}>({})", K::NAME, self.value)?; - f.write_str(before_debug_info_text)?; - let debug_data = - state_layout.and_then(|state_layout| K::part_debug_data(state_layout, *self)); - if state.is_some() || debug_data.is_some() { - f.write_str(comment_start)?; - } - let mut f = PrefixLinesWrapper { - writer: f, - at_beginning_of_line: false, - blank_line_prefix: comment_line_start.trim_end(), - line_prefix: comment_line_start, - }; - if let Some(state) = state { - f.write_str("(")?; - K::debug_fmt_state_value(state, *self, &mut f)?; - f.write_str(")")?; - } - if state.is_some() && debug_data.is_some() { - f.write_str(" ")?; - } - if let Some(debug_data) = debug_data { - write!(f, "{debug_data:?}")?; - } - if state.is_some() || debug_data.is_some() { - f.writer.write_str(comment_end)?; - } - Ok(()) - } -} - -impl fmt::Debug for StatePartIndex { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.debug_fmt::(f, "", "", "", "", None, None) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub(crate) struct StatePartIndexRange { - pub(crate) start: StatePartIndex, - pub(crate) len: StatePartLen, -} - -impl StatePartIndexRange { - pub(crate) fn start(self) -> StatePartIndex { - self.start - } - pub(crate) fn end(self) -> StatePartIndex { - StatePartIndex::new( - self.start - .value - .checked_add(self.len.value) - .expect("state part allocation layout is too big"), - ) - } - pub(crate) fn len(self) -> StatePartLen { - self.len - } - pub(crate) fn is_empty(self) -> bool { - self.len.value == 0 - } - pub(crate) fn iter(self) -> impl Iterator> { - (self.start.value..self.end().value).map(StatePartIndex::new) - } - pub(crate) fn offset(self, offset: StatePartIndex) -> Self { - self.end().offset(offset); // check for overflow - Self { - start: self.start.offset(offset), - len: self.len, - } - } - pub(crate) fn slice(self, index: StatePartIndexRange) -> Self { - assert!(index.end().value <= self.len.value, "index out of range"); - Self { - start: StatePartIndex::new(self.start.value + index.start.value), - len: index.len, - } - } - pub(crate) fn index_array(self, element_size: StatePartLen, index: usize) -> Self { - if element_size.value == 0 { - assert_eq!( - self.len.value, 0, - "array with zero-sized element must also be zero-sized", - ); - return self; - } - assert!( - self.len.value % element_size.value == 0, - "array's size must be a multiple of its element size", - ); - self.slice(StatePartIndexRange { - start: StatePartIndex::new( - index - .try_into() - .ok() - .and_then(|index| element_size.value.checked_mul(index)) - .expect("index out of range"), - ), - len: element_size, - }) - } -} - -impl fmt::Debug for StatePartIndexRange { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "StatePartIndexRange<{}> {{ start: {}, len: {} }}", - K::NAME, - self.start.value, - self.len.value - ) - } -} - -#[derive(Copy, Clone, Hash, PartialEq, Eq)] -pub(crate) struct MemoryData> { - pub(crate) array_type: Array, - pub(crate) data: T, -} - -impl> fmt::Debug for MemoryData { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { array_type, data } = self; - f.debug_struct("MemoryData") - .field("array_type", array_type) - .field( - "data", - &crate::memory::DebugMemoryData::from_bit_slice(*array_type, data), - ) - .finish() - } -} - -macro_rules! make_state_layout { - ( - state_plural_fields = [$(#[state] $state_plural_field:ident,)* $(#[type] $type_plural_field:ident,)*]; - state_kinds = [$(#[state] $state_kind:ident,)* $(#[type] $type_kind:ident,)*]; - ) => { - #[derive(Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct StateLayout { - pub(crate) ty: TypeLayout, - $(pub(crate) $state_plural_field: StatePartLayout<$state_kind, BK>,)* - } - - impl Copy for StateLayout {} - - impl StateLayout { - pub(crate) fn len(&self) -> StateLen { - StateLen { - ty: self.ty.len(), - $($state_plural_field: self.$state_plural_field.len(),)* - } - } - pub(crate) fn is_empty(&self) -> bool { - self.ty.is_empty() $(&& self.$state_plural_field.is_empty())* - } - pub(crate) fn empty() -> Self { - Self { - ty: TypeLayout::empty(), - $($state_plural_field: StatePartLayout::empty(),)* - } - } - } - - impl StateLayout { - pub(crate) fn next_index(&self) -> StateIndex { - StateIndex { - ty: self.ty.next_index(), - $($state_plural_field: self.$state_plural_field.next_index(),)* - } - } - pub(crate) fn allocate( - &mut self, - layout: &StateLayout, - ) -> StateIndexRange { - StateIndexRange { - ty: self.ty.allocate(&layout.ty), - $($state_plural_field: self.$state_plural_field.allocate(&layout.$state_plural_field),)* - } - } - } - - impl From> for StateLayout { - fn from(v: StateLayout) -> Self { - Self { - ty: v.ty.into(), - $($state_plural_field: v.$state_plural_field.into(),)* - } - } - } - - #[derive(Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct TypeLayout { - $(pub(crate) $type_plural_field: StatePartLayout<$type_kind, BK>,)* - } - - impl Copy for TypeLayout {} - - impl TypeLayout { - pub(crate) fn len(&self) -> TypeLen { - TypeLen { - $($type_plural_field: self.$type_plural_field.len(),)* - } - } - pub(crate) fn is_empty(&self) -> bool { - $(self.$type_plural_field.is_empty())&&+ - } - pub(crate) fn empty() -> Self { - Self { - $($type_plural_field: StatePartLayout::empty(),)* - } - } - pub(crate) fn with_prefixed_debug_names(&self, prefix: &str) -> Self { - Self { - $($type_plural_field: self.$type_plural_field.with_prefixed_debug_names(prefix),)* - } - } - pub(crate) fn with_anonymized_debug_info(&self) -> Self { - Self { - $($type_plural_field: self.$type_plural_field.with_anonymized_debug_info(),)* - } - } - } - - impl TypeLayout { - pub(crate) fn next_index(&self) -> TypeIndex { - TypeIndex { - $($type_plural_field: self.$type_plural_field.next_index(),)* - } - } - pub(crate) fn allocate( - &mut self, - layout: &TypeLayout, - ) -> TypeIndexRange { - TypeIndexRange { - $($type_plural_field: self.$type_plural_field.allocate(&layout.$type_plural_field),)* - } - } - } - - impl From> for TypeLayout { - fn from(v: TypeLayout) -> Self { - Self { - $($type_plural_field: v.$type_plural_field.into(),)* - } - } - } - }; -} - -get_state_part_kinds! { - make_state_layout! { - state_plural_fields; - state_kinds; - } -} - -#[derive(Clone, PartialEq, Eq, Hash)] -pub(crate) struct StatePartLayout { - pub(crate) debug_data: BK::Vec, - pub(crate) layout_data: BK::Vec, - pub(crate) _phantom: PhantomData, -} - -impl Copy for StatePartLayout {} - -impl StatePartLayout { - pub(crate) fn len(&self) -> StatePartLen { - StatePartLen::new( - self.debug_data - .len() - .try_into() - .expect("state part allocation layout is too big"), - ) - } - pub(crate) fn is_empty(&self) -> bool { - self.debug_data.is_empty() - } - pub(crate) fn empty() -> Self { - Self { - debug_data: Default::default(), - layout_data: Default::default(), - _phantom: PhantomData, - } - } - pub(crate) fn debug_data(&self, index: StatePartIndex) -> &K::DebugData { - &self.debug_data[index.as_usize()] - } -} - -impl From> - for StatePartLayout -{ - fn from(value: StatePartLayout) -> Self { - Self { - debug_data: Intern::intern_owned(value.debug_data), - layout_data: Intern::intern_owned(value.layout_data), - _phantom: PhantomData, - } - } -} - -impl StatePartLayout { - pub(crate) fn scalar(debug_data: K::DebugData, layout_data: K::LayoutData) -> Self { - Self { - debug_data: vec![debug_data], - layout_data: vec![layout_data], - _phantom: PhantomData, - } - } - pub(crate) fn next_index(&self) -> StatePartIndex { - StatePartIndex::new(self.len().value) - } - pub(crate) fn allocate( - &mut self, - layout: &StatePartLayout, - ) -> StatePartIndexRange { - let start = self.next_index(); - let len = layout.len(); - let Self { - debug_data, - layout_data, - _phantom: _, - } = self; - debug_data.extend_from_slice(&layout.debug_data); - layout_data.extend_from_slice(&layout.layout_data); - StatePartIndexRange { start, len } - } -} - -impl fmt::Debug for StatePartLayout { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - debug_data, - layout_data, - _phantom: _, - } = self; - write!(f, "StatePartLayout<{}>", K::NAME)?; - let mut debug_struct = f.debug_struct(""); - debug_struct - .field("len", &debug_data.len()) - .field("debug_data", debug_data); - if TypeId::of::() != TypeId::of::<()>() { - debug_struct.field("layout_data", layout_data); - } - debug_struct.finish_non_exhaustive() - } -} - -impl, BK: InsnsBuildingKind> StatePartLayout { - pub(crate) fn with_prefixed_debug_names(&self, prefix: &str) -> Self { - Self { - debug_data: self - .debug_data - .iter() - .map(|v| v.with_prefixed_debug_names(prefix)) - .collect(), - layout_data: self.layout_data.clone(), - _phantom: PhantomData, - } - } - pub(crate) fn with_anonymized_debug_info(&self) -> Self { - Self { - debug_data: self - .debug_data - .iter() - .map(|v| v.with_anonymized_debug_info()) - .collect(), - layout_data: self.layout_data.clone(), - _phantom: PhantomData, - } - } -} - -macro_rules! make_state_len { - ( - state_plural_fields = [$(#[state] $state_plural_field:ident,)* $(#[type] $type_plural_field:ident,)*]; - state_kinds = [$(#[state] $state_kind:ident,)* $(#[type] $type_kind:ident,)*]; - type_singular_variants = [$($type_singular_variant:ident,)*]; - type_singular_fields = [$($type_singular_field:ident,)*]; - ) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct StateLen { - pub(crate) ty: TypeLen, - $(pub(crate) $state_plural_field: StatePartLen<$state_kind>,)* - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct TypeLen { - $(pub(crate) $type_plural_field: StatePartLen<$type_kind>,)* - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) enum TypeLenSingle { - $($type_singular_variant,)* - } - - impl TypeLen { - pub(crate) const fn as_index(self) -> TypeIndex { - TypeIndex { - $($type_plural_field: self.$type_plural_field.as_index(),)* - } - } - pub(crate) const fn empty() -> Self { - Self { - $($type_plural_field: StatePartLen::new(0),)* - } - } - $(pub(crate) const fn $type_singular_field() -> Self { - let mut retval = Self::empty(); - retval.$type_plural_field.value = 1; - retval - })* - pub(crate) const fn as_single(self) -> Option { - $({ - const SINGLE: TypeLen = TypeLen::$type_singular_field(); - if let SINGLE = self { - return Some(TypeLenSingle::$type_singular_variant); - } - })* - None - } - pub(crate) const fn only_small(mut self) -> Option> { - const EMPTY: TypeLen = TypeLen::empty(); - let retval = self.small_slots; - self.small_slots.value = 0; - if let EMPTY = self { - Some(retval) - } else { - None - } - } - } - }; -} - -get_state_part_kinds! { - make_state_len! { - state_plural_fields; - state_kinds; - type_singular_variants; - type_singular_fields; - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) struct StatePartLen { - pub(crate) value: u32, - pub(crate) _phantom: PhantomData, -} - -impl StatePartLen { - pub(crate) const fn new(value: u32) -> Self { - Self { - value, - _phantom: PhantomData, - } - } - pub(crate) const fn as_index(self) -> StatePartIndex { - StatePartIndex::new(self.value) - } -} - -impl fmt::Debug for StatePartLen { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "StatePartLen<{}>({})", K::NAME, self.value) - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub(crate) struct SlotDebugData { - pub(crate) name: Interned, - pub(crate) ty: CanonicalType, -} - -impl SlotDebugData { - pub(crate) fn with_prefixed_debug_names(&self, prefix: &str) -> Self { - let mut name = String::with_capacity(self.name.len() + prefix.len()); - name.push_str(prefix); - name.push_str(&self.name); - Self { - name: Intern::intern_owned(name), - ty: self.ty, - } - } - pub(crate) fn with_anonymized_debug_info(&self) -> Self { - Self { - name: Interned::default(), - ty: self.ty, - } - } -} - -macro_rules! make_state_index { - ( - state_plural_fields = [$(#[state] $state_plural_field:ident,)* $(#[type] $type_plural_field:ident,)*]; - state_kinds = [$(#[state] $state_kind:ident,)* $(#[type] $type_kind:ident,)*]; - ) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct StateIndex { - pub(crate) ty: TypeIndex, - $(pub(crate) $state_plural_field: StatePartIndex<$state_kind>,)* - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct TypeIndex { - $(pub(crate) $type_plural_field: StatePartIndex<$type_kind>,)* - } - - impl TypeIndex { - pub(crate) const ZERO: Self = Self { - $($type_plural_field: StatePartIndex::ZERO,)* - }; - pub(crate) fn offset(self, offset: TypeIndex) -> Self { - Self { - $($type_plural_field: self.$type_plural_field.offset(offset.$type_plural_field),)* - } - } - } - }; -} - -get_state_part_kinds! { - make_state_index! { - state_plural_fields; - state_kinds; - } -} - -macro_rules! make_state_index_range { - ( - state_plural_fields = [$(#[state] $state_plural_field:ident,)* $(#[type] $type_plural_field:ident,)*]; - state_kinds = [$(#[state] $state_kind:ident,)* $(#[type] $type_kind:ident,)*]; - copy_insns = [$($copy_insn:ident,)*]; - ) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct StateIndexRange { - pub(crate) ty: TypeIndexRange, - $(pub(crate) $state_plural_field: StatePartIndexRange<$state_kind>,)* - } - - impl StateIndexRange { - pub(crate) fn start(self) -> StateIndex { - StateIndex { - ty: self.ty.start(), - $($state_plural_field: self.$state_plural_field.start(),)* - } - } - pub(crate) fn len(self) -> StateLen { - StateLen { - ty: self.ty.len(), - $($state_plural_field: self.$state_plural_field.len(),)* - } - } - pub(crate) fn is_empty(self) -> bool { - self.ty.is_empty() $(&& self.$state_plural_field.is_empty())* - } - } - - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - pub(crate) struct TypeIndexRange { - $(pub(crate) $type_plural_field: StatePartIndexRange<$type_kind>,)* - } - - impl TypeIndexRange { - pub(crate) fn new(start: TypeIndex, len: TypeLen) -> Self { - Self { - $($type_plural_field: StatePartIndexRange { - start: start.$type_plural_field, - len: len.$type_plural_field, - },)* - } - } - pub(crate) fn start(self) -> TypeIndex { - TypeIndex { - $($type_plural_field: self.$type_plural_field.start(),)* - } - } - pub(crate) fn len(self) -> TypeLen { - TypeLen { - $($type_plural_field: self.$type_plural_field.len(),)* - } - } - pub(crate) fn is_empty(self) -> bool { - $(self.$type_plural_field.is_empty()) &&+ - } - pub(crate) fn slice(self, index: TypeIndexRange) -> Self { - Self { - $($type_plural_field: self.$type_plural_field.slice(index.$type_plural_field),)* - } - } - pub(crate) fn index_array(self, element_size: TypeLen, index: usize) -> Self { - Self { - $($type_plural_field: self.$type_plural_field.index_array(element_size.$type_plural_field, index),)* - } - } - pub(crate) fn offset(self, offset: TypeIndex) -> Self { - Self { - $($type_plural_field: self.$type_plural_field.offset(offset.$type_plural_field),)* - } - } - #[must_use] - pub(crate) fn insns_for_copy_to(self, dest: TypeIndexRange) -> impl Iterator { - assert_eq!(self.len(), dest.len()); - chain!($(self.$type_plural_field.iter().zip(dest.$type_plural_field.iter()).map(|(src, dest)| Insn::$copy_insn { dest, src })),*) - } - #[must_use] - pub(crate) fn insns_for_copy_from(self, src: TypeIndexRange) -> impl Iterator { - src.insns_for_copy_to(self) - } - } - }; -} - -get_state_part_kinds! { - make_state_index_range! { - state_plural_fields; - state_kinds; - copy_insns; - } -} diff --git a/crates/fayalite/src/sim/value.rs b/crates/fayalite/src/sim/value.rs deleted file mode 100644 index 9717417..0000000 --- a/crates/fayalite/src/sim/value.rs +++ /dev/null @@ -1,1344 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - array::{Array, ArrayType}, - bundle::{Bundle, BundleType}, - clock::Clock, - enum_::{Enum, EnumType}, - expr::{CastBitsTo, Expr, ToExpr}, - int::{Bool, IntType, KnownSize, SInt, SIntType, SIntValue, Size, UInt, UIntType, UIntValue}, - reset::{AsyncReset, Reset, SyncReset}, - source_location::SourceLocation, - ty::{ - CanonicalType, OpaqueSimValue, OpaqueSimValueSize, OpaqueSimValueSlice, - OpaqueSimValueWriter, StaticType, Type, TypeProperties, impl_match_variant_as_self, - }, - util::{ - ConstUsize, HashMap, - alternating_cell::{AlternatingCell, AlternatingCellMethods}, - }, -}; -use bitvec::{slice::BitSlice, vec::BitVec}; -use hashbrown::hash_map::Entry; -use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _, ser::Error as _}; -use std::{ - borrow::Cow, - fmt::{self, Write}, - hash::{BuildHasher, Hash, Hasher, RandomState}, - ops::{Deref, DerefMut}, - sync::{Arc, Mutex}, -}; - -pub(crate) mod sim_only_value_unsafe; - -pub use sim_only_value_unsafe::{ - DynSimOnly, DynSimOnlyValue, SimOnly, SimOnlyValue, SimOnlyValueTrait, -}; - -#[derive(Copy, Clone, Eq, PartialEq)] -enum ValidFlags { - BothValid = 0, - OnlyValueValid = 1, - OnlyOpaqueValid = 2, -} - -#[derive(Clone)] -struct SimValueInner { - value: T::SimValue, - opaque: OpaqueSimValue, - valid_flags: ValidFlags, - ty: T, - sim_only_values_len: usize, -} - -impl SimValueInner { - fn size(&self) -> OpaqueSimValueSize { - OpaqueSimValueSize { - bit_width: self.opaque.bit_width(), - sim_only_values_len: self.sim_only_values_len, - } - } - fn fill_opaque(&mut self) { - match self.valid_flags { - ValidFlags::BothValid | ValidFlags::OnlyOpaqueValid => {} - ValidFlags::OnlyValueValid => { - OpaqueSimValueWriter::rewrite_with(self.size(), &mut self.opaque, |writer| { - self.ty.sim_value_to_opaque(&self.value, writer) - }); - self.valid_flags = ValidFlags::BothValid; - } - } - } - fn into_opaque(mut self) -> OpaqueSimValue { - self.fill_opaque(); - self.opaque - } - fn opaque_mut(&mut self) -> &mut OpaqueSimValue { - self.fill_opaque(); - self.valid_flags = ValidFlags::OnlyOpaqueValid; - &mut self.opaque - } - fn fill_value(&mut self) { - match self.valid_flags { - ValidFlags::BothValid | ValidFlags::OnlyValueValid => {} - ValidFlags::OnlyOpaqueValid => { - self.ty - .sim_value_clone_from_opaque(&mut self.value, self.opaque.as_slice()); - self.valid_flags = ValidFlags::BothValid; - } - } - } - fn into_value(mut self) -> T::SimValue { - self.fill_value(); - self.value - } - fn value_mut(&mut self) -> &mut T::SimValue { - self.fill_value(); - self.valid_flags = ValidFlags::OnlyValueValid; - &mut self.value - } -} - -impl AlternatingCellMethods for SimValueInner { - fn unique_to_shared(&mut self) { - match self.valid_flags { - ValidFlags::BothValid => return, - ValidFlags::OnlyValueValid => { - OpaqueSimValueWriter::rewrite_with(self.size(), &mut self.opaque, |writer| { - self.ty.sim_value_to_opaque(&self.value, writer) - }) - } - ValidFlags::OnlyOpaqueValid => self - .ty - .sim_value_clone_from_opaque(&mut self.value, self.opaque.as_slice()), - } - self.valid_flags = ValidFlags::BothValid; - } - - fn shared_to_unique(&mut self) {} -} - -#[derive(Serialize, Deserialize)] -#[serde(rename = "SimValue")] -#[serde(bound( - serialize = "T: Type + Serialize", - deserialize = "T: Type> + Deserialize<'de>" -))] -struct SerdeSimValue<'a, T: Type> { - ty: T, - value: std::borrow::Cow<'a, T::SimValue>, -} - -impl + Serialize> Serialize for SimValue { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - SerdeSimValue { - ty: SimValue::ty(self), - value: std::borrow::Cow::Borrowed(&*self), - } - .serialize(serializer) - } -} - -impl<'de, T: Type> + Deserialize<'de>> Deserialize<'de> for SimValue { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let SerdeSimValue { ty, value } = SerdeSimValue::::deserialize(deserializer)?; - Ok(SimValue::from_value(ty, value.into_owned())) - } -} - -pub struct SimValue { - inner: AlternatingCell>, -} - -impl Clone for SimValue { - fn clone(&self) -> Self { - Self { - inner: AlternatingCell::new_unique(self.inner.share().clone()), - } - } -} - -impl SimValue { - #[track_caller] - pub fn from_opaque(ty: T, opaque: OpaqueSimValue) -> Self { - let size = ty.canonical().size(); - assert_eq!(size, opaque.size()); - let inner = SimValueInner { - value: ty.sim_value_from_opaque(opaque.as_slice()), - opaque, - valid_flags: ValidFlags::BothValid, - ty, - sim_only_values_len: size.sim_only_values_len, - }; - Self { - inner: AlternatingCell::new_shared(inner), - } - } - #[track_caller] - pub fn from_bitslice(ty: T, bits: &BitSlice) -> Self { - Self::from_bitslice_and_sim_only_values(ty, bits, Vec::new()) - } - #[track_caller] - pub fn from_bitslice_and_sim_only_values( - ty: T, - bits: &BitSlice, - sim_only_values: Vec, - ) -> Self { - Self::from_opaque( - ty, - OpaqueSimValue::from_bitslice_and_sim_only_values(bits, sim_only_values), - ) - } - pub fn from_value(ty: T, value: T::SimValue) -> Self { - let type_properties = ty.canonical().type_properties(); - let inner = SimValueInner { - opaque: OpaqueSimValue::from_bits_and_sim_only_values( - UIntValue::new_dyn(Arc::new(BitVec::repeat(false, type_properties.bit_width))), - Vec::with_capacity(type_properties.sim_only_values_len), - ), - value, - valid_flags: ValidFlags::OnlyValueValid, - ty, - sim_only_values_len: type_properties.sim_only_values_len, - }; - Self { - inner: AlternatingCell::new_unique(inner), - } - } - pub fn ty(this: &Self) -> T { - this.inner.share().ty - } - pub fn into_opaque(this: Self) -> OpaqueSimValue { - this.inner.into_inner().into_opaque() - } - pub fn into_ty_and_opaque(this: Self) -> (T, OpaqueSimValue) { - let inner = this.inner.into_inner(); - (inner.ty, inner.into_opaque()) - } - pub fn opaque(this: &Self) -> &OpaqueSimValue { - &this.inner.share().opaque - } - pub fn opaque_mut(this: &mut Self) -> &mut OpaqueSimValue { - this.inner.unique().opaque_mut() - } - pub fn bits(this: &Self) -> &UIntValue { - Self::opaque(this).bits() - } - pub fn bits_mut(this: &mut Self) -> &mut UIntValue { - Self::opaque_mut(this).bits_mut() - } - pub fn into_value(this: Self) -> T::SimValue { - this.inner.into_inner().into_value() - } - pub fn value(this: &Self) -> &T::SimValue { - &this.inner.share().value - } - pub fn value_mut(this: &mut Self) -> &mut T::SimValue { - this.inner.unique().value_mut() - } - #[track_caller] - pub fn from_canonical(v: SimValue) -> Self { - let (ty, opaque) = SimValue::into_ty_and_opaque(v); - Self::from_opaque(T::from_canonical(ty), opaque) - } - pub fn into_canonical(this: Self) -> SimValue { - let (ty, opaque) = Self::into_ty_and_opaque(this); - SimValue::from_opaque(ty.canonical(), opaque) - } - pub fn canonical(this: &Self) -> SimValue { - SimValue::from_opaque(Self::ty(this).canonical(), Self::opaque(this).clone()) - } - #[track_caller] - pub fn from_dyn_int(v: SimValue) -> Self - where - T: IntType, - { - let (ty, opaque) = SimValue::into_ty_and_opaque(v); - SimValue::from_opaque(T::from_dyn_int(ty), opaque) - } - pub fn into_dyn_int(this: Self) -> SimValue - where - T: IntType, - { - let (ty, opaque) = Self::into_ty_and_opaque(this); - SimValue::from_opaque(ty.as_dyn_int(), opaque) - } - pub fn to_dyn_int(this: &Self) -> SimValue - where - T: IntType, - { - SimValue::from_opaque(Self::ty(this).as_dyn_int(), Self::opaque(&this).clone()) - } - #[track_caller] - pub fn from_bundle(v: SimValue) -> Self - where - T: BundleType, - { - let (ty, opaque) = SimValue::into_ty_and_opaque(v); - SimValue::from_opaque(T::from_canonical(CanonicalType::Bundle(ty)), opaque) - } - pub fn into_bundle(this: Self) -> SimValue - where - T: BundleType, - { - let (ty, opaque) = Self::into_ty_and_opaque(this); - SimValue::from_opaque(Bundle::from_canonical(ty.canonical()), opaque) - } - pub fn to_bundle(this: &Self) -> SimValue - where - T: BundleType, - { - SimValue::from_opaque( - Bundle::from_canonical(Self::ty(this).canonical()), - Self::opaque(&this).clone(), - ) - } - #[track_caller] - pub fn from_enum(v: SimValue) -> Self - where - T: EnumType, - { - let (ty, opaque) = SimValue::into_ty_and_opaque(v); - SimValue::from_opaque(T::from_canonical(CanonicalType::Enum(ty)), opaque) - } - pub fn into_enum(this: Self) -> SimValue - where - T: EnumType, - { - let (ty, opaque) = Self::into_ty_and_opaque(this); - SimValue::from_opaque(Enum::from_canonical(ty.canonical()), opaque) - } - pub fn to_enum(this: &Self) -> SimValue - where - T: EnumType, - { - SimValue::from_opaque( - Enum::from_canonical(Self::ty(this).canonical()), - Self::opaque(&this).clone(), - ) - } -} - -impl Deref for SimValue { - type Target = T::SimValue; - - fn deref(&self) -> &Self::Target { - Self::value(self) - } -} - -impl DerefMut for SimValue { - fn deref_mut(&mut self) -> &mut Self::Target { - Self::value_mut(self) - } -} - -impl fmt::Debug for SimValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let inner = self.inner.share(); - f.debug_struct("SimValue") - .field("ty", &inner.ty) - .field("value", &inner.value) - .finish() - } -} - -impl ToExpr for SimValue { - type Type = T; - - #[track_caller] - fn to_expr(&self) -> Expr { - let inner = self.inner.share(); - assert_eq!( - inner.sim_only_values_len, 0, - "can't convert sim-only values to Expr" - ); - inner.opaque.bits().cast_bits_to(inner.ty) - } -} - -pub trait SimValuePartialEq: Type { - #[track_caller] - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool; -} - -impl, U: Type> PartialEq> for SimValue { - #[track_caller] - fn eq(&self, other: &SimValue) -> bool { - T::sim_value_eq(self, other) - } -} - -impl SimValuePartialEq for UIntType { - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - **this == **other - } -} - -impl SimValuePartialEq for SIntType { - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - **this == **other - } -} - -impl SimValuePartialEq for Bool { - fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { - **this == **other - } -} - -pub trait ToSimValue: ToSimValueWithType<::Type> { - type Type: Type; - - #[track_caller] - fn to_sim_value(&self) -> SimValue; - #[track_caller] - fn into_sim_value(self) -> SimValue - where - Self: Sized, - { - self.to_sim_value() - } - #[track_caller] - fn arc_into_sim_value(self: Arc) -> SimValue { - self.to_sim_value() - } - #[track_caller] - fn arc_to_sim_value(self: &Arc) -> SimValue { - self.to_sim_value() - } -} - -pub trait ToSimValueWithType { - #[track_caller] - fn to_sim_value_with_type(&self, ty: T) -> SimValue; - #[track_caller] - fn into_sim_value_with_type(self, ty: T) -> SimValue - where - Self: Sized, - { - self.to_sim_value_with_type(ty) - } - #[track_caller] - fn arc_into_sim_value_with_type(self: Arc, ty: T) -> SimValue { - self.to_sim_value_with_type(ty) - } - #[track_caller] - fn arc_to_sim_value_with_type(self: &Arc, ty: T) -> SimValue { - self.to_sim_value_with_type(ty) - } -} - -macro_rules! forward_to_sim_value_with_type { - ([$($generics:tt)*] $ty:ty) => { - impl<$($generics)*> ToSimValueWithType<::Type> for $ty { - fn to_sim_value_with_type(&self, ty: ::Type) -> SimValue<::Type> { - let retval = Self::to_sim_value(self); - assert_eq!(SimValue::ty(&retval), ty); - retval - } - #[track_caller] - fn into_sim_value_with_type(self, ty: ::Type) -> SimValue<::Type> - where - Self: Sized, - { - let retval = Self::into_sim_value(self); - assert_eq!(SimValue::ty(&retval), ty); - retval - } - #[track_caller] - fn arc_into_sim_value_with_type(self: Arc, ty: ::Type) -> SimValue<::Type> { - let retval = Self::arc_into_sim_value(self); - assert_eq!(SimValue::ty(&retval), ty); - retval - } - #[track_caller] - fn arc_to_sim_value_with_type(self: &Arc, ty: ::Type) -> SimValue<::Type> { - let retval = Self::arc_to_sim_value(self); - assert_eq!(SimValue::ty(&retval), ty); - retval - } - } - }; -} - -impl ToSimValue for SimValue { - type Type = T; - fn to_sim_value(&self) -> SimValue { - self.clone() - } - - fn into_sim_value(self) -> SimValue { - self - } -} - -forward_to_sim_value_with_type!([T: Type] SimValue); - -impl ToSimValueWithType for BitVec { - #[track_caller] - fn to_sim_value_with_type(&self, ty: T) -> SimValue { - self.clone().into_sim_value_with_type(ty) - } - - #[track_caller] - fn into_sim_value_with_type(self, ty: T) -> SimValue { - Arc::new(self).arc_into_sim_value_with_type(ty) - } - - #[track_caller] - fn arc_into_sim_value_with_type(self: Arc, ty: T) -> SimValue { - SimValue::from_opaque(ty, OpaqueSimValue::from_bits(UIntValue::new_dyn(self))) - } - - #[track_caller] - fn arc_to_sim_value_with_type(self: &Arc, ty: T) -> SimValue { - SimValue::from_opaque( - ty, - OpaqueSimValue::from_bits(UIntValue::new_dyn(self.clone())), - ) - } -} - -impl ToSimValueWithType for bitvec::boxed::BitBox { - #[track_caller] - fn to_sim_value_with_type(&self, ty: T) -> SimValue { - self.clone().into_sim_value_with_type(ty) - } - - #[track_caller] - fn into_sim_value_with_type(self, ty: T) -> SimValue { - self.into_bitvec().into_sim_value_with_type(ty) - } -} - -impl ToSimValueWithType for BitSlice { - #[track_caller] - fn to_sim_value_with_type(&self, ty: T) -> SimValue { - self.to_bitvec().into_sim_value_with_type(ty) - } -} - -impl ToSimValue for &'_ This { - type Type = This::Type; - - fn to_sim_value(&self) -> SimValue { - This::to_sim_value(self) - } -} - -impl, T: Type> ToSimValueWithType for &'_ This { - fn to_sim_value_with_type(&self, ty: T) -> SimValue { - This::to_sim_value_with_type(self, ty) - } -} - -impl ToSimValue for &'_ mut This { - type Type = This::Type; - - fn to_sim_value(&self) -> SimValue { - This::to_sim_value(self) - } -} - -impl, T: Type> ToSimValueWithType for &'_ mut This { - fn to_sim_value_with_type(&self, ty: T) -> SimValue { - This::to_sim_value_with_type(self, ty) - } -} - -impl ToSimValue for Arc { - type Type = This::Type; - - fn to_sim_value(&self) -> SimValue { - This::arc_to_sim_value(self) - } - fn into_sim_value(self) -> SimValue { - This::arc_into_sim_value(self) - } -} - -impl, T: Type> ToSimValueWithType for Arc { - fn to_sim_value_with_type(&self, ty: T) -> SimValue { - This::arc_to_sim_value_with_type(self, ty) - } - fn into_sim_value_with_type(self, ty: T) -> SimValue { - This::arc_into_sim_value_with_type(self, ty) - } -} - -impl ToSimValue - for crate::intern::Interned -{ - type Type = This::Type; - fn to_sim_value(&self) -> SimValue { - This::to_sim_value(self) - } -} - -impl + Send + Sync + 'static, T: Type> ToSimValueWithType - for crate::intern::Interned -{ - fn to_sim_value_with_type(&self, ty: T) -> SimValue { - This::to_sim_value_with_type(self, ty) - } -} - -impl ToSimValue for Box { - type Type = This::Type; - - fn to_sim_value(&self) -> SimValue { - This::to_sim_value(self) - } - fn into_sim_value(self) -> SimValue { - This::into_sim_value(*self) - } -} - -impl, T: Type> ToSimValueWithType for Box { - fn to_sim_value_with_type(&self, ty: T) -> SimValue { - This::to_sim_value_with_type(self, ty) - } - fn into_sim_value_with_type(self, ty: T) -> SimValue { - This::into_sim_value_with_type(*self, ty) - } -} - -impl SimValue> { - #[track_caller] - pub fn from_array_elements>>( - ty: ArrayType, - elements: I, - ) -> Self { - let element_ty = ty.element(); - let elements = Vec::from_iter( - elements - .into_iter() - .map(|element| element.into_sim_value_with_type(element_ty)), - ); - assert_eq!(elements.len(), ty.len()); - SimValue::from_value(ty, elements.try_into().ok().expect("already checked len")) - } -} - -impl, T: Type> ToSimValueWithType> for [Element] { - #[track_caller] - fn to_sim_value_with_type(&self, ty: Array) -> SimValue> { - SimValue::from_array_elements(ty, self) - } -} - -impl> ToSimValue for [Element] { - type Type = Array; - - #[track_caller] - fn to_sim_value(&self) -> SimValue { - SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self) - } -} - -impl> ToSimValueWithType for [Element] { - #[track_caller] - fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue { - SimValue::into_canonical(SimValue::from_array_elements( - ::from_canonical(ty), - self, - )) - } -} - -impl, T: Type, const N: usize> ToSimValueWithType> - for [Element; N] -where - ConstUsize: KnownSize, -{ - #[track_caller] - fn to_sim_value_with_type(&self, ty: Array) -> SimValue> { - SimValue::from_array_elements(ty, self) - } - #[track_caller] - fn into_sim_value_with_type(self, ty: Array) -> SimValue> { - SimValue::from_array_elements(ty, self) - } -} - -impl, const N: usize> ToSimValue for [Element; N] -where - ConstUsize: KnownSize, -{ - type Type = Array; - - fn to_sim_value(&self) -> SimValue { - SimValue::from_array_elements(StaticType::TYPE, self) - } - - fn into_sim_value(self) -> SimValue { - SimValue::from_array_elements(StaticType::TYPE, self) - } -} - -impl, T: Type, const N: usize> ToSimValueWithType> - for [Element; N] -{ - #[track_caller] - fn to_sim_value_with_type(&self, ty: Array) -> SimValue> { - SimValue::from_array_elements(ty, self) - } - #[track_caller] - fn into_sim_value_with_type(self, ty: Array) -> SimValue> { - SimValue::from_array_elements(ty, self) - } -} - -impl, const N: usize> ToSimValueWithType - for [Element; N] -{ - #[track_caller] - fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue { - SimValue::into_canonical(SimValue::from_array_elements( - ::from_canonical(ty), - self, - )) - } - #[track_caller] - fn into_sim_value_with_type(self, ty: CanonicalType) -> SimValue { - SimValue::into_canonical(SimValue::from_array_elements( - ::from_canonical(ty), - self, - )) - } -} - -impl, T: Type> ToSimValueWithType> for Vec { - #[track_caller] - fn to_sim_value_with_type(&self, ty: Array) -> SimValue> { - SimValue::from_array_elements(ty, self) - } - #[track_caller] - fn into_sim_value_with_type(self, ty: Array) -> SimValue> { - SimValue::from_array_elements(ty, self) - } -} - -impl> ToSimValue for Vec { - type Type = Array; - - fn to_sim_value(&self) -> SimValue { - SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self) - } - - fn into_sim_value(self) -> SimValue { - SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self) - } -} - -impl> ToSimValueWithType - for Vec -{ - #[track_caller] - fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue { - SimValue::into_canonical(SimValue::from_array_elements( - ::from_canonical(ty), - self, - )) - } - #[track_caller] - fn into_sim_value_with_type(self, ty: CanonicalType) -> SimValue { - SimValue::into_canonical(SimValue::from_array_elements( - ::from_canonical(ty), - self, - )) - } -} - -impl, T: Type> ToSimValueWithType> for Box<[Element]> { - #[track_caller] - fn to_sim_value_with_type(&self, ty: Array) -> SimValue> { - SimValue::from_array_elements(ty, self) - } - #[track_caller] - fn into_sim_value_with_type(self, ty: Array) -> SimValue> { - SimValue::from_array_elements(ty, self) - } -} - -impl> ToSimValue for Box<[Element]> { - type Type = Array; - - fn to_sim_value(&self) -> SimValue { - SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self) - } - - fn into_sim_value(self) -> SimValue { - SimValue::from_array_elements(ArrayType::new_dyn(StaticType::TYPE, self.len()), self) - } -} - -impl> ToSimValueWithType - for Box<[Element]> -{ - #[track_caller] - fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue { - SimValue::into_canonical(SimValue::from_array_elements( - ::from_canonical(ty), - self, - )) - } - #[track_caller] - fn into_sim_value_with_type(self, ty: CanonicalType) -> SimValue { - SimValue::into_canonical(SimValue::from_array_elements( - ::from_canonical(ty), - self, - )) - } -} - -impl ToSimValue for Expr { - type Type = T; - #[track_caller] - fn to_sim_value(&self) -> SimValue { - SimValue::from_bitslice( - Expr::ty(*self), - &crate::expr::ToLiteralBits::to_literal_bits(self) - .expect("must be a literal expression"), - ) - } -} - -forward_to_sim_value_with_type!([T: Type] Expr); - -macro_rules! impl_to_sim_value_for_bool_like { - ($ty:ident) => { - impl ToSimValueWithType<$ty> for bool { - fn to_sim_value_with_type(&self, ty: $ty) -> SimValue<$ty> { - SimValue::from_value(ty, *self) - } - } - }; -} - -impl ToSimValue for bool { - type Type = Bool; - - fn to_sim_value(&self) -> SimValue { - SimValue::from_value(Bool, *self) - } -} - -impl_to_sim_value_for_bool_like!(Bool); -impl_to_sim_value_for_bool_like!(AsyncReset); -impl_to_sim_value_for_bool_like!(SyncReset); -impl_to_sim_value_for_bool_like!(Reset); -impl_to_sim_value_for_bool_like!(Clock); - -impl ToSimValueWithType for bool { - #[track_caller] - fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue { - match ty { - CanonicalType::UInt(_) - | CanonicalType::SInt(_) - | CanonicalType::Array(_) - | CanonicalType::Enum(_) - | CanonicalType::Bundle(_) - | CanonicalType::PhantomConst(_) - | CanonicalType::DynSimOnly(_) => { - panic!("can't create SimValue from bool: expected value of type: {ty:?}"); - } - CanonicalType::Bool(_) - | CanonicalType::AsyncReset(_) - | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::Clock(_) => SimValue::from_opaque( - ty, - OpaqueSimValue::from_bits(UIntValue::new(Arc::new(BitVec::repeat(*self, 1)))), - ), - } - } -} - -macro_rules! impl_to_sim_value_for_primitive_int { - ($prim:ident) => { - impl ToSimValue for $prim { - type Type = <$prim as ToExpr>::Type; - - #[track_caller] - fn to_sim_value( - &self, - ) -> SimValue { - SimValue::from_value(StaticType::TYPE, (*self).into()) - } - } - - forward_to_sim_value_with_type!([] $prim); - - impl ToSimValueWithType<<<$prim as ToExpr>::Type as IntType>::Dyn> for $prim { - #[track_caller] - fn to_sim_value_with_type( - &self, - ty: <<$prim as ToExpr>::Type as IntType>::Dyn, - ) -> SimValue<<<$prim as ToExpr>::Type as IntType>::Dyn> { - SimValue::from_value( - ty, - <<$prim as ToExpr>::Type as Type>::SimValue::from(*self).as_dyn_int(), - ) - } - } - - impl ToSimValueWithType for $prim { - #[track_caller] - fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue { - let ty: <<$prim as ToExpr>::Type as IntType>::Dyn = Type::from_canonical(ty); - SimValue::into_canonical(self.to_sim_value_with_type(ty)) - } - } - }; -} - -impl_to_sim_value_for_primitive_int!(u8); -impl_to_sim_value_for_primitive_int!(u16); -impl_to_sim_value_for_primitive_int!(u32); -impl_to_sim_value_for_primitive_int!(u64); -impl_to_sim_value_for_primitive_int!(u128); -impl_to_sim_value_for_primitive_int!(usize); -impl_to_sim_value_for_primitive_int!(i8); -impl_to_sim_value_for_primitive_int!(i16); -impl_to_sim_value_for_primitive_int!(i32); -impl_to_sim_value_for_primitive_int!(i64); -impl_to_sim_value_for_primitive_int!(i128); -impl_to_sim_value_for_primitive_int!(isize); - -macro_rules! impl_to_sim_value_for_int_value { - ($IntValue:ident, $Int:ident, $IntType:ident) => { - impl ToSimValue for $IntValue { - type Type = $IntType; - - fn to_sim_value(&self) -> SimValue { - SimValue::from_value(self.ty(), self.clone()) - } - - fn into_sim_value(self) -> SimValue { - SimValue::from_value(self.ty(), self) - } - } - - impl ToSimValueWithType<$IntType> for $IntValue { - fn to_sim_value_with_type(&self, ty: $IntType) -> SimValue<$IntType> { - SimValue::from_value(ty, self.clone()) - } - - fn into_sim_value_with_type(self, ty: $IntType) -> SimValue<$IntType> { - SimValue::from_value(ty, self) - } - } - - impl ToSimValueWithType<$Int> for $IntValue { - fn to_sim_value_with_type(&self, ty: $Int) -> SimValue<$Int> { - self.bits().to_sim_value_with_type(ty) - } - - fn into_sim_value_with_type(self, ty: $Int) -> SimValue<$Int> { - self.into_bits().into_sim_value_with_type(ty) - } - } - - impl ToSimValueWithType for $IntValue { - #[track_caller] - fn to_sim_value_with_type(&self, ty: CanonicalType) -> SimValue { - SimValue::into_canonical( - self.to_sim_value_with_type($IntType::::from_canonical(ty)), - ) - } - - #[track_caller] - fn into_sim_value_with_type(self, ty: CanonicalType) -> SimValue { - SimValue::into_canonical( - self.into_sim_value_with_type($IntType::::from_canonical(ty)), - ) - } - } - }; -} - -impl_to_sim_value_for_int_value!(UIntValue, UInt, UIntType); -impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType); - -#[derive(Default)] -struct DynSimOnlySerdeTableRest { - from_serde: HashMap, - serde_id_random_state: RandomState, - buffer: String, -} - -impl DynSimOnlySerdeTableRest { - #[cold] - fn add_new(&mut self, ty: DynSimOnly) -> DynSimOnlySerdeId { - let mut try_number = 0u64; - let mut hasher = self.serde_id_random_state.build_hasher(); - // extract more bits of randomness from TypeId -- its Hash impl only hashes 64-bits - write!(self.buffer, "{:?}", ty.type_id()).expect("shouldn't ever fail"); - self.buffer.hash(&mut hasher); - loop { - let mut hasher = hasher.clone(); - try_number.hash(&mut hasher); - try_number += 1; - let retval = DynSimOnlySerdeId(std::array::from_fn(|i| { - let mut hasher = hasher.clone(); - i.hash(&mut hasher); - hasher.finish() as u32 - })); - match self.from_serde.entry(retval) { - Entry::Occupied(_) => continue, - Entry::Vacant(e) => { - e.insert(ty); - return retval; - } - } - } - } -} - -#[derive(Default)] -struct DynSimOnlySerdeTable { - to_serde: HashMap, - rest: DynSimOnlySerdeTableRest, -} - -static DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE: Mutex> = Mutex::new(None); - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] -#[serde(transparent)] -struct DynSimOnlySerdeId([u32; 4]); - -impl From for DynSimOnlySerdeId { - fn from(ty: DynSimOnly) -> Self { - let mut locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE - .lock() - .expect("shouldn't be poison"); - let DynSimOnlySerdeTable { to_serde, rest } = locked.get_or_insert_default(); - match to_serde.entry(ty) { - Entry::Occupied(occupied_entry) => *occupied_entry.get(), - Entry::Vacant(vacant_entry) => *vacant_entry.insert(rest.add_new(ty)), - } - } -} - -impl DynSimOnlySerdeId { - fn ty(self) -> Option { - let locked = DYN_SIM_ONLY_VALUE_TYPE_SERDE_TABLE - .lock() - .expect("shouldn't be poison"); - Some(*locked.as_ref()?.rest.from_serde.get(&self)?) - } -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] -struct DynSimOnlySerde<'a> { - random_id: DynSimOnlySerdeId, - #[serde(borrow)] - type_name: Cow<'a, str>, -} - -impl Serialize for DynSimOnly { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - DynSimOnlySerde { - random_id: (*self).into(), - type_name: Cow::Borrowed(self.type_name()), - } - .serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for DynSimOnly { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let deserialized = DynSimOnlySerde::deserialize(deserializer)?; - let retval = deserialized - .random_id - .ty() - .filter(|ty| ty.type_name() == deserialized.type_name); - retval.ok_or_else(|| { - D::Error::custom( - "doesn't match any DynSimOnly that was serialized this time this program was run", - ) - }) - } -} - -impl DynSimOnly { - pub const fn type_properties(self) -> TypeProperties { - TypeProperties { - is_passive: true, - is_storable: true, - is_castable_from_bits: false, - bit_width: 0, - sim_only_values_len: 1, - } - } - pub fn can_connect(self, other: Self) -> bool { - self == other - } -} - -impl Type for DynSimOnly { - type BaseType = DynSimOnly; - type MaskType = Bool; - type SimValue = DynSimOnlyValue; - - impl_match_variant_as_self!(); - - fn mask_type(&self) -> Self::MaskType { - Bool - } - - fn canonical(&self) -> CanonicalType { - CanonicalType::DynSimOnly(*self) - } - - fn from_canonical(canonical_type: CanonicalType) -> Self { - let CanonicalType::DynSimOnly(v) = canonical_type else { - panic!("expected DynSimOnly"); - }; - v - } - - fn source_location() -> SourceLocation { - SourceLocation::builtin() - } - - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - assert_eq!(opaque.size(), self.type_properties().size()); - opaque.sim_only_values()[0].clone() - } - - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ) { - assert_eq!(opaque.size(), self.type_properties().size()); - value.clone_from(&opaque.sim_only_values()[0]); - } - - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> crate::ty::OpaqueSimValueWritten<'w> { - writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_parts( - BitSlice::empty(), - std::array::from_ref(value), - )) - } -} - -impl Type for SimOnly { - type BaseType = DynSimOnly; - type MaskType = Bool; - type SimValue = SimOnlyValue; - - impl_match_variant_as_self!(); - - fn mask_type(&self) -> Self::MaskType { - Bool - } - - fn canonical(&self) -> CanonicalType { - DynSimOnly::from(*self).canonical() - } - - fn from_canonical(canonical_type: CanonicalType) -> Self { - DynSimOnly::from_canonical(canonical_type) - .downcast() - .expect("got wrong SimOnly") - } - - fn source_location() -> SourceLocation { - SourceLocation::builtin() - } - - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - assert_eq!(Self::TYPE_PROPERTIES.size(), opaque.size()); - SimOnlyValue::new( - opaque.sim_only_values()[0] - .downcast_ref::() - .expect("type mismatch") - .clone(), - ) - } - - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ) { - assert_eq!(Self::TYPE_PROPERTIES.size(), opaque.size()); - *value = match opaque.sim_only_values()[0].clone().downcast::() { - Ok(v) => v, - Err(v) => panic!( - "type mismatch: expected {:?}, got {:?}", - DynSimOnly::of::(), - v.ty() - ), - }; - } - - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> crate::ty::OpaqueSimValueWritten<'w> { - SimOnlyValue::with_dyn_ref(value, |value| { - writer.fill_cloned_from_slice(OpaqueSimValueSlice::from_parts( - BitSlice::empty(), - std::array::from_ref(value), - )) - }) - } -} - -impl StaticType for SimOnly { - const TYPE: Self = Self::new(); - - const MASK_TYPE: Self::MaskType = Bool; - - const TYPE_PROPERTIES: TypeProperties = DynSimOnly::of::().type_properties(); - - const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; -} - -impl fmt::Debug for SimOnlyValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Self::with_dyn_ref(self, |this| fmt::Debug::fmt(this, f)) - } -} - -#[derive(Serialize, Deserialize)] -#[serde(rename = "SimOnlyValue")] -struct SerdeSimOnlyValue<'a> { - ty: DynSimOnly, - #[serde(borrow)] - value: Cow<'a, str>, -} - -impl Serialize for DynSimOnlyValue { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - SerdeSimOnlyValue { - ty: self.ty(), - value: Cow::Owned(self.serialize_to_json_string().map_err(S::Error::custom)?), - } - .serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for DynSimOnlyValue { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let SerdeSimOnlyValue { ty, value } = Deserialize::deserialize(deserializer)?; - ty.deserialize_from_json_string(&value) - .map_err(D::Error::custom) - } -} - -impl ToSimValueWithType for DynSimOnlyValue { - #[track_caller] - fn to_sim_value_with_type(&self, ty: DynSimOnly) -> SimValue { - assert_eq!(self.ty(), ty, "mismatched type"); - SimValue::from_value(ty, self.clone()) - } - #[track_caller] - fn into_sim_value_with_type(self, ty: DynSimOnly) -> SimValue { - assert_eq!(self.ty(), ty, "mismatched type"); - SimValue::from_value(ty, self) - } -} - -impl ToSimValueWithType> for SimOnlyValue { - fn to_sim_value_with_type(&self, ty: SimOnly) -> SimValue> { - SimValue::from_value(ty, self.clone()) - } - fn into_sim_value_with_type(self, ty: SimOnly) -> SimValue> { - SimValue::from_value(ty, self) - } -} - -impl ToSimValue for DynSimOnlyValue { - type Type = DynSimOnly; - - fn to_sim_value(&self) -> SimValue { - SimValue::from_value(self.ty(), self.clone()) - } - - fn into_sim_value(self) -> SimValue { - SimValue::from_value(self.ty(), self) - } -} - -impl ToSimValue for SimOnlyValue { - type Type = SimOnly; - - fn to_sim_value(&self) -> SimValue { - SimValue::from_value(Default::default(), self.clone()) - } - - fn into_sim_value(self) -> SimValue { - SimValue::from_value(Default::default(), self) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::{any, collections::BTreeMap}; - - #[test] - fn test_sim_value_serde() -> eyre::Result<()> { - type Inner = Option>>; - let original = SimOnlyValue::::new(Some(BTreeMap::from_iter([ - (String::new(), Some(3)), - (String::from("foo"), None), - ]))); - let json = SimOnlyValue::with_dyn_ref(&original, serde_json::to_string_pretty)?; - #[derive(Deserialize)] - #[serde(deny_unknown_fields)] - struct ExpectedTy { - random_id: [u32; 4], - type_name: String, - } - #[derive(Deserialize)] - #[serde(deny_unknown_fields)] - struct Expected { - ty: ExpectedTy, - value: String, - } - let Expected { - ty: ExpectedTy { - random_id, - type_name, - }, - value, - } = serde_json::from_str(&json)?; - let _ = random_id; - assert_eq!(type_name, any::type_name::()); - assert_eq!(value, r#"{"":3,"foo":null}"#); - let deserialized: DynSimOnlyValue = serde_json::from_str(&json)?; - assert_eq!(Some(&*original), deserialized.downcast_ref::()); - Ok(()) - } -} diff --git a/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs b/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs deleted file mode 100644 index 98a199c..0000000 --- a/crates/fayalite/src/sim/value/sim_only_value_unsafe.rs +++ /dev/null @@ -1,304 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -//! `unsafe` parts of [`DynSimOnlyValue`] - -use serde::{Serialize, de::DeserializeOwned}; -use std::{ - any::{self, TypeId}, - fmt, - hash::{Hash, Hasher}, - marker::PhantomData, - mem::ManuallyDrop, - rc::Rc, -}; - -pub trait SimOnlyValueTrait: - 'static + Eq + Hash + fmt::Debug + Serialize + DeserializeOwned + Clone + Default -{ -} - -impl - SimOnlyValueTrait for T -{ -} - -/// Safety: `type_id_dyn` must return `TypeId::of::()` where `Self = SimOnly` -unsafe trait DynSimOnlyTrait: 'static + Send + Sync { - fn type_id_dyn(&self) -> TypeId; - fn type_name(&self) -> &'static str; - fn default_value(&self) -> Rc; - fn deserialize_from_json_string( - &self, - json_str: &str, - ) -> serde_json::Result>; -} - -/// Safety: `type_id_dyn` is implemented correctly -unsafe impl DynSimOnlyTrait for SimOnly { - fn type_id_dyn(&self) -> TypeId { - TypeId::of::() - } - - fn type_name(&self) -> &'static str { - any::type_name::() - } - - fn default_value(&self) -> Rc { - Rc::new(T::default()) - } - - fn deserialize_from_json_string( - &self, - json_str: &str, - ) -> serde_json::Result> { - Ok(Rc::::new(serde_json::from_str(json_str)?)) - } -} - -/// Safety: -/// * `type_id_dyn()` must return `TypeId::of::()`. -/// * `ty().type_id()` must return `TypeId::of::()`. -unsafe trait DynSimOnlyValueTrait: 'static + fmt::Debug { - fn type_id_dyn(&self) -> TypeId; - fn ty(&self) -> DynSimOnly; - fn eq_dyn(&self, other: &dyn DynSimOnlyValueTrait) -> bool; - fn serialize_to_json_string(&self) -> serde_json::Result; - fn hash_dyn(&self, state: &mut dyn Hasher); -} - -impl dyn DynSimOnlyValueTrait { - fn is(&self) -> bool { - Self::type_id_dyn(self) == TypeId::of::() - } - - fn downcast_ref(&self) -> Option<&T> { - if Self::is::(self) { - // Safety: checked that `Self` is really `T` - Some(unsafe { &*(self as *const Self as *const T) }) - } else { - None - } - } - - fn downcast_rc(self: Rc) -> Result, Rc> { - if Self::is::(&*self) { - // Safety: checked that `Self` is really `T` - Ok(unsafe { Rc::from_raw(Rc::into_raw(self) as *const T) }) - } else { - Err(self) - } - } -} - -/// Safety: -/// * `type_id_dyn()` returns `TypeId::of::()`. -/// * `ty().type_id()` returns `TypeId::of::()`. -unsafe impl DynSimOnlyValueTrait for T { - fn type_id_dyn(&self) -> TypeId { - TypeId::of::() - } - - fn ty(&self) -> DynSimOnly { - DynSimOnly::of::() - } - - fn eq_dyn(&self, other: &dyn DynSimOnlyValueTrait) -> bool { - other.downcast_ref::().is_some_and(|other| self == other) - } - - fn serialize_to_json_string(&self) -> serde_json::Result { - serde_json::to_string(self) - } - - fn hash_dyn(&self, mut state: &mut dyn Hasher) { - self.hash(&mut state); - } -} - -#[derive(Copy, Clone)] -pub struct DynSimOnly { - ty: &'static dyn DynSimOnlyTrait, -} - -impl DynSimOnly { - pub const fn of() -> Self { - Self { - ty: &const { SimOnly::::new() }, - } - } - pub fn type_id(self) -> TypeId { - self.ty.type_id_dyn() - } - pub fn type_name(self) -> &'static str { - self.ty.type_name() - } - pub fn is(self) -> bool { - self.type_id() == TypeId::of::() - } - pub fn downcast(self) -> Option> { - self.is::().then_some(SimOnly::default()) - } - pub fn deserialize_from_json_string( - self, - json_str: &str, - ) -> serde_json::Result { - self.ty - .deserialize_from_json_string(json_str) - .map(DynSimOnlyValue) - } - pub fn default_value(self) -> DynSimOnlyValue { - DynSimOnlyValue(self.ty.default_value()) - } -} - -impl PartialEq for DynSimOnly { - fn eq(&self, other: &Self) -> bool { - Self::type_id(*self) == Self::type_id(*other) - } -} - -impl Eq for DynSimOnly {} - -impl Hash for DynSimOnly { - fn hash(&self, state: &mut H) { - Self::type_id(*self).hash(state); - } -} - -impl fmt::Debug for DynSimOnly { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "SimOnly<{}>", self.ty.type_name()) - } -} - -impl From> for DynSimOnly { - fn from(value: SimOnly) -> Self { - let SimOnly(PhantomData) = value; - Self::of::() - } -} - -/// the [`Type`][Type] for a value that can only be used in a Fayalite simulation, it can't be converted to FIRRTL -/// -/// [Type]: crate::ty::Type -#[derive(Clone, Eq, PartialEq, Hash)] -pub struct SimOnly(PhantomData T>); - -impl fmt::Debug for SimOnly { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - DynSimOnly::of::().fmt(f) - } -} - -impl SimOnly { - pub const fn new() -> Self { - Self(PhantomData) - } -} - -impl Copy for SimOnly {} - -impl Default for SimOnly { - fn default() -> Self { - Self::new() - } -} - -/// a value that can only be used in a Fayalite simulation, it can't be converted to FIRRTL -#[derive(Clone, Eq, PartialEq, Hash, Default, PartialOrd, Ord)] -pub struct SimOnlyValue(Rc); - -impl SimOnlyValue { - pub fn with_dyn_ref R, R>(&self, f: F) -> R { - // Safety: creating a copied `Rc` is safe as long as the copy isn't dropped and isn't changed - // to point somewhere else, `f` can't change `dyn_ref` because it's only given a shared reference. - let dyn_ref = - unsafe { ManuallyDrop::new(DynSimOnlyValue(Rc::::from_raw(Rc::as_ptr(&self.0)))) }; - f(&dyn_ref) - } - pub fn from_rc(v: Rc) -> Self { - Self(v) - } - pub fn new(v: T) -> Self { - Self(Rc::new(v)) - } - pub fn into_inner(this: Self) -> Rc { - this.0 - } - pub fn inner_mut(this: &mut Self) -> &mut Rc { - &mut this.0 - } - pub fn inner(this: &Self) -> &Rc { - &this.0 - } - pub fn into_dyn(this: Self) -> DynSimOnlyValue { - DynSimOnlyValue::from(this) - } -} - -impl std::ops::Deref for SimOnlyValue { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl std::ops::DerefMut for SimOnlyValue { - fn deref_mut(&mut self) -> &mut Self::Target { - Rc::make_mut(&mut self.0) - } -} - -#[derive(Clone)] -pub struct DynSimOnlyValue(Rc); - -impl fmt::Debug for DynSimOnlyValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ::fmt(&*self.0, f) - } -} - -impl PartialEq for DynSimOnlyValue { - fn eq(&self, other: &Self) -> bool { - DynSimOnlyValueTrait::eq_dyn(&*self.0, &*other.0) - } -} - -impl Eq for DynSimOnlyValue {} - -impl Hash for DynSimOnlyValue { - fn hash(&self, state: &mut H) { - DynSimOnlyValueTrait::hash_dyn(&*self.0, state); - } -} - -impl From> for DynSimOnlyValue { - fn from(value: SimOnlyValue) -> Self { - Self(value.0) - } -} - -impl DynSimOnlyValue { - pub fn ty(&self) -> DynSimOnly { - self.0.ty() - } - pub fn type_id(&self) -> TypeId { - self.0.type_id_dyn() - } - pub fn is(&self) -> bool { - self.0.is::() - } - pub fn downcast(self) -> Result, DynSimOnlyValue> { - match ::downcast_rc(self.0) { - Ok(v) => Ok(SimOnlyValue(v)), - Err(v) => Err(Self(v)), - } - } - pub fn downcast_ref(&self) -> Option<&T> { - ::downcast_ref(&*self.0) - } - pub fn serialize_to_json_string(&self) -> serde_json::Result { - self.0.serialize_to_json_string() - } -} diff --git a/crates/fayalite/src/sim/vcd.rs b/crates/fayalite/src/sim/vcd.rs index e66c3ee..b8248e3 100644 --- a/crates/fayalite/src/sim/vcd.rs +++ b/crates/fayalite/src/sim/vcd.rs @@ -5,86 +5,22 @@ use crate::{ enum_::{Enum, EnumType}, expr::Flow, int::UInt, - intern::{Intern, Interned}, sim::{ + time::{SimDuration, SimInstant}, TraceArray, TraceAsyncReset, TraceBool, TraceBundle, TraceClock, TraceDecl, TraceEnumDiscriminant, TraceEnumWithFields, TraceFieldlessEnum, TraceInstance, TraceLocation, TraceMem, TraceMemPort, TraceMemoryId, TraceMemoryLocation, TraceModule, - TraceModuleIO, TraceReg, TraceSInt, TraceScalar, TraceScalarId, TraceScope, TraceSimOnly, - TraceSyncReset, TraceUInt, TraceWire, TraceWriter, TraceWriterDecls, - time::{SimDuration, SimInstant}, - value::DynSimOnlyValue, + TraceModuleIO, TraceReg, TraceSInt, TraceScalar, TraceScalarId, TraceScope, TraceSyncReset, + TraceUInt, TraceWire, TraceWriter, TraceWriterDecls, }, - util::HashMap, }; use bitvec::{order::Lsb0, slice::BitSlice}; -use hashbrown::hash_map::Entry; use std::{ - fmt::{self, Write as _}, - io, mem, + fmt, + io::{self, Write}, + mem, }; -#[derive(Default)] -struct Scope { - last_inserted: HashMap, usize>, -} - -#[derive(Copy, Clone)] -struct VerilogIdentifier { - unescaped_name: Interned, -} - -impl VerilogIdentifier { - fn needs_escape(self) -> bool { - // we only allow ascii, so we can just check bytes - let Some((&first, rest)) = self.unescaped_name.as_bytes().split_first() else { - unreachable!("Scope::new_identifier guarantees a non-empty name"); - }; - if !first.is_ascii_alphabetic() && first != b'_' { - true - } else { - rest.iter() - .any(|&ch| !ch.is_ascii_alphanumeric() && ch != b'_' && ch != b'$') - } - } -} - -impl fmt::Display for VerilogIdentifier { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.needs_escape() { - f.write_str("\\")?; - } - write!(f, "{}", Escaped(self.unescaped_name)) - } -} - -impl Scope { - fn new_identifier(&mut self, unescaped_name: Interned) -> VerilogIdentifier { - let next_disambiguator = match self.last_inserted.entry(unescaped_name) { - Entry::Vacant(entry) => { - entry.insert(1); - return VerilogIdentifier { unescaped_name }; - } - Entry::Occupied(entry) => entry.get() + 1, - }; - let mut disambiguated_name = String::from(&*unescaped_name); - for disambiguator in next_disambiguator.. { - disambiguated_name.truncate(unescaped_name.len()); - write!(disambiguated_name, "_{disambiguator}").expect("can't fail"); - if let Entry::Vacant(entry) = self.last_inserted.entry((*disambiguated_name).intern()) { - let retval = VerilogIdentifier { - unescaped_name: *entry.key(), - }; - entry.insert(1); - // speed up future searches - self.last_inserted.insert(unescaped_name, disambiguator); - return retval; - } - } - panic!("too many names"); - } -} - pub struct VcdWriterDecls { writer: W, timescale: SimDuration, @@ -161,20 +97,14 @@ impl fmt::Debug for VcdWriterDecls { } } -/// pass in scope to ensure it's not available in child scope fn write_vcd_scope( writer: &mut W, scope_type: &str, - scope_name: Interned, - scope: &mut Scope, - f: impl FnOnce(&mut W, &mut Scope) -> io::Result, + scope_name: &str, + f: impl FnOnce(&mut W) -> io::Result, ) -> io::Result { - writeln!( - writer, - "$scope {scope_type} {} $end", - scope.new_identifier(scope_name), - )?; - let retval = f(writer, &mut Scope::default())?; + writeln!(writer, "$scope {scope_type} {scope_name} $end")?; + let retval = f(writer)?; writeln!(writer, "$upscope $end")?; Ok(retval) } @@ -213,28 +143,24 @@ trait_arg! { struct ArgModule<'a> { properties: &'a mut VcdWriterProperties, - scope: &'a mut Scope, } impl<'a> ArgModule<'a> { fn reborrow(&mut self) -> ArgModule<'_> { ArgModule { properties: self.properties, - scope: self.scope, } } } struct ArgModuleBody<'a> { properties: &'a mut VcdWriterProperties, - scope: &'a mut Scope, } impl<'a> ArgModuleBody<'a> { fn reborrow(&mut self) -> ArgModuleBody<'_> { ArgModuleBody { properties: self.properties, - scope: self.scope, } } } @@ -244,7 +170,6 @@ struct ArgInType<'a> { sink_var_type: &'static str, duplex_var_type: &'static str, properties: &'a mut VcdWriterProperties, - scope: &'a mut Scope, } impl<'a> ArgInType<'a> { @@ -254,7 +179,6 @@ impl<'a> ArgInType<'a> { sink_var_type: self.sink_var_type, duplex_var_type: self.duplex_var_type, properties: self.properties, - scope: self.scope, } } } @@ -283,7 +207,6 @@ impl WriteTrace for TraceScalar { Self::Clock(v) => v.write_trace(writer, arg), Self::SyncReset(v) => v.write_trace(writer, arg), Self::AsyncReset(v) => v.write_trace(writer, arg), - Self::SimOnly(v) => v.write_trace(writer, arg), } } } @@ -303,42 +226,55 @@ fn write_vcd_id(writer: &mut W, mut id: usize) -> io::Result<()> { Ok(()) } -struct Escaped(T); - -impl fmt::Display for Escaped { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // escaping rules from function GTKWave uses to decode VCD strings: - // https://github.com/gtkwave/gtkwave/blob/491f24d7e8619cfc1fcc65704ee5c967d1083c18/lib/libfst/fstapi.c#L7090 - struct Wrapper(W); - impl fmt::Write for Wrapper { - fn write_str(&mut self, s: &str) -> fmt::Result { - for byte in s.bytes() { - match byte { - b'\\' | b'\'' | b'"' | b'?' => { - self.0.write_str("\\")?; - self.0.write_char(byte as char)?; - } - b'\n' => self.0.write_str(r"\n")?, - b'\r' => self.0.write_str(r"\r")?, - b'\t' => self.0.write_str(r"\t")?, - 0x7 => self.0.write_str(r"\a")?, - 0x8 => self.0.write_str(r"\b")?, - 0xC => self.0.write_str(r"\f")?, - 0xB => self.0.write_str(r"\v")?, - _ => { - if byte.is_ascii_graphic() { - self.0.write_char(byte as char)?; - } else { - write!(self.0, r"\x{byte:02x}")?; - } +fn write_escaped(writer: &mut W, value: impl fmt::Display) -> io::Result<()> { + // escaping rules from function GTKWave uses to decode VCD strings: + // https://github.com/gtkwave/gtkwave/blob/491f24d7e8619cfc1fcc65704ee5c967d1083c18/lib/libfst/fstapi.c#L7090 + struct Wrapper(W); + impl io::Write for Wrapper { + fn write(&mut self, buf: &[u8]) -> io::Result { + if buf.is_empty() { + return self.0.write(buf); + } + let mut retval = 0; + for &byte in buf { + match byte { + b'\\' | b'\'' | b'"' | b'?' => self.0.write_all(&[b'\\', byte])?, + b'\n' => self.0.write_all(br"\n")?, + b'\r' => self.0.write_all(br"\r")?, + b'\t' => self.0.write_all(br"\t")?, + 0x7 => self.0.write_all(br"\a")?, + 0x8 => self.0.write_all(br"\b")?, + 0xC => self.0.write_all(br"\f")?, + 0xB => self.0.write_all(br"\v")?, + _ => { + if byte.is_ascii_graphic() { + self.0.write_all(&[byte])?; + } else { + write!(self.0, r"\x{byte:02x}")?; } } } - Ok(()) + retval += 1; } + Ok(retval) + } + + fn flush(&mut self) -> io::Result<()> { + self.0.flush() } - write!(Wrapper(f), "{}", self.0) } + write!(Wrapper(writer), "{value}") +} + +fn is_unescaped_verilog_identifier(ident: &str) -> bool { + // we only allow ascii, so we can just check bytes + let Some((&first, rest)) = ident.as_bytes().split_first() else { + return false; // empty string is not an identifier + }; + (first.is_ascii_alphabetic() || first == b'_') + && rest + .iter() + .all(|&ch| ch.is_ascii_alphanumeric() || ch == b'_' || ch == b'$') } fn write_vcd_var( @@ -348,7 +284,7 @@ fn write_vcd_var( var_type: &str, size: usize, location: TraceLocation, - name: VerilogIdentifier, + name: &str, ) -> io::Result<()> { let id = match location { TraceLocation::Scalar(id) => id.as_usize(), @@ -383,7 +319,12 @@ fn write_vcd_var( }; write!(writer, "$var {var_type} {size} ")?; write_vcd_id(writer, id)?; - writeln!(writer, " {name} $end") + writer.write_all(b" ")?; + if !is_unescaped_verilog_identifier(name) { + writer.write_all(b"\\")?; + } + write_escaped(writer, name)?; + writer.write_all(b" $end\n") } impl WriteTrace for TraceUInt { @@ -393,7 +334,6 @@ impl WriteTrace for TraceUInt { sink_var_type, duplex_var_type, properties, - scope, } = arg.in_type(); let Self { location, @@ -416,7 +356,7 @@ impl WriteTrace for TraceUInt { var_type, ty.width(), location, - scope.new_identifier(name), + &name, ) } } @@ -481,7 +421,6 @@ impl WriteTrace for TraceEnumDiscriminant { sink_var_type: _, duplex_var_type: _, properties, - scope, } = arg.in_type(); let Self { location, @@ -496,7 +435,7 @@ impl WriteTrace for TraceEnumDiscriminant { "string", 1, location, - scope.new_identifier(name), + &name, ) } } @@ -549,33 +488,6 @@ impl WriteTrace for TraceAsyncReset { } } -impl WriteTrace for TraceSimOnly { - fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgInType { - source_var_type: _, - sink_var_type: _, - duplex_var_type: _, - properties, - scope, - } = arg.in_type(); - let Self { - location, - name, - ty: _, - flow: _, - } = self; - write_vcd_var( - properties, - MemoryElementPartBody::Scalar, - writer, - "string", - 1, - location, - scope.new_identifier(name), - ) - } -} - impl WriteTrace for TraceScope { fn write_trace(self, writer: &mut W, arg: A) -> io::Result<()> { match self { @@ -595,11 +507,11 @@ impl WriteTrace for TraceScope { impl WriteTrace for TraceModule { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModule { properties, scope } = arg.module(); + let ArgModule { properties } = arg.module(); let Self { name, children } = self; - write_vcd_scope(writer, "module", name, scope, |writer, scope| { + write_vcd_scope(writer, "module", &name, |writer| { for child in children { - child.write_trace(writer, ArgModuleBody { properties, scope })?; + child.write_trace(writer, ArgModuleBody { properties })?; } Ok(()) }) @@ -608,7 +520,7 @@ impl WriteTrace for TraceModule { impl WriteTrace for TraceInstance { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties, scope } = arg.module_body(); + let ArgModuleBody { properties } = arg.module_body(); let Self { name: _, instance_io, @@ -622,16 +534,15 @@ impl WriteTrace for TraceInstance { sink_var_type: "wire", duplex_var_type: "wire", properties, - scope, }, )?; - module.write_trace(writer, ArgModule { properties, scope }) + module.write_trace(writer, ArgModule { properties }) } } impl WriteTrace for TraceMem { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties, scope } = arg.module_body(); + let ArgModuleBody { properties } = arg.module_body(); let Self { id, name, @@ -640,41 +551,27 @@ impl WriteTrace for TraceMem { ports, array_type, } = self; - write_vcd_scope(writer, "struct", name, scope, |writer, scope| { - write_vcd_scope( - writer, - "struct", - "contents".intern(), - scope, - |writer, scope| { - for element_index in 0..array_type.len() { - write_vcd_scope( + write_vcd_scope(writer, "struct", &*name, |writer| { + write_vcd_scope(writer, "struct", "contents", |writer| { + for element_index in 0..array_type.len() { + write_vcd_scope(writer, "struct", &format!("[{element_index}]"), |writer| { + properties.memory_properties[id.as_usize()].element_index = element_index; + properties.memory_properties[id.as_usize()].element_part_index = 0; + element_type.write_trace( writer, - "struct", - Intern::intern_owned(format!("[{element_index}]")), - scope, - |writer, scope| { - properties.memory_properties[id.as_usize()].element_index = - element_index; - properties.memory_properties[id.as_usize()].element_part_index = 0; - element_type.write_trace( - writer, - ArgInType { - source_var_type: "reg", - sink_var_type: "reg", - duplex_var_type: "reg", - properties, - scope, - }, - ) + ArgInType { + source_var_type: "reg", + sink_var_type: "reg", + duplex_var_type: "reg", + properties, }, - )?; - } - Ok(()) - }, - )?; + ) + })?; + } + Ok(()) + })?; for port in ports { - port.write_trace(writer, ArgModuleBody { properties, scope })?; + port.write_trace(writer, ArgModuleBody { properties })?; } Ok(()) }) @@ -683,7 +580,7 @@ impl WriteTrace for TraceMem { impl WriteTrace for TraceMemPort { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties, scope } = arg.module_body(); + let ArgModuleBody { properties } = arg.module_body(); let Self { name: _, bundle, @@ -696,7 +593,6 @@ impl WriteTrace for TraceMemPort { sink_var_type: "wire", duplex_var_type: "wire", properties, - scope, }, ) } @@ -704,7 +600,7 @@ impl WriteTrace for TraceMemPort { impl WriteTrace for TraceWire { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties, scope } = arg.module_body(); + let ArgModuleBody { properties } = arg.module_body(); let Self { name: _, child, @@ -717,7 +613,6 @@ impl WriteTrace for TraceWire { sink_var_type: "wire", duplex_var_type: "wire", properties, - scope, }, ) } @@ -725,7 +620,7 @@ impl WriteTrace for TraceWire { impl WriteTrace for TraceReg { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties, scope } = arg.module_body(); + let ArgModuleBody { properties } = arg.module_body(); let Self { name: _, child, @@ -738,7 +633,6 @@ impl WriteTrace for TraceReg { sink_var_type: "reg", duplex_var_type: "reg", properties, - scope, }, ) } @@ -746,7 +640,7 @@ impl WriteTrace for TraceReg { impl WriteTrace for TraceModuleIO { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties, scope } = arg.module_body(); + let ArgModuleBody { properties } = arg.module_body(); let Self { name: _, child, @@ -760,7 +654,6 @@ impl WriteTrace for TraceModuleIO { sink_var_type: "wire", duplex_var_type: "wire", properties, - scope, }, ) } @@ -768,31 +661,16 @@ impl WriteTrace for TraceModuleIO { impl WriteTrace for TraceBundle { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgInType { - source_var_type, - sink_var_type, - duplex_var_type, - properties, - scope, - } = arg.in_type(); + let mut arg = arg.in_type(); let Self { name, fields, ty: _, flow: _, } = self; - write_vcd_scope(writer, "struct", name, scope, |writer, scope| { + write_vcd_scope(writer, "struct", &name, |writer| { for field in fields { - field.write_trace( - writer, - ArgInType { - source_var_type, - sink_var_type, - duplex_var_type, - properties, - scope, - }, - )?; + field.write_trace(writer, arg.reborrow())?; } Ok(()) }) @@ -801,31 +679,16 @@ impl WriteTrace for TraceBundle { impl WriteTrace for TraceArray { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgInType { - source_var_type, - sink_var_type, - duplex_var_type, - properties, - scope, - } = arg.in_type(); + let mut arg = arg.in_type(); let Self { name, elements, ty: _, flow: _, } = self; - write_vcd_scope(writer, "struct", name, scope, |writer, scope| { + write_vcd_scope(writer, "struct", &name, |writer| { for element in elements { - element.write_trace( - writer, - ArgInType { - source_var_type, - sink_var_type, - duplex_var_type, - properties, - scope, - }, - )?; + element.write_trace(writer, arg.reborrow())?; } Ok(()) }) @@ -834,13 +697,7 @@ impl WriteTrace for TraceArray { impl WriteTrace for TraceEnumWithFields { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgInType { - source_var_type, - sink_var_type, - duplex_var_type, - properties, - scope, - } = arg.in_type(); + let mut arg = arg.in_type(); let Self { name, discriminant, @@ -848,28 +705,10 @@ impl WriteTrace for TraceEnumWithFields { ty: _, flow: _, } = self; - write_vcd_scope(writer, "struct", name, scope, |writer, scope| { - discriminant.write_trace( - writer, - ArgInType { - source_var_type, - sink_var_type, - duplex_var_type, - properties, - scope, - }, - )?; + write_vcd_scope(writer, "struct", &name, |writer| { + discriminant.write_trace(writer, arg.reborrow())?; for field in non_empty_fields { - field.write_trace( - writer, - ArgInType { - source_var_type, - sink_var_type, - duplex_var_type, - properties, - scope, - }, - )?; + field.write_trace(writer, arg.reborrow())?; } Ok(()) }) @@ -905,7 +744,6 @@ impl TraceWriterDecls for VcdWriterDecls { &mut writer, ArgModule { properties: &mut properties, - scope: &mut Scope::default(), }, )?; writeln!(writer, "$enddefinitions $end")?; @@ -960,7 +798,9 @@ fn write_string_value_change( value: impl fmt::Display, id: usize, ) -> io::Result<()> { - write!(writer, "s{} ", Escaped(value))?; + writer.write_all(b"s")?; + write_escaped(writer, value)?; + writer.write_all(b" ")?; write_vcd_id(writer, id)?; writer.write_all(b"\n") } @@ -1090,14 +930,6 @@ impl TraceWriter for VcdWriter { ) -> Result<(), Self::Error> { write_enum_discriminant_value_change(&mut self.writer, variant_index, ty, id.as_usize()) } - - fn set_signal_sim_only_value( - &mut self, - id: TraceScalarId, - value: &DynSimOnlyValue, - ) -> Result<(), Self::Error> { - write_string_value_change(&mut self.writer, format_args!("{value:?}"), id.as_usize()) - } } impl fmt::Debug for VcdWriter { @@ -1114,49 +946,3 @@ impl fmt::Debug for VcdWriter { .finish_non_exhaustive() } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_scope() { - let mut scope = Scope::default(); - assert_eq!(&*scope.new_identifier("foo".intern()).unescaped_name, "foo"); - assert_eq!( - &*scope.new_identifier("foo_0".intern()).unescaped_name, - "foo_0" - ); - assert_eq!( - &*scope.new_identifier("foo_1".intern()).unescaped_name, - "foo_1" - ); - assert_eq!( - &*scope.new_identifier("foo_3".intern()).unescaped_name, - "foo_3" - ); - assert_eq!( - &*scope.new_identifier("foo".intern()).unescaped_name, - "foo_2" - ); - assert_eq!( - &*scope.new_identifier("foo".intern()).unescaped_name, - "foo_4" - ); - assert_eq!( - &*scope.new_identifier("foo_0".intern()).unescaped_name, - "foo_0_2" - ); - assert_eq!( - &*scope.new_identifier("foo_1".intern()).unescaped_name, - "foo_1_2" - ); - for i in 5..1000u64 { - // verify it actually picks the next available identifier with no skips or duplicates - assert_eq!( - *scope.new_identifier("foo".intern()).unescaped_name, - format!("foo_{i}"), - ); - } - } -} diff --git a/crates/fayalite/src/source_location.rs b/crates/fayalite/src/source_location.rs index 1a168b1..d143f22 100644 --- a/crates/fayalite/src/source_location.rs +++ b/crates/fayalite/src/source_location.rs @@ -2,8 +2,9 @@ // See Notices.txt for copyright information use crate::{ intern::{Intern, Interned}, - util::{DebugAsDisplay, HashMap}, + util::DebugAsDisplay, }; +use hashbrown::HashMap; use std::{cell::RefCell, fmt, num::NonZeroUsize, panic, path::Path}; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -96,7 +97,7 @@ impl NormalizeFilesForTestsState { fn new() -> Self { Self { test_position: panic::Location::caller(), - file_pattern_matches: HashMap::default(), + file_pattern_matches: HashMap::new(), } } } @@ -142,7 +143,7 @@ impl From<&'_ panic::Location<'_>> for SourceLocation { map.entry_ref(file) .or_insert_with(|| NormalizedFileForTestState { file_name_id: NonZeroUsize::new(len + 1).unwrap(), - positions_map: HashMap::default(), + positions_map: HashMap::new(), }); file_str = m.generate_file_name(file_state.file_name_id); file = &file_str; diff --git a/crates/fayalite/src/testing.rs b/crates/fayalite/src/testing.rs index bc7a0b1..4517e34 100644 --- a/crates/fayalite/src/testing.rs +++ b/crates/fayalite/src/testing.rs @@ -1,54 +1,25 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ - build::{ - BaseJobArgs, BaseJobKind, GlobalParams, JobArgsAndDependencies, JobKindAndArgs, JobParams, - NoArgs, RunBuild, - external::{ExternalCommandArgs, ExternalCommandJobKind}, - firrtl::{FirrtlArgs, FirrtlJobKind}, - formal::{Formal, FormalAdditionalArgs, FormalArgs, WriteSbyFileJobKind}, - verilog::{UnadjustedVerilogArgs, VerilogJobArgs, VerilogJobKind}, - }, - bundle::BundleType, + cli::{FormalArgs, FormalMode, FormalOutput, RunPhase}, firrtl::ExportOptions, - module::Module, - util::HashMap, }; -use serde::{Deserialize, Serialize}; +use clap::Parser; +use hashbrown::HashMap; +use serde::Deserialize; use std::{ - fmt::{self, Write}, + fmt::Write, path::{Path, PathBuf}, process::Command, sync::{Mutex, OnceLock}, }; -#[derive( - clap::ValueEnum, Copy, Clone, Debug, PartialEq, Eq, Hash, Default, Deserialize, Serialize, -)] -#[non_exhaustive] -pub enum FormalMode { - #[default] - BMC, - Prove, - Live, - Cover, -} - -impl FormalMode { - pub fn as_str(self) -> &'static str { - match self { - FormalMode::BMC => "bmc", - FormalMode::Prove => "prove", - FormalMode::Live => "live", - FormalMode::Cover => "cover", - } - } -} - -impl fmt::Display for FormalMode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } +fn assert_formal_helper() -> FormalArgs { + static FORMAL_ARGS: OnceLock = OnceLock::new(); + // ensure we only run parsing once, so errors from env vars don't produce overlapping output if we're called on multiple threads + FORMAL_ARGS + .get_or_init(|| FormalArgs::parse_from(["fayalite::testing::assert_formal"])) + .clone() } #[derive(Deserialize)] @@ -116,7 +87,7 @@ fn get_assert_formal_target_path(test_name: &dyn std::fmt::Display) -> PathBuf { let index = *DIRS .lock() .unwrap() - .get_or_insert_with(HashMap::default) + .get_or_insert_with(HashMap::new) .entry_ref(&dir) .and_modify(|v| *v += 1) .or_insert(0); @@ -126,99 +97,26 @@ fn get_assert_formal_target_path(test_name: &dyn std::fmt::Display) -> PathBuf { .join(dir) } -fn make_assert_formal_args( - test_name: &dyn std::fmt::Display, - formal_mode: FormalMode, - formal_depth: u64, - solver: Option<&str>, - export_options: ExportOptions, -) -> eyre::Result>> { - let args = JobKindAndArgs { - kind: BaseJobKind, - args: BaseJobArgs::from_output_dir_and_env(get_assert_formal_target_path(&test_name), None), - }; - let dependencies = JobArgsAndDependencies { - args, - dependencies: (), - }; - let args = JobKindAndArgs { - kind: FirrtlJobKind, - args: FirrtlArgs { export_options }, - }; - let dependencies = JobArgsAndDependencies { args, dependencies }; - let args = JobKindAndArgs { - kind: ExternalCommandJobKind::new(), - args: ExternalCommandArgs::resolve_program_path( - None, - UnadjustedVerilogArgs { - firtool_extra_args: vec![], - verilog_dialect: None, - verilog_debug: true, - }, - )?, - }; - let dependencies = JobArgsAndDependencies { args, dependencies }; - let args = JobKindAndArgs { - kind: VerilogJobKind, - args: VerilogJobArgs {}, - }; - let dependencies = JobArgsAndDependencies { args, dependencies }; - let args = JobKindAndArgs { - kind: WriteSbyFileJobKind, - args: FormalArgs { - sby_extra_args: vec![], - formal_mode, - formal_depth, - formal_solver: solver.unwrap_or(FormalArgs::DEFAULT_SOLVER).into(), - smtbmc_extra_args: vec![], - }, - }; - let dependencies = JobArgsAndDependencies { args, dependencies }; - let args = JobKindAndArgs { - kind: ExternalCommandJobKind::new(), - args: ExternalCommandArgs::resolve_program_path(None, FormalAdditionalArgs {})?, - }; - Ok(JobArgsAndDependencies { args, dependencies }) -} - -pub fn try_assert_formal>, T: BundleType>( - test_name: impl std::fmt::Display, - module: M, - formal_mode: FormalMode, - formal_depth: u64, - solver: Option<&str>, - export_options: ExportOptions, -) -> eyre::Result<()> { - const APP_NAME: &'static str = "fayalite::testing::assert_formal"; - make_assert_formal_args( - &test_name, - formal_mode, - formal_depth, - solver, - export_options, - )? - .run_without_platform( - |NoArgs {}| Ok(JobParams::new(module)), - &GlobalParams::new(None, APP_NAME), - ) -} - #[track_caller] -pub fn assert_formal>, T: BundleType>( +pub fn assert_formal( test_name: impl std::fmt::Display, module: M, - formal_mode: FormalMode, - formal_depth: u64, + mode: FormalMode, + depth: u64, solver: Option<&str>, export_options: ExportOptions, -) { - try_assert_formal( - test_name, - module, - formal_mode, - formal_depth, - solver, - export_options, - ) - .expect("testing::assert_formal() failed"); +) where + FormalArgs: RunPhase, +{ + let mut args = assert_formal_helper(); + args.verilog.firrtl.base.redirect_output_for_rust_test = true; + args.verilog.firrtl.base.output = Some(get_assert_formal_target_path(&test_name)); + args.verilog.firrtl.export_options = export_options; + args.verilog.debug = true; + args.mode = mode; + args.depth = depth; + if let Some(solver) = solver { + args.solver = solver.into(); + } + args.run(module).expect("testing::assert_formal() failed"); } diff --git a/crates/fayalite/src/ty.rs b/crates/fayalite/src/ty.rs index d9ea6b2..69080c9 100644 --- a/crates/fayalite/src/ty.rs +++ b/crates/fayalite/src/ty.rs @@ -7,27 +7,12 @@ use crate::{ clock::Clock, enum_::Enum, expr::Expr, - int::{Bool, SInt, UInt, UIntValue}, + int::{Bool, SInt, UInt}, intern::{Intern, Interned}, - phantom_const::PhantomConst, reset::{AsyncReset, Reset, SyncReset}, - sim::value::{DynSimOnlyValue, DynSimOnly, SimValue, ToSimValueWithType}, source_location::SourceLocation, - util::{ConstUsize, slice_range, try_slice_range}, }; -use bitvec::{slice::BitSlice, vec::BitVec}; -use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned}; -use std::{ - fmt, - hash::Hash, - iter::{FusedIterator, Sum}, - marker::PhantomData, - mem, - ops::{Add, AddAssign, Bound, Index, Mul, MulAssign, Range, Sub, SubAssign}, - sync::Arc, -}; - -pub(crate) mod serde_impls; +use std::{fmt, hash::Hash, iter::FusedIterator, ops::Index}; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] #[non_exhaustive] @@ -36,23 +21,6 @@ pub struct TypeProperties { pub is_storable: bool, pub is_castable_from_bits: bool, pub bit_width: usize, - pub sim_only_values_len: usize, -} - -impl TypeProperties { - pub const fn size(self) -> OpaqueSimValueSize { - let Self { - is_passive: _, - is_storable: _, - is_castable_from_bits: _, - bit_width, - sim_only_values_len, - } = self; - OpaqueSimValueSize { - bit_width, - sim_only_values_len, - } - } } #[derive(Copy, Clone, Hash, PartialEq, Eq)] @@ -67,8 +35,6 @@ pub enum CanonicalType { SyncReset(SyncReset), Reset(Reset), Clock(Clock), - PhantomConst(PhantomConst), - DynSimOnly(DynSimOnly), } impl fmt::Debug for CanonicalType { @@ -84,30 +50,10 @@ impl fmt::Debug for CanonicalType { Self::SyncReset(v) => v.fmt(f), Self::Reset(v) => v.fmt(f), Self::Clock(v) => v.fmt(f), - Self::PhantomConst(v) => v.fmt(f), - Self::DynSimOnly(v) => v.fmt(f), } } } -impl Serialize for CanonicalType { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serde_impls::SerdeCanonicalType::from(*self).serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for CanonicalType { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - Ok(serde_impls::SerdeCanonicalType::deserialize(deserializer)?.into()) - } -} - impl CanonicalType { pub fn type_properties(self) -> TypeProperties { match self { @@ -121,8 +67,6 @@ impl CanonicalType { CanonicalType::SyncReset(v) => v.type_properties(), CanonicalType::Reset(v) => v.type_properties(), CanonicalType::Clock(v) => v.type_properties(), - CanonicalType::PhantomConst(v) => v.type_properties(), - CanonicalType::DynSimOnly(v) => v.type_properties(), } } pub fn is_passive(self) -> bool { @@ -137,12 +81,6 @@ impl CanonicalType { pub fn bit_width(self) -> usize { self.type_properties().bit_width } - pub fn sim_only_values_len(self) -> usize { - self.type_properties().sim_only_values_len - } - pub fn size(self) -> OpaqueSimValueSize { - self.type_properties().size() - } pub fn can_connect(self, rhs: Self) -> bool { match self { CanonicalType::UInt(lhs) => { @@ -205,23 +143,8 @@ impl CanonicalType { }; lhs.can_connect(rhs) } - CanonicalType::PhantomConst(lhs) => { - let CanonicalType::PhantomConst(rhs) = rhs else { - return false; - }; - lhs.can_connect(rhs) - } - CanonicalType::DynSimOnly(lhs) => { - let CanonicalType::DynSimOnly(rhs) = rhs else { - return false; - }; - lhs.can_connect(rhs) - } } } - pub(crate) fn as_serde_unexpected_str(self) -> &'static str { - serde_impls::SerdeCanonicalType::from(self).as_serde_unexpected_str() - } } pub trait MatchVariantAndInactiveScope: Sized { @@ -243,7 +166,7 @@ impl MatchVariantAndInactiveScope for MatchVariantWith } pub trait FillInDefaultedGenerics { - type Type; + type Type: Type; fn fill_in_defaulted_generics(self) -> Self::Type; } @@ -255,22 +178,6 @@ impl FillInDefaultedGenerics for T { } } -impl FillInDefaultedGenerics for usize { - type Type = usize; - - fn fill_in_defaulted_generics(self) -> Self::Type { - self - } -} - -impl FillInDefaultedGenerics for ConstUsize { - type Type = ConstUsize; - - fn fill_in_defaulted_generics(self) -> Self::Type { - self - } -} - mod sealed { pub trait TypeOrDefaultSealed {} pub trait BaseTypeSealed {} @@ -288,34 +195,6 @@ macro_rules! impl_base_type { }; } -macro_rules! impl_base_type_serde { - ($name:ident, $expected:literal) => { - impl Serialize for $name { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.canonical().serialize(serializer) - } - } - - impl<'de> Deserialize<'de> for $name { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - match CanonicalType::deserialize(deserializer)? { - CanonicalType::$name(retval) => Ok(retval), - ty => Err(serde::de::Error::invalid_value( - serde::de::Unexpected::Other(ty.as_serde_unexpected_str()), - &$expected, - )), - } - } - } - }; -} - impl_base_type!(UInt); impl_base_type!(SInt); impl_base_type!(Bool); @@ -326,16 +205,6 @@ impl_base_type!(AsyncReset); impl_base_type!(SyncReset); impl_base_type!(Reset); impl_base_type!(Clock); -impl_base_type!(PhantomConst); -impl_base_type!(DynSimOnly); - -impl_base_type_serde!(Bool, "a Bool"); -impl_base_type_serde!(Enum, "an Enum"); -impl_base_type_serde!(Bundle, "a Bundle"); -impl_base_type_serde!(AsyncReset, "an AsyncReset"); -impl_base_type_serde!(SyncReset, "a SyncReset"); -impl_base_type_serde!(Reset, "a Reset"); -impl_base_type_serde!(Clock, "a Clock"); impl sealed::BaseTypeSealed for CanonicalType {} @@ -371,48 +240,26 @@ pub trait Type: { type BaseType: BaseType; type MaskType: Type; - type SimValue: fmt::Debug + Clone + 'static + ToSimValueWithType; type MatchVariant: 'static + Send + Sync; type MatchActiveScope; type MatchVariantAndInactiveScope: MatchVariantAndInactiveScope< - MatchVariant = Self::MatchVariant, - MatchActiveScope = Self::MatchActiveScope, - >; + MatchVariant = Self::MatchVariant, + MatchActiveScope = Self::MatchActiveScope, + >; type MatchVariantsIter: Iterator + ExactSizeIterator + FusedIterator + DoubleEndedIterator; #[track_caller] fn match_variants(this: Expr, source_location: SourceLocation) - -> Self::MatchVariantsIter; + -> Self::MatchVariantsIter; fn mask_type(&self) -> Self::MaskType; fn canonical(&self) -> CanonicalType; fn from_canonical(canonical_type: CanonicalType) -> Self; fn source_location() -> SourceLocation; - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue; - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ); - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> OpaqueSimValueWritten<'w>; } -pub trait BaseType: - Type< - BaseType = Self, - MaskType: Serialize + DeserializeOwned, - SimValue: Serialize + DeserializeOwned, - > + sealed::BaseTypeSealed - + Into - + Serialize - + DeserializeOwned -{ -} +pub trait BaseType: Type + sealed::BaseTypeSealed + Into {} macro_rules! impl_match_variant_as_self { () => { @@ -439,7 +286,6 @@ pub trait TypeWithDeref: Type { impl Type for CanonicalType { type BaseType = CanonicalType; type MaskType = CanonicalType; - type SimValue = OpaqueSimValue; impl_match_variant_as_self!(); fn mask_type(&self) -> Self::MaskType { match self { @@ -453,8 +299,6 @@ impl Type for CanonicalType { CanonicalType::SyncReset(v) => v.mask_type().canonical(), CanonicalType::Reset(v) => v.mask_type().canonical(), CanonicalType::Clock(v) => v.mask_type().canonical(), - CanonicalType::PhantomConst(v) => v.mask_type().canonical(), - CanonicalType::DynSimOnly(v) => v.mask_type().canonical(), } } fn canonical(&self) -> CanonicalType { @@ -466,636 +310,9 @@ impl Type for CanonicalType { fn source_location() -> SourceLocation { SourceLocation::builtin() } - fn sim_value_from_opaque(&self, opaque: OpaqueSimValueSlice<'_>) -> Self::SimValue { - assert_eq!(self.type_properties().size(), opaque.size()); - opaque.to_owned() - } - fn sim_value_clone_from_opaque( - &self, - value: &mut Self::SimValue, - opaque: OpaqueSimValueSlice<'_>, - ) { - assert_eq!(self.type_properties().size(), opaque.size()); - assert_eq!(value.size(), opaque.size()); - value.clone_from_slice(opaque); - } - fn sim_value_to_opaque<'w>( - &self, - value: &Self::SimValue, - writer: OpaqueSimValueWriter<'w>, - ) -> OpaqueSimValueWritten<'w> { - assert_eq!(self.type_properties().size(), writer.size()); - assert_eq!(value.size(), writer.size()); - writer.fill_cloned_from_slice(value.as_slice()) - } } -#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Default)] -#[non_exhaustive] -pub struct OpaqueSimValueSizeRange { - pub bit_width: Range, - pub sim_only_values_len: Range, -} - -impl OpaqueSimValueSizeRange { - pub fn start(&self) -> OpaqueSimValueSize { - OpaqueSimValueSize { - bit_width: self.bit_width.start, - sim_only_values_len: self.sim_only_values_len.start, - } - } - pub fn end(&self) -> OpaqueSimValueSize { - OpaqueSimValueSize { - bit_width: self.bit_width.end, - sim_only_values_len: self.sim_only_values_len.end, - } - } - pub fn is_empty(&self) -> bool { - let Self { - bit_width, - sim_only_values_len, - } = self; - bit_width.is_empty() && sim_only_values_len.is_empty() - } -} - -impl From> for OpaqueSimValueSizeRange { - fn from(value: Range) -> Self { - Self { - bit_width: value.start.bit_width..value.end.bit_width, - sim_only_values_len: value.start.sim_only_values_len..value.end.sim_only_values_len, - } - } -} - -impl From for Range { - fn from(value: OpaqueSimValueSizeRange) -> Self { - value.start()..value.end() - } -} - -pub trait OpaqueSimValueSizeRangeBounds { - fn start_bound(&self) -> Bound; - fn end_bound(&self) -> Bound; -} - -impl OpaqueSimValueSizeRangeBounds for OpaqueSimValueSizeRange { - fn start_bound(&self) -> Bound { - Bound::Included(self.start()) - } - - fn end_bound(&self) -> Bound { - Bound::Excluded(self.end()) - } -} - -impl> OpaqueSimValueSizeRangeBounds for T { - fn start_bound(&self) -> Bound { - std::ops::RangeBounds::start_bound(self).cloned() - } - fn end_bound(&self) -> Bound { - std::ops::RangeBounds::end_bound(self).cloned() - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Default)] -#[non_exhaustive] -pub struct OpaqueSimValueSize { - pub bit_width: usize, - pub sim_only_values_len: usize, -} - -impl OpaqueSimValueSize { - pub const fn from_bit_width(bit_width: usize) -> Self { - Self::from_bit_width_and_sim_only_values_len(bit_width, 0) - } - pub const fn from_bit_width_and_sim_only_values_len( - bit_width: usize, - sim_only_values_len: usize, - ) -> Self { - Self { - bit_width, - sim_only_values_len, - } - } - pub const fn only_bit_width(self) -> Option { - if let Self { - bit_width, - sim_only_values_len: 0, - } = self - { - Some(bit_width) - } else { - None - } - } - pub const fn empty() -> Self { - Self { - bit_width: 0, - sim_only_values_len: 0, - } - } - pub const fn is_empty(self) -> bool { - let Self { - bit_width, - sim_only_values_len, - } = self; - bit_width == 0 && sim_only_values_len == 0 - } - pub const fn checked_mul(self, factor: usize) -> Option { - let Some(bit_width) = self.bit_width.checked_mul(factor) else { - return None; - }; - let Some(sim_only_values_len) = self.sim_only_values_len.checked_mul(factor) else { - return None; - }; - Some(Self { - bit_width, - sim_only_values_len, - }) - } - pub const fn checked_add(self, rhs: Self) -> Option { - let Some(bit_width) = self.bit_width.checked_add(rhs.bit_width) else { - return None; - }; - let Some(sim_only_values_len) = self - .sim_only_values_len - .checked_add(rhs.sim_only_values_len) - else { - return None; - }; - Some(Self { - bit_width, - sim_only_values_len, - }) - } - pub const fn checked_sub(self, rhs: Self) -> Option { - let Some(bit_width) = self.bit_width.checked_sub(rhs.bit_width) else { - return None; - }; - let Some(sim_only_values_len) = self - .sim_only_values_len - .checked_sub(rhs.sim_only_values_len) - else { - return None; - }; - Some(Self { - bit_width, - sim_only_values_len, - }) - } - pub fn try_slice_range( - self, - range: R, - ) -> Option { - let start = range.start_bound(); - let end = range.end_bound(); - let bit_width = try_slice_range( - (start.map(|v| v.bit_width), end.map(|v| v.bit_width)), - self.bit_width, - )?; - let sim_only_values_len = try_slice_range( - ( - start.map(|v| v.sim_only_values_len), - end.map(|v| v.sim_only_values_len), - ), - self.sim_only_values_len, - )?; - Some(OpaqueSimValueSizeRange { - bit_width, - sim_only_values_len, - }) - } - pub fn slice_range( - self, - range: R, - ) -> OpaqueSimValueSizeRange { - self.try_slice_range(range).expect("range out of bounds") - } -} - -impl Mul for OpaqueSimValueSize { - type Output = OpaqueSimValueSize; - - fn mul(self, rhs: usize) -> Self::Output { - self.checked_mul(rhs).expect("multiplication overflowed") - } -} - -impl Mul for usize { - type Output = OpaqueSimValueSize; - - fn mul(self, rhs: OpaqueSimValueSize) -> Self::Output { - rhs.checked_mul(self).expect("multiplication overflowed") - } -} - -impl Add for OpaqueSimValueSize { - type Output = OpaqueSimValueSize; - - fn add(self, rhs: OpaqueSimValueSize) -> Self::Output { - rhs.checked_add(self).expect("addition overflowed") - } -} - -impl Sub for OpaqueSimValueSize { - type Output = OpaqueSimValueSize; - - fn sub(self, rhs: OpaqueSimValueSize) -> Self::Output { - rhs.checked_sub(self).expect("subtraction underflowed") - } -} - -impl MulAssign for OpaqueSimValueSize { - fn mul_assign(&mut self, rhs: usize) { - *self = *self * rhs; - } -} - -impl AddAssign for OpaqueSimValueSize { - fn add_assign(&mut self, rhs: OpaqueSimValueSize) { - *self = *self + rhs; - } -} - -impl SubAssign for OpaqueSimValueSize { - fn sub_assign(&mut self, rhs: OpaqueSimValueSize) { - *self = *self - rhs; - } -} - -impl Sum for OpaqueSimValueSize { - fn sum>(iter: I) -> Self { - iter.fold(OpaqueSimValueSize::empty(), Add::add) - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -pub struct OpaqueSimValue { - bits: UIntValue, - #[serde(skip_serializing_if = "Vec::is_empty", default)] - sim_only_values: Vec, -} - -impl OpaqueSimValue { - pub fn empty() -> Self { - Self { - bits: UIntValue::new(Default::default()), - sim_only_values: Vec::new(), - } - } - pub fn with_capacity(capacity: OpaqueSimValueSize) -> Self { - Self { - bits: UIntValue::new(Arc::new(BitVec::with_capacity(capacity.bit_width))), - sim_only_values: Vec::with_capacity(capacity.sim_only_values_len), - } - } - pub fn size(&self) -> OpaqueSimValueSize { - OpaqueSimValueSize { - bit_width: self.bits.width(), - sim_only_values_len: self.sim_only_values.len(), - } - } - pub fn is_empty(&self) -> bool { - self.size().is_empty() - } - pub fn bit_width(&self) -> usize { - self.bits.width() - } - pub fn bits(&self) -> &UIntValue { - &self.bits - } - pub fn bits_mut(&mut self) -> &mut UIntValue { - &mut self.bits - } - pub fn into_bits(self) -> UIntValue { - self.bits - } - pub fn from_bits(bits: UIntValue) -> Self { - Self { - bits, - sim_only_values: Vec::new(), - } - } - pub fn from_bitslice(v: &BitSlice) -> Self { - Self::from_bitslice_and_sim_only_values(v, Vec::new()) - } - pub fn from_bitslice_and_sim_only_values( - bits: &BitSlice, - sim_only_values: Vec, - ) -> Self { - Self { - bits: UIntValue::new(Arc::new(bits.to_bitvec())), - sim_only_values, - } - } - pub fn from_bits_and_sim_only_values( - bits: UIntValue, - sim_only_values: Vec, - ) -> Self { - Self { - bits, - sim_only_values, - } - } - pub fn into_parts(self) -> (UIntValue, Vec) { - let Self { - bits, - sim_only_values, - } = self; - (bits, sim_only_values) - } - pub fn parts_mut(&mut self) -> (&mut UIntValue, &mut Vec) { - let Self { - bits, - sim_only_values, - } = self; - (bits, sim_only_values) - } - pub fn sim_only_values(&self) -> &[DynSimOnlyValue] { - &self.sim_only_values - } - pub fn sim_only_values_mut(&mut self) -> &mut Vec { - &mut self.sim_only_values - } - pub fn as_slice(&self) -> OpaqueSimValueSlice<'_> { - OpaqueSimValueSlice { - bits: self.bits.bits(), - sim_only_values: &self.sim_only_values, - } - } - pub fn slice(&self, range: R) -> OpaqueSimValueSlice<'_> { - self.as_slice().slice(range) - } - pub fn rewrite_with(&mut self, target_size: OpaqueSimValueSize, f: F) - where - F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand - { - OpaqueSimValueWriter::rewrite_with(target_size, self, f); - } - pub fn clone_from_slice(&mut self, slice: OpaqueSimValueSlice<'_>) { - let OpaqueSimValueSlice { - bits, - sim_only_values, - } = slice; - self.bits.bits_mut().copy_from_bitslice(bits); - self.sim_only_values.clone_from_slice(sim_only_values); - } - pub fn extend_from_slice(&mut self, slice: OpaqueSimValueSlice<'_>) { - let OpaqueSimValueSlice { - bits, - sim_only_values, - } = slice; - self.bits.bitvec_mut().extend_from_bitslice(bits); - self.sim_only_values.extend_from_slice(sim_only_values); - } -} - -impl<'a> Extend> for OpaqueSimValue { - fn extend>>(&mut self, iter: T) { - let Self { - bits, - sim_only_values, - } = self; - let bits = bits.bitvec_mut(); - for slice in iter { - bits.extend_from_bitslice(slice.bits); - sim_only_values.extend_from_slice(slice.sim_only_values); - } - } -} - -impl Extend for OpaqueSimValue { - fn extend>(&mut self, iter: T) { - let Self { - bits, - sim_only_values, - } = self; - let bits = bits.bitvec_mut(); - for value in iter { - bits.extend_from_bitslice(value.bits().bits()); - sim_only_values.extend_from_slice(value.sim_only_values()); - } - } -} - -impl> ToSimValueWithType for OpaqueSimValue { - fn to_sim_value_with_type(&self, ty: T) -> SimValue { - SimValue::from_value(ty, self.clone()) - } - fn into_sim_value_with_type(self, ty: T) -> SimValue { - SimValue::from_value(ty, self) - } -} - -#[derive(Copy, Clone, Debug)] -pub struct OpaqueSimValueSlice<'a> { - bits: &'a BitSlice, - sim_only_values: &'a [DynSimOnlyValue], -} - -impl<'a> Default for OpaqueSimValueSlice<'a> { - fn default() -> Self { - Self::empty() - } -} - -impl<'a> OpaqueSimValueSlice<'a> { - pub fn from_parts(bits: &'a BitSlice, sim_only_values: &'a [DynSimOnlyValue]) -> Self { - Self { - bits, - sim_only_values, - } - } - pub fn from_bitslice(bits: &'a BitSlice) -> Self { - Self::from_parts(bits, &[]) - } - pub fn empty() -> Self { - Self { - bits: BitSlice::empty(), - sim_only_values: &[], - } - } - pub fn size(self) -> OpaqueSimValueSize { - OpaqueSimValueSize { - bit_width: self.bit_width(), - sim_only_values_len: self.sim_only_values_len(), - } - } - pub fn is_empty(self) -> bool { - self.size().is_empty() - } - pub fn bit_width(self) -> usize { - self.bits.len() - } - pub fn bits(self) -> &'a BitSlice { - self.bits - } - pub fn sim_only_values(self) -> &'a [DynSimOnlyValue] { - self.sim_only_values - } - pub fn sim_only_values_len(self) -> usize { - self.sim_only_values.len() - } - pub fn to_owned(self) -> OpaqueSimValue { - OpaqueSimValue::from_bitslice_and_sim_only_values(self.bits, self.sim_only_values.to_vec()) - } - pub fn slice(self, range: R) -> OpaqueSimValueSlice<'a> { - let start = range.start_bound(); - let end = range.end_bound(); - let bits_range = slice_range( - (start.map(|v| v.bit_width), end.map(|v| v.bit_width)), - self.bit_width(), - ); - let sim_only_values_range = slice_range( - (start.map(|v| v.bit_width), end.map(|v| v.bit_width)), - self.sim_only_values_len(), - ); - Self { - bits: &self.bits[bits_range], - sim_only_values: &self.sim_only_values[sim_only_values_range], - } - } - pub fn split_at(self, index: OpaqueSimValueSize) -> (Self, Self) { - let bits = self.bits.split_at(index.bit_width); - let sim_only_values = self.sim_only_values.split_at(index.sim_only_values_len); - ( - Self { - bits: bits.0, - sim_only_values: sim_only_values.0, - }, - Self { - bits: bits.1, - sim_only_values: sim_only_values.1, - }, - ) - } -} - -#[derive(Debug)] -pub struct OpaqueSimValueWriter<'a> { - bits: &'a mut BitSlice, - sim_only_values: &'a mut Vec, - sim_only_values_range: std::ops::Range, -} - -#[derive(Debug)] -pub struct OpaqueSimValueWritten<'a> { - _phantom: PhantomData<&'a ()>, -} - -impl<'a> OpaqueSimValueWriter<'a> { - pub fn sim_only_values_range(&self) -> std::ops::Range { - self.sim_only_values_range.clone() - } - pub fn rewrite_with(target_size: OpaqueSimValueSize, value: &mut OpaqueSimValue, f: F) - where - F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand - { - let OpaqueSimValueWritten { - _phantom: PhantomData, - } = f(OpaqueSimValueWriter::rewrite_helper(target_size, value)); - } - pub(crate) fn rewrite_helper( - target_size: OpaqueSimValueSize, - value: &'a mut OpaqueSimValue, - ) -> Self { - let (bits, sim_only_values) = value.parts_mut(); - let OpaqueSimValueSize { - bit_width, - sim_only_values_len, - } = target_size; - let bits = bits.bitvec_mut(); - bits.resize(bit_width, false); - sim_only_values.truncate(sim_only_values_len); - sim_only_values.reserve_exact(sim_only_values_len - sim_only_values.len()); - Self { - bits, - sim_only_values, - sim_only_values_range: 0..sim_only_values_len, - } - } - pub fn size(&self) -> OpaqueSimValueSize { - OpaqueSimValueSize { - bit_width: self.bit_width(), - sim_only_values_len: self.sim_only_values_len(), - } - } - pub fn bit_width(&self) -> usize { - self.bits.len() - } - pub fn sim_only_values_len(&self) -> usize { - self.sim_only_values_range.len() - } - pub fn is_empty(&self) -> bool { - self.size().is_empty() - } - pub fn fill_cloned_from_slice( - self, - slice: OpaqueSimValueSlice<'_>, - ) -> OpaqueSimValueWritten<'a> { - assert_eq!(self.size(), slice.size()); - let Self { - bits, - sim_only_values, - sim_only_values_range, - } = self; - bits.copy_from_bitslice(slice.bits); - let (clone_from_src, clone_src) = slice.sim_only_values.split_at( - (sim_only_values.len() - sim_only_values_range.start).min(slice.sim_only_values.len()), - ); - sim_only_values[sim_only_values_range.start..][..clone_from_src.len()] - .clone_from_slice(clone_from_src); - sim_only_values.extend_from_slice(clone_src); - OpaqueSimValueWritten { - _phantom: PhantomData, - } - } - pub fn fill_with_bits_with(self, f: F) -> OpaqueSimValueWritten<'a> { - assert!(self.size().only_bit_width().is_some()); - let Self { - bits, - sim_only_values, - sim_only_values_range, - } = self; - f(bits); - assert_eq!(sim_only_values.len(), sim_only_values_range.end); - OpaqueSimValueWritten { - _phantom: PhantomData, - } - } - pub fn fill_with_zeros(self) -> OpaqueSimValueWritten<'a> { - assert!( - self.size().only_bit_width().is_some(), - "can't fill things other than bits with zeros", - ); - self.fill_with_bits_with(|bits| bits.fill(false)) - } - pub fn fill_prefix_with(&mut self, prefix_size: OpaqueSimValueSize, f: F) - where - F: for<'b> FnOnce(OpaqueSimValueWriter<'b>) -> OpaqueSimValueWritten<'b>, // 'b is used as a brand - { - let OpaqueSimValueSize { - bit_width, - sim_only_values_len, - } = prefix_size; - assert!(bit_width <= self.bit_width()); - assert!(sim_only_values_len <= self.sim_only_values_len()); - let next_start = self.sim_only_values_range.start + sim_only_values_len; - let OpaqueSimValueWritten { - _phantom: PhantomData, - } = f(OpaqueSimValueWriter { - bits: &mut self.bits[..bit_width], - sim_only_values: self.sim_only_values, - sim_only_values_range: self.sim_only_values_range.start..next_start, - }); - assert!(self.sim_only_values.len() >= next_start); - self.bits = &mut mem::take(&mut self.bits)[bit_width..]; - self.sim_only_values_range.start = next_start; - } -} - -pub trait StaticType: Type + Default { +pub trait StaticType: Type { const TYPE: Self; const MASK_TYPE: Self::MaskType; const TYPE_PROPERTIES: TypeProperties; diff --git a/crates/fayalite/src/ty/serde_impls.rs b/crates/fayalite/src/ty/serde_impls.rs deleted file mode 100644 index 1ca916b..0000000 --- a/crates/fayalite/src/ty/serde_impls.rs +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - array::Array, - bundle::{Bundle, BundleType}, - clock::Clock, - enum_::{Enum, EnumType}, - int::{Bool, SInt, UInt}, - intern::Interned, - phantom_const::{PhantomConstCanonicalValue, PhantomConstValue}, - prelude::PhantomConst, - reset::{AsyncReset, Reset, SyncReset}, - sim::value::DynSimOnly, - ty::{BaseType, CanonicalType}, -}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -pub(crate) struct SerdePhantomConst(pub T); - -impl Serialize for SerdePhantomConst> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.0.serialize(serializer) - } -} - -impl<'de, T: ?Sized + PhantomConstValue> Deserialize<'de> for SerdePhantomConst> { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - T::deserialize_value(deserializer).map(Self) - } -} - -#[derive(Serialize, Deserialize)] -#[serde(rename = "CanonicalType")] -pub(crate) enum SerdeCanonicalType< - ArrayElement = CanonicalType, - ThePhantomConst = SerdePhantomConst>, -> { - UInt { - width: usize, - }, - SInt { - width: usize, - }, - Bool, - Array { - element: ArrayElement, - len: usize, - }, - Enum { - variants: Interned<[crate::enum_::EnumVariant]>, - }, - Bundle { - fields: Interned<[crate::bundle::BundleField]>, - }, - AsyncReset, - SyncReset, - Reset, - Clock, - PhantomConst(ThePhantomConst), - DynSimOnly(DynSimOnly), -} - -impl SerdeCanonicalType { - pub(crate) fn as_serde_unexpected_str(&self) -> &'static str { - match self { - Self::UInt { .. } => "a UInt", - Self::SInt { .. } => "a SInt", - Self::Bool => "a Bool", - Self::Array { .. } => "an Array", - Self::Enum { .. } => "an Enum", - Self::Bundle { .. } => "a Bundle", - Self::AsyncReset => "an AsyncReset", - Self::SyncReset => "a SyncReset", - Self::Reset => "a Reset", - Self::Clock => "a Clock", - Self::PhantomConst(_) => "a PhantomConst", - Self::DynSimOnly(_) => "a SimOnlyValue", - } - } -} - -impl From for SerdeCanonicalType { - fn from(ty: T) -> Self { - let ty: CanonicalType = ty.into(); - match ty { - CanonicalType::UInt(ty) => Self::UInt { width: ty.width() }, - CanonicalType::SInt(ty) => Self::SInt { width: ty.width() }, - CanonicalType::Bool(Bool {}) => Self::Bool, - CanonicalType::Array(ty) => Self::Array { - element: ty.element(), - len: ty.len(), - }, - CanonicalType::Enum(ty) => Self::Enum { - variants: ty.variants(), - }, - CanonicalType::Bundle(ty) => Self::Bundle { - fields: ty.fields(), - }, - CanonicalType::AsyncReset(AsyncReset {}) => Self::AsyncReset, - CanonicalType::SyncReset(SyncReset {}) => Self::SyncReset, - CanonicalType::Reset(Reset {}) => Self::Reset, - CanonicalType::Clock(Clock {}) => Self::Clock, - CanonicalType::PhantomConst(ty) => Self::PhantomConst(SerdePhantomConst(ty.get())), - CanonicalType::DynSimOnly(ty) => Self::DynSimOnly(ty), - } - } -} - -impl From for CanonicalType { - fn from(ty: SerdeCanonicalType) -> Self { - match ty { - SerdeCanonicalType::UInt { width } => Self::UInt(UInt::new(width)), - SerdeCanonicalType::SInt { width } => Self::SInt(SInt::new(width)), - SerdeCanonicalType::Bool => Self::Bool(Bool), - SerdeCanonicalType::Array { element, len } => Self::Array(Array::new(element, len)), - SerdeCanonicalType::Enum { variants } => Self::Enum(Enum::new(variants)), - SerdeCanonicalType::Bundle { fields } => Self::Bundle(Bundle::new(fields)), - SerdeCanonicalType::AsyncReset => Self::AsyncReset(AsyncReset), - SerdeCanonicalType::SyncReset => Self::SyncReset(SyncReset), - SerdeCanonicalType::Reset => Self::Reset(Reset), - SerdeCanonicalType::Clock => Self::Clock(Clock), - SerdeCanonicalType::PhantomConst(value) => { - Self::PhantomConst(PhantomConst::new(value.0)) - } - SerdeCanonicalType::DynSimOnly(value) => Self::DynSimOnly(value), - } - } -} diff --git a/crates/fayalite/src/util.rs b/crates/fayalite/src/util.rs index 9796488..fadc7af 100644 --- a/crates/fayalite/src/util.rs +++ b/crates/fayalite/src/util.rs @@ -1,23 +1,12 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -pub(crate) mod alternating_cell; mod const_bool; mod const_cmp; mod const_usize; mod misc; mod scoped_ref; pub(crate) mod streaming_read_utf8; -mod test_hasher; - -// allow easily switching the hasher crate-wide for testing -#[cfg(feature = "unstable-test-hasher")] -pub type DefaultBuildHasher = test_hasher::DefaultBuildHasher; -#[cfg(not(feature = "unstable-test-hasher"))] -pub(crate) type DefaultBuildHasher = hashbrown::DefaultHashBuilder; - -pub(crate) type HashMap = hashbrown::HashMap; -pub(crate) type HashSet = hashbrown::HashSet; #[doc(inline)] pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool}; @@ -35,14 +24,9 @@ pub use scoped_ref::ScopedRef; #[doc(inline)] pub use misc::{ - BitSliceWriteWithBase, DebugAsDisplay, DebugAsRawString, MakeMutSlice, RcWriter, - SerdeJsonEscapeIf, SerdeJsonEscapeIfFormatter, SerdeJsonEscapeIfTest, - SerdeJsonEscapeIfTestResult, interned_bit, iter_eq_by, os_str_strip_prefix, - os_str_strip_suffix, serialize_to_json_ascii, serialize_to_json_ascii_pretty, - serialize_to_json_ascii_pretty_with_indent, slice_range, try_slice_range, + get_many_mut, interned_bit, iter_eq_by, BitSliceWriteWithBase, DebugAsDisplay, + DebugAsRawString, MakeMutSlice, RcWriter, }; -pub(crate) use misc::{InternedStrCompareAsStr, chain}; pub mod job_server; -pub mod prefix_sum; pub mod ready_valid; diff --git a/crates/fayalite/src/util/alternating_cell.rs b/crates/fayalite/src/util/alternating_cell.rs deleted file mode 100644 index 17e06a6..0000000 --- a/crates/fayalite/src/util/alternating_cell.rs +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::util::DebugAsDisplay; -use std::{ - cell::{Cell, UnsafeCell}, - fmt, -}; - -pub(crate) trait AlternatingCellMethods { - fn unique_to_shared(&mut self); - fn shared_to_unique(&mut self); -} - -#[derive(Copy, Clone, Debug)] -enum State { - Unique, - Shared, - Locked, -} - -pub(crate) struct AlternatingCell { - state: Cell, - value: UnsafeCell, -} - -impl fmt::Debug for AlternatingCell { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("AlternatingCell") - .field( - self.try_share() - .as_ref() - .map(|v| -> &dyn fmt::Debug { v }) - .unwrap_or(&DebugAsDisplay("<...>")), - ) - .finish() - } -} - -impl AlternatingCell { - pub(crate) const fn new_shared(value: T) -> Self - where - T: Sized, - { - Self { - state: Cell::new(State::Shared), - value: UnsafeCell::new(value), - } - } - pub(crate) const fn new_unique(value: T) -> Self - where - T: Sized, - { - Self { - state: Cell::new(State::Unique), - value: UnsafeCell::new(value), - } - } - pub(crate) fn is_unique(&self) -> bool { - matches!(self.state.get(), State::Unique) - } - pub(crate) fn is_shared(&self) -> bool { - matches!(self.state.get(), State::Shared) - } - pub(crate) fn into_inner(self) -> T - where - T: Sized, - { - self.value.into_inner() - } - pub(crate) fn try_share(&self) -> Option<&T> - where - T: AlternatingCellMethods, - { - match self.state.get() { - State::Shared => {} - State::Unique => { - struct Locked<'a>(&'a Cell); - impl Drop for Locked<'_> { - fn drop(&mut self) { - self.0.set(State::Shared); - } - } - self.state.set(State::Locked); - let lock = Locked(&self.state); - // Safety: state is Locked, so nothing else will - // access value while calling unique_to_shared. - unsafe { &mut *self.value.get() }.unique_to_shared(); - drop(lock); - } - State::Locked => return None, - } - - // Safety: state is Shared so nothing will create any mutable - // references until the returned reference's lifetime expires. - Some(unsafe { &*self.value.get() }) - } - #[track_caller] - pub(crate) fn share(&self) -> &T - where - T: AlternatingCellMethods, - { - let Some(retval) = self.try_share() else { - panic!("`share` called recursively"); - }; - retval - } - pub(crate) fn unique(&mut self) -> &mut T - where - T: AlternatingCellMethods, - { - match self.state.get() { - State::Shared => { - self.state.set(State::Unique); - self.value.get_mut().shared_to_unique(); - } - State::Unique => {} - State::Locked => unreachable!(), - } - self.value.get_mut() - } -} diff --git a/crates/fayalite/src/util/const_bool.rs b/crates/fayalite/src/util/const_bool.rs index 050f6a7..7033d6a 100644 --- a/crates/fayalite/src/util/const_bool.rs +++ b/crates/fayalite/src/util/const_bool.rs @@ -1,9 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -use serde::{ - Deserialize, Deserializer, Serialize, Serializer, - de::{DeserializeOwned, Error, Unexpected}, -}; use std::{fmt::Debug, hash::Hash, mem::ManuallyDrop, ptr}; mod sealed { @@ -13,17 +9,7 @@ mod sealed { /// # Safety /// the only implementation is `ConstBool` pub unsafe trait GenericConstBool: - sealed::Sealed - + Copy - + Ord - + Hash - + Default - + Debug - + 'static - + Send - + Sync - + Serialize - + DeserializeOwned + sealed::Sealed + Copy + Ord + Hash + Default + Debug + 'static + Send + Sync { const VALUE: bool; } @@ -44,32 +30,6 @@ unsafe impl GenericConstBool for ConstBool { const VALUE: bool = VALUE; } -impl Serialize for ConstBool { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - VALUE.serialize(serializer) - } -} - -impl<'de, const VALUE: bool> Deserialize<'de> for ConstBool { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let value = bool::deserialize(deserializer)?; - if value == VALUE { - Ok(ConstBool) - } else { - Err(D::Error::invalid_value( - Unexpected::Bool(value), - &if VALUE { "true" } else { "false" }, - )) - } - } -} - pub trait ConstBoolDispatchTag { type Type; } diff --git a/crates/fayalite/src/util/const_usize.rs b/crates/fayalite/src/util/const_usize.rs index d76f7a7..a605336 100644 --- a/crates/fayalite/src/util/const_usize.rs +++ b/crates/fayalite/src/util/const_usize.rs @@ -1,9 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -use serde::{ - Deserialize, Deserializer, Serialize, Serializer, - de::{DeserializeOwned, Error, Unexpected}, -}; use std::{fmt::Debug, hash::Hash}; mod sealed { @@ -12,17 +8,7 @@ mod sealed { /// the only implementation is `ConstUsize` pub trait GenericConstUsize: - sealed::Sealed - + Copy - + Ord - + Hash - + Default - + Debug - + 'static - + Send - + Sync - + Serialize - + DeserializeOwned + sealed::Sealed + Copy + Ord + Hash + Default + Debug + 'static + Send + Sync { const VALUE: usize; } @@ -41,29 +27,3 @@ impl sealed::Sealed for ConstUsize {} impl GenericConstUsize for ConstUsize { const VALUE: usize = VALUE; } - -impl Serialize for ConstUsize { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - VALUE.serialize(serializer) - } -} - -impl<'de, const VALUE: usize> Deserialize<'de> for ConstUsize { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let value = usize::deserialize(deserializer)?; - if value == VALUE { - Ok(ConstUsize) - } else { - Err(D::Error::invalid_value( - Unexpected::Unsigned(value as u64), - &&*VALUE.to_string(), - )) - } - } -} diff --git a/crates/fayalite/src/util/job_server.rs b/crates/fayalite/src/util/job_server.rs index e58bba8..376ddc0 100644 --- a/crates/fayalite/src/util/job_server.rs +++ b/crates/fayalite/src/util/job_server.rs @@ -1,156 +1,192 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -use ctor::{ctor, dtor}; -use jobslot::Client; +use ctor::ctor; +use jobslot::{Acquired, Client}; use std::{ ffi::OsString, - io, mem, + mem, num::NonZeroUsize, - sync::{Mutex, MutexGuard}, + sync::{Condvar, Mutex, Once, OnceLock}, + thread::spawn, }; -#[ctor] -static CLIENT: Mutex>> = unsafe { Mutex::new(Some(Client::from_env())) }; - -#[dtor] -fn drop_client() { - drop( - match CLIENT.lock() { - Ok(v) => v, - Err(e) => e.into_inner(), +fn get_or_make_client() -> &'static Client { + #[ctor] + static CLIENT: OnceLock = unsafe { + match Client::from_env() { + Some(client) => OnceLock::from(client), + None => OnceLock::new(), } - .take(), - ); -} + }; -fn get_or_make_client() -> Client { - CLIENT - .lock() - .expect("shouldn't have panicked") - .as_mut() - .expect("shutting down") - .get_or_insert_with(|| { - let mut available_parallelism = None; - let mut args = std::env::args_os().skip(1); - while let Some(arg) = args.next() { - const TEST_THREADS_OPTION: &'static [u8] = b"--test-threads"; - if arg.as_encoded_bytes().starts_with(TEST_THREADS_OPTION) { - match arg.as_encoded_bytes().get(TEST_THREADS_OPTION.len()) { - Some(b'=') => { - let mut arg = arg.into_encoded_bytes(); - arg.drain(..=TEST_THREADS_OPTION.len()); - available_parallelism = Some(arg); - break; - } - None => { - available_parallelism = args.next().map(OsString::into_encoded_bytes); - break; - } - _ => {} + CLIENT.get_or_init(|| { + let mut available_parallelism = None; + let mut args = std::env::args_os().skip(1); + while let Some(arg) = args.next() { + const TEST_THREADS_OPTION: &'static [u8] = b"--test-threads"; + if arg.as_encoded_bytes().starts_with(TEST_THREADS_OPTION) { + match arg.as_encoded_bytes().get(TEST_THREADS_OPTION.len()) { + Some(b'=') => { + let mut arg = arg.into_encoded_bytes(); + arg.drain(..=TEST_THREADS_OPTION.len()); + available_parallelism = Some(arg); + break; } + None => { + available_parallelism = args.next().map(OsString::into_encoded_bytes); + break; + } + _ => {} } } - let available_parallelism = if let Some(available_parallelism) = available_parallelism - .as_deref() - .and_then(|v| std::str::from_utf8(v).ok()) - .and_then(|v| v.parse().ok()) - { - available_parallelism - } else if let Ok(available_parallelism) = std::thread::available_parallelism() { - available_parallelism - } else { - NonZeroUsize::new(1).unwrap() - }; - Client::new_with_fifo(available_parallelism.get() - 1) - .expect("failed to create job server") - }) - .clone() + } + let available_parallelism = if let Some(available_parallelism) = available_parallelism + .as_deref() + .and_then(|v| std::str::from_utf8(v).ok()) + .and_then(|v| v.parse().ok()) + { + available_parallelism + } else if let Ok(available_parallelism) = std::thread::available_parallelism() { + available_parallelism + } else { + NonZeroUsize::new(1).unwrap() + }; + Client::new_with_fifo(available_parallelism.get() - 1).expect("failed to create job server") + }) } struct State { - obtained_count: usize, waiting_count: usize, + available: Vec, + implicit_available: bool, +} + +impl State { + fn total_available(&self) -> usize { + self.available.len() + self.implicit_available as usize + } + fn additional_waiting(&self) -> usize { + self.waiting_count.saturating_sub(self.total_available()) + } } static STATE: Mutex = Mutex::new(State { - obtained_count: 0, waiting_count: 0, + available: Vec::new(), + implicit_available: true, }); +static COND_VAR: Condvar = Condvar::new(); + +#[derive(Debug)] +enum AcquiredJobInner { + FromJobServer(Acquired), + ImplicitJob, +} #[derive(Debug)] pub struct AcquiredJob { - client: Client, + job: AcquiredJobInner, } impl AcquiredJob { - pub fn acquire() -> io::Result { - let client = get_or_make_client(); - struct Waiting {} - - impl Waiting { - fn done(self) -> MutexGuard<'static, State> { - mem::forget(self); + fn start_acquire_thread() { + static STARTED_THREAD: Once = Once::new(); + STARTED_THREAD.call_once(|| { + spawn(|| { + let mut acquired = None; + let client = get_or_make_client(); let mut state = STATE.lock().unwrap(); - state.waiting_count -= 1; - state - } - } - impl Drop for Waiting { - fn drop(&mut self) { - STATE.lock().unwrap().waiting_count -= 1; - } - } + loop { + state = if state.additional_waiting() == 0 { + if acquired.is_some() { + drop(state); + drop(acquired.take()); // drop Acquired outside of lock + STATE.lock().unwrap() + } else { + COND_VAR.wait(state).unwrap() + } + } else if acquired.is_some() { + // allocate space before moving Acquired to ensure we + // drop Acquired outside of the lock on panic + state.available.reserve(1); + state.available.push(acquired.take().unwrap()); + COND_VAR.notify_all(); + state + } else { + drop(state); + acquired = Some( + client + .acquire() + .expect("can't acquire token from job server"), + ); + STATE.lock().unwrap() + }; + } + }); + }); + } + fn acquire_inner(block: bool) -> Option { + Self::start_acquire_thread(); let mut state = STATE.lock().unwrap(); - if state.obtained_count == 0 && state.waiting_count == 0 { - state.obtained_count = 1; // get implicit token - return Ok(Self { client }); + loop { + if let Some(acquired) = state.available.pop() { + return Some(Self { + job: AcquiredJobInner::FromJobServer(acquired), + }); + } + if state.implicit_available { + state.implicit_available = false; + return Some(Self { + job: AcquiredJobInner::ImplicitJob, + }); + } + if !block { + return None; + } + state.waiting_count += 1; + state = COND_VAR.wait(state).unwrap(); + state.waiting_count -= 1; } - state.waiting_count += 1; - drop(state); - let waiting = Waiting {}; - client.acquire_raw()?; - state = waiting.done(); - state.obtained_count = state - .obtained_count - .checked_add(1) - .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "obtained_count overflowed"))?; - drop(state); - Ok(Self { client }) + } + pub fn try_acquire() -> Option { + Self::acquire_inner(false) + } + pub fn acquire() -> Self { + Self::acquire_inner(true).expect("failed to acquire token") } pub fn run_command( &mut self, cmd: std::process::Command, f: impl FnOnce(&mut std::process::Command) -> std::io::Result, ) -> std::io::Result { - self.client.configure_make_and_run_with_fifo(cmd, f) + get_or_make_client().configure_make_and_run_with_fifo(cmd, f) } } impl Drop for AcquiredJob { fn drop(&mut self) { let mut state = STATE.lock().unwrap(); - match &mut *state { - State { - obtained_count: 0, .. - } => unreachable!(), - State { - obtained_count: obtained_count @ 1, - waiting_count, - } => { - *obtained_count = 0; // drop implicit token - let any_waiting = *waiting_count != 0; - drop(state); - if any_waiting { - // we have the implicit token, but some other thread is trying to acquire a token, - // release the implicit token so they can acquire it. - let _ = self.client.release_raw(); // we're in drop, just ignore errors since we at least tried + match &self.job { + AcquiredJobInner::FromJobServer(_) => { + if state.waiting_count > state.available.len() + state.implicit_available as usize { + // allocate space before moving Acquired to ensure we + // drop Acquired outside of the lock on panic + state.available.reserve(1); + let AcquiredJobInner::FromJobServer(acquired) = + mem::replace(&mut self.job, AcquiredJobInner::ImplicitJob) + else { + unreachable!() + }; + state.available.push(acquired); + COND_VAR.notify_all(); } } - State { obtained_count, .. } => { - *obtained_count = obtained_count.saturating_sub(1); - drop(state); - let _ = self.client.release_raw(); // we're in drop, just ignore errors since we at least tried + AcquiredJobInner::ImplicitJob => { + state.implicit_available = true; + if state.waiting_count > state.available.len() { + COND_VAR.notify_all(); + } } } } diff --git a/crates/fayalite/src/util/misc.rs b/crates/fayalite/src/util/misc.rs index 165ab3a..f482eaa 100644 --- a/crates/fayalite/src/util/misc.rs +++ b/crates/fayalite/src/util/misc.rs @@ -4,10 +4,7 @@ use crate::intern::{Intern, Interned}; use bitvec::{bits, order::Lsb0, slice::BitSlice, view::BitView}; use std::{ cell::Cell, - ffi::OsStr, fmt::{self, Debug, Write}, - io, - ops::{Bound, Range, RangeBounds}, rc::Rc, sync::{Arc, OnceLock}, }; @@ -166,6 +163,22 @@ impl fmt::UpperHex for BitSliceWriteWithBase<'_> { } } +#[inline] +#[track_caller] +pub fn get_many_mut(slice: &mut [T], indexes: [usize; N]) -> [&mut T; N] { + for i in 0..N { + for j in 0..i { + assert!(indexes[i] != indexes[j], "duplicate index"); + } + assert!(indexes[i] < slice.len(), "index out of bounds"); + } + // Safety: checked that no indexes are duplicates and no indexes are out of bounds + unsafe { + let base = slice.as_mut_ptr(); // convert to a raw pointer before loop to avoid aliasing with &mut [T] + std::array::from_fn(|i| &mut *base.add(indexes[i])) + } +} + #[derive(Clone, Default)] pub struct RcWriter(Rc>>); @@ -212,403 +225,3 @@ impl std::io::Write for RcWriter { Ok(()) } } - -macro_rules! chain { - () => { - std::iter::empty() - }; - ($first:expr $(, $rest:expr)* $(,)?) => { - { - let retval = IntoIterator::into_iter($first); - $(let retval = Iterator::chain(retval, $rest);)* - retval - } - }; -} - -pub(crate) use chain; - -pub fn try_slice_range>(range: R, size: usize) -> Option> { - let start = match range.start_bound() { - Bound::Included(start) => *start, - Bound::Excluded(start) => start.checked_add(1)?, - Bound::Unbounded => 0, - }; - let end = match range.end_bound() { - Bound::Included(end) => end.checked_add(1)?, - Bound::Excluded(end) => *end, - Bound::Unbounded => size, - }; - (start <= end && end <= size).then_some(start..end) -} - -pub fn slice_range>(range: R, size: usize) -> Range { - try_slice_range(range, size).expect("range out of bounds") -} - -pub trait SerdeJsonEscapeIfTest { - fn char_needs_escape(&mut self, ch: char) -> serde_json::Result; -} - -pub trait SerdeJsonEscapeIfTestResult { - fn to_result(self) -> serde_json::Result; -} - -impl SerdeJsonEscapeIfTestResult for bool { - fn to_result(self) -> serde_json::Result { - Ok(self) - } -} - -impl> SerdeJsonEscapeIfTestResult for Result { - fn to_result(self) -> serde_json::Result { - self.map_err(Into::into) - } -} - -impl R, R: SerdeJsonEscapeIfTestResult> SerdeJsonEscapeIfTest for T { - fn char_needs_escape(&mut self, ch: char) -> serde_json::Result { - self(ch).to_result() - } -} - -pub trait SerdeJsonEscapeIfFormatter: serde_json::ser::Formatter { - fn write_unicode_escape(&mut self, writer: &mut W, ch: char) -> io::Result<()> - where - W: ?Sized + io::Write, - { - for utf16 in ch.encode_utf16(&mut [0; 2]) { - write!(writer, "\\u{utf16:04x}")?; - } - Ok(()) - } -} - -impl SerdeJsonEscapeIfFormatter for serde_json::ser::CompactFormatter {} -impl SerdeJsonEscapeIfFormatter for serde_json::ser::PrettyFormatter<'_> {} - -pub struct SerdeJsonEscapeIf { - pub base: Base, - pub test: Test, -} - -impl serde_json::ser::Formatter - for SerdeJsonEscapeIf -{ - fn write_null(&mut self, writer: &mut W) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_null(writer) - } - - fn write_bool(&mut self, writer: &mut W, value: bool) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_bool(writer, value) - } - - fn write_i8(&mut self, writer: &mut W, value: i8) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_i8(writer, value) - } - - fn write_i16(&mut self, writer: &mut W, value: i16) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_i16(writer, value) - } - - fn write_i32(&mut self, writer: &mut W, value: i32) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_i32(writer, value) - } - - fn write_i64(&mut self, writer: &mut W, value: i64) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_i64(writer, value) - } - - fn write_i128(&mut self, writer: &mut W, value: i128) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_i128(writer, value) - } - - fn write_u8(&mut self, writer: &mut W, value: u8) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_u8(writer, value) - } - - fn write_u16(&mut self, writer: &mut W, value: u16) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_u16(writer, value) - } - - fn write_u32(&mut self, writer: &mut W, value: u32) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_u32(writer, value) - } - - fn write_u64(&mut self, writer: &mut W, value: u64) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_u64(writer, value) - } - - fn write_u128(&mut self, writer: &mut W, value: u128) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_u128(writer, value) - } - - fn write_f32(&mut self, writer: &mut W, value: f32) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_f32(writer, value) - } - - fn write_f64(&mut self, writer: &mut W, value: f64) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_f64(writer, value) - } - - fn write_number_str(&mut self, writer: &mut W, value: &str) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_number_str(writer, value) - } - - fn begin_string(&mut self, writer: &mut W) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.begin_string(writer) - } - - fn end_string(&mut self, writer: &mut W) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.end_string(writer) - } - - fn write_string_fragment(&mut self, writer: &mut W, mut fragment: &str) -> io::Result<()> - where - W: ?Sized + io::Write, - { - while let Some((next_escape_index, next_escape_char)) = fragment - .char_indices() - .find_map(|(index, ch)| match self.test.char_needs_escape(ch) { - Ok(false) => None, - Ok(true) => Some(Ok((index, ch))), - Err(e) => Some(Err(e)), - }) - .transpose()? - { - let (no_escapes, rest) = fragment.split_at(next_escape_index); - fragment = &rest[next_escape_char.len_utf8()..]; - self.base.write_string_fragment(writer, no_escapes)?; - self.base.write_unicode_escape(writer, next_escape_char)?; - } - self.base.write_string_fragment(writer, fragment) - } - - fn write_char_escape( - &mut self, - writer: &mut W, - char_escape: serde_json::ser::CharEscape, - ) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_char_escape(writer, char_escape) - } - - fn write_byte_array(&mut self, writer: &mut W, value: &[u8]) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_byte_array(writer, value) - } - - fn begin_array(&mut self, writer: &mut W) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.begin_array(writer) - } - - fn end_array(&mut self, writer: &mut W) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.end_array(writer) - } - - fn begin_array_value(&mut self, writer: &mut W, first: bool) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.begin_array_value(writer, first) - } - - fn end_array_value(&mut self, writer: &mut W) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.end_array_value(writer) - } - - fn begin_object(&mut self, writer: &mut W) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.begin_object(writer) - } - - fn end_object(&mut self, writer: &mut W) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.end_object(writer) - } - - fn begin_object_key(&mut self, writer: &mut W, first: bool) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.begin_object_key(writer, first) - } - - fn end_object_key(&mut self, writer: &mut W) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.end_object_key(writer) - } - - fn begin_object_value(&mut self, writer: &mut W) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.begin_object_value(writer) - } - - fn end_object_value(&mut self, writer: &mut W) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.end_object_value(writer) - } - - fn write_raw_fragment(&mut self, writer: &mut W, fragment: &str) -> io::Result<()> - where - W: ?Sized + io::Write, - { - self.base.write_raw_fragment(writer, fragment) - } -} - -fn serialize_to_json_ascii_helper( - v: &S, - base: F, -) -> serde_json::Result { - let mut retval = Vec::new(); - v.serialize(&mut serde_json::ser::Serializer::with_formatter( - &mut retval, - SerdeJsonEscapeIf { - base, - test: |ch| ch < '\x20' || ch > '\x7F', - }, - ))?; - String::from_utf8(retval).map_err(|_| serde::ser::Error::custom("invalid UTF-8")) -} - -pub fn serialize_to_json_ascii(v: &T) -> serde_json::Result { - serialize_to_json_ascii_helper(v, serde_json::ser::CompactFormatter) -} - -pub fn serialize_to_json_ascii_pretty( - v: &T, -) -> serde_json::Result { - serialize_to_json_ascii_helper(v, serde_json::ser::PrettyFormatter::new()) -} - -pub fn serialize_to_json_ascii_pretty_with_indent( - v: &T, - indent: &str, -) -> serde_json::Result { - serialize_to_json_ascii_helper( - v, - serde_json::ser::PrettyFormatter::with_indent(indent.as_bytes()), - ) -} - -pub fn os_str_strip_prefix<'a>(os_str: &'a OsStr, prefix: impl AsRef) -> Option<&'a OsStr> { - os_str - .as_encoded_bytes() - .strip_prefix(prefix.as_ref().as_bytes()) - .map(|bytes| { - // Safety: we removed a UTF-8 prefix so bytes starts with a valid boundary - unsafe { OsStr::from_encoded_bytes_unchecked(bytes) } - }) -} - -pub fn os_str_strip_suffix<'a>(os_str: &'a OsStr, suffix: impl AsRef) -> Option<&'a OsStr> { - os_str - .as_encoded_bytes() - .strip_suffix(suffix.as_ref().as_bytes()) - .map(|bytes| { - // Safety: we removed a UTF-8 suffix so bytes ends with a valid boundary - unsafe { OsStr::from_encoded_bytes_unchecked(bytes) } - }) -} - -#[derive(Copy, Clone, PartialEq, Eq)] -pub(crate) struct InternedStrCompareAsStr(pub(crate) Interned); - -impl fmt::Debug for InternedStrCompareAsStr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl Ord for InternedStrCompareAsStr { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - str::cmp(&self.0, &other.0) - } -} - -impl PartialOrd for InternedStrCompareAsStr { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl std::borrow::Borrow for InternedStrCompareAsStr { - fn borrow(&self) -> &str { - &self.0 - } -} diff --git a/crates/fayalite/src/util/prefix_sum.rs b/crates/fayalite/src/util/prefix_sum.rs deleted file mode 100644 index 98e6d95..0000000 --- a/crates/fayalite/src/util/prefix_sum.rs +++ /dev/null @@ -1,839 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -// code derived from: -// https://web.archive.org/web/20250303054010/https://git.libre-soc.org/?p=nmutil.git;a=blob;f=src/nmutil/prefix_sum.py;hb=effeb28e5848392adddcdad1f6e7a098f2a44c9c - -use crate::intern::{Intern, Interned, Memoize}; -use std::{borrow::Cow, num::NonZeroUsize}; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub struct PrefixSumOp { - pub lhs_index: usize, - pub rhs_and_dest_index: NonZeroUsize, - pub row: u32, -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -#[non_exhaustive] -pub struct DiagramConfig { - pub space: Cow<'static, str>, - pub vertical_bar: Cow<'static, str>, - pub plus: Cow<'static, str>, - pub slant: Cow<'static, str>, - pub connect: Cow<'static, str>, - pub no_connect: Cow<'static, str>, - pub padding: usize, -} - -impl DiagramConfig { - pub const fn new() -> Self { - Self { - space: Cow::Borrowed(" "), - vertical_bar: Cow::Borrowed("|"), - plus: Cow::Borrowed("\u{2295}"), // ⊕ - slant: Cow::Borrowed(r"\"), - connect: Cow::Borrowed("\u{25CF}"), // ● - no_connect: Cow::Borrowed("X"), - padding: 1, - } - } - pub fn draw(self, ops: impl IntoIterator, item_count: usize) -> String { - #[derive(Copy, Clone, Debug)] - struct DiagramCell { - slant: bool, - plus: bool, - tee: bool, - } - let mut ops_by_row: Vec> = Vec::new(); - let mut last_row = 0; - ops.into_iter().for_each(|op| { - assert!( - op.lhs_index < op.rhs_and_dest_index.get(), - "invalid PrefixSumOp! lhs_index must be less \ - than rhs_and_dest_index: {op:?}", - ); - assert!( - op.row >= last_row, - "invalid PrefixSumOp! row must \ - not decrease (row last was: {last_row}): {op:?}", - ); - let ops = if op.row > last_row || ops_by_row.is_empty() { - ops_by_row.push(vec![]); - ops_by_row.last_mut().expect("just pushed") - } else { - ops_by_row - .last_mut() - .expect("just checked if ops_by_row is empty") - }; - if let Some(last) = ops.last() { - assert!( - op.rhs_and_dest_index < last.rhs_and_dest_index, - "invalid PrefixSumOp! rhs_and_dest_index must strictly \ - decrease in a row:\nthis op: {op:?}\nlast op: {last:?}", - ); - } - ops.push(op); - last_row = op.row; - }); - let blank_row = || { - vec![ - DiagramCell { - slant: false, - plus: false, - tee: false - }; - item_count - ] - }; - let mut cells = vec![blank_row()]; - for ops in ops_by_row { - let max_distance = ops - .iter() - .map( - |&PrefixSumOp { - lhs_index, - rhs_and_dest_index, - .. - }| { rhs_and_dest_index.get() - lhs_index }, - ) - .max() - .expect("ops is known to be non-empty"); - cells.extend((0..max_distance).map(|_| blank_row())); - for op in ops { - let mut y = cells.len() - 1; - assert!( - op.rhs_and_dest_index.get() < item_count, - "invalid PrefixSumOp! rhs_and_dest_index must be \ - less than item_count ({item_count}): {op:?}", - ); - let mut x = op.rhs_and_dest_index.get(); - cells[y][x].plus = true; - x -= 1; - y -= 1; - while op.lhs_index < x { - cells[y][x].slant = true; - x -= 1; - y -= 1; - } - cells[y][x].tee = true; - } - } - let mut retval = String::new(); - let mut row_text = vec![String::new(); 2 * self.padding + 1]; - for cells_row in cells { - for cell in cells_row { - // top padding - for y in 0..self.padding { - // top left padding - for x in 0..self.padding { - row_text[y] += if x == y && (cell.plus || cell.slant) { - &self.slant - } else { - &self.space - }; - } - // top vertical bar - row_text[y] += &self.vertical_bar; - // top right padding - for _ in 0..self.padding { - row_text[y] += &self.space; - } - } - // center left padding - for _ in 0..self.padding { - row_text[self.padding] += &self.space; - } - // center - row_text[self.padding] += if cell.plus { - &self.plus - } else if cell.tee { - &self.connect - } else if cell.slant { - &self.no_connect - } else { - &self.vertical_bar - }; - // center right padding - for _ in 0..self.padding { - row_text[self.padding] += &self.space; - } - let bottom_padding_start = self.padding + 1; - let bottom_padding_last = self.padding * 2; - // bottom padding - for y in bottom_padding_start..=bottom_padding_last { - // bottom left padding - for _ in 0..self.padding { - row_text[y] += &self.space; - } - // bottom vertical bar - row_text[y] += &self.vertical_bar; - // bottom right padding - for x in bottom_padding_start..=bottom_padding_last { - row_text[y] += if x == y && (cell.tee || cell.slant) { - &self.slant - } else { - &self.space - }; - } - } - } - for line in &mut row_text { - retval += line.trim_end(); - retval += "\n"; - line.clear(); - } - } - retval - } -} - -impl Default for DiagramConfig { - fn default() -> Self { - Self::new() - } -} - -impl PrefixSumOp { - pub fn diagram(ops: impl IntoIterator, item_count: usize) -> String { - Self::diagram_with_config(ops, item_count, DiagramConfig::new()) - } - pub fn diagram_with_config( - ops: impl IntoIterator, - item_count: usize, - config: DiagramConfig, - ) -> String { - config.draw(ops, item_count) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum PrefixSumAlgorithm { - /// Uses the algorithm from: - /// - LowLatency, - /// Uses the algorithm from: - /// - WorkEfficient, -} - -impl PrefixSumAlgorithm { - fn ops_impl(self, item_count: usize) -> Vec { - let mut retval = Vec::new(); - let mut distance = 1; - let mut row = 0; - while distance < item_count { - let double_distance = distance - .checked_mul(2) - .expect("prefix-sum item_count is too big"); - let (start, step) = match self { - Self::LowLatency => (distance, 1), - Self::WorkEfficient => (double_distance - 1, double_distance), - }; - for rhs_and_dest_index in (start..item_count).step_by(step).rev() { - let Some(rhs_and_dest_index) = NonZeroUsize::new(rhs_and_dest_index) else { - unreachable!(); - }; - let lhs_index = rhs_and_dest_index.get() - distance; - retval.push(PrefixSumOp { - lhs_index, - rhs_and_dest_index, - row, - }); - } - distance = double_distance; - row += 1; - } - match self { - Self::LowLatency => {} - Self::WorkEfficient => { - distance /= 2; - while distance >= 1 { - let start = distance - .checked_mul(3) - .expect("prefix-sum item_count is too big") - - 1; - for rhs_and_dest_index in (start..item_count).step_by(distance * 2).rev() { - let Some(rhs_and_dest_index) = NonZeroUsize::new(rhs_and_dest_index) else { - unreachable!(); - }; - let lhs_index = rhs_and_dest_index.get() - distance; - retval.push(PrefixSumOp { - lhs_index, - rhs_and_dest_index, - row, - }); - } - row += 1; - distance /= 2; - } - } - } - retval - } - pub fn ops(self, item_count: usize) -> Interned<[PrefixSumOp]> { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - struct MyMemoize(PrefixSumAlgorithm); - impl Memoize for MyMemoize { - type Input = usize; - type InputOwned = usize; - type Output = Interned<[PrefixSumOp]>; - - fn inner(self, item_count: &Self::Input) -> Self::Output { - Intern::intern_owned(self.0.ops_impl(*item_count)) - } - } - MyMemoize(self).get_owned(item_count) - } - pub fn run(self, items: impl IntoIterator, f: impl FnMut(&T, &T) -> T) -> Vec { - let mut items = Vec::from_iter(items); - self.run_on_slice(&mut items, f); - items - } - pub fn run_on_slice(self, items: &mut [T], mut f: impl FnMut(&T, &T) -> T) -> &mut [T] { - self.ops(items.len()).into_iter().for_each( - |PrefixSumOp { - lhs_index, - rhs_and_dest_index, - row: _, - }| { - items[rhs_and_dest_index.get()] = - f(&items[lhs_index], &items[rhs_and_dest_index.get()]); - }, - ); - items - } - pub fn filtered_ops( - self, - item_live_out_flags: impl IntoIterator, - ) -> Vec { - let mut item_live_out_flags = Vec::from_iter(item_live_out_flags); - let prefix_sum_ops = self.ops(item_live_out_flags.len()); - let mut ops_live_flags = vec![false; prefix_sum_ops.len()]; - for ( - op_index, - &PrefixSumOp { - lhs_index, - rhs_and_dest_index, - row: _, - }, - ) in prefix_sum_ops.iter().enumerate().rev() - { - let live = item_live_out_flags[rhs_and_dest_index.get()]; - item_live_out_flags[lhs_index] |= live; - ops_live_flags[op_index] = live; - } - prefix_sum_ops - .into_iter() - .zip(ops_live_flags) - .filter_map(|(op, live)| live.then_some(op)) - .collect() - } - pub fn reduce_ops(self, item_count: usize) -> Interned<[PrefixSumOp]> { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - struct MyMemoize(PrefixSumAlgorithm); - impl Memoize for MyMemoize { - type Input = usize; - type InputOwned = usize; - type Output = Interned<[PrefixSumOp]>; - - fn inner(self, item_count: &Self::Input) -> Self::Output { - let mut item_live_out_flags = vec![false; *item_count]; - let Some(last_item_live_out_flag) = item_live_out_flags.last_mut() else { - return Interned::default(); - }; - *last_item_live_out_flag = true; - Intern::intern_owned(self.0.filtered_ops(item_live_out_flags)) - } - } - MyMemoize(self).get_owned(item_count) - } -} - -pub fn reduce_ops(item_count: usize) -> Interned<[PrefixSumOp]> { - PrefixSumAlgorithm::LowLatency.reduce_ops(item_count) -} - -pub fn reduce(items: impl IntoIterator, mut f: impl FnMut(T, T) -> T) -> Option { - let mut items: Vec<_> = items.into_iter().map(Some).collect(); - for op in reduce_ops(items.len()) { - let (Some(lhs), Some(rhs)) = ( - items[op.lhs_index].take(), - items[op.rhs_and_dest_index.get()].take(), - ) else { - unreachable!(); - }; - items[op.rhs_and_dest_index.get()] = Some(f(lhs, rhs)); - } - items.last_mut().and_then(Option::take) -} - -#[cfg(test)] -mod tests { - use super::*; - - fn input_strings() -> [String; 9] { - std::array::from_fn(|i| String::from_utf8(vec![b'a' + i as u8]).unwrap()) - } - - #[test] - fn test_prefix_sum_strings() { - let input = input_strings(); - let expected: Vec = input - .iter() - .scan(String::new(), |l, r| { - *l += r; - Some(l.clone()) - }) - .collect(); - println!("expected: {expected:?}"); - assert_eq!( - *PrefixSumAlgorithm::WorkEfficient - .run_on_slice(&mut input.clone(), |l, r| l.to_string() + r), - *expected - ); - assert_eq!( - *PrefixSumAlgorithm::LowLatency - .run_on_slice(&mut input.clone(), |l, r| l.to_string() + r), - *expected - ); - } - - #[test] - fn test_reduce_string() { - let input = input_strings(); - let expected = input.clone().into_iter().reduce(|l, r| l + &r); - assert_eq!(reduce(input, |l, r| l + &r), expected); - } - - fn op(lhs_index: usize, rhs_and_dest_index: usize, row: u32) -> PrefixSumOp { - PrefixSumOp { - lhs_index, - rhs_and_dest_index: NonZeroUsize::new(rhs_and_dest_index).expect("should be non-zero"), - row, - } - } - - #[test] - fn test_reduce_ops_9() { - let expected = vec![ - op(7, 8, 0), - op(5, 6, 0), - op(3, 4, 0), - op(1, 2, 0), - op(6, 8, 1), - op(2, 4, 1), - op(4, 8, 2), - op(0, 8, 3), - ]; - println!("expected: {expected:#?}"); - let ops = reduce_ops(9); - println!("ops: {ops:#?}"); - assert_eq!(*ops, *expected); - } - - #[test] - fn test_reduce_ops_8() { - let expected = vec![ - op(6, 7, 0), - op(4, 5, 0), - op(2, 3, 0), - op(0, 1, 0), - op(5, 7, 1), - op(1, 3, 1), - op(3, 7, 2), - ]; - println!("expected: {expected:#?}"); - let ops = reduce_ops(8); - println!("ops: {ops:#?}"); - assert_eq!(*ops, *expected); - } - - #[test] - fn test_count_ones() { - for width in 0..=10u32 { - for v in 0..1u32 << width { - let expected = v.count_ones(); - assert_eq!( - reduce((0..width).map(|i| (v >> i) & 1), |l, r| l + r).unwrap_or(0), - expected, - "v={v:#X}" - ); - } - } - } - - #[track_caller] - fn test_diagram(ops: impl IntoIterator, item_count: usize, expected: &str) { - let text = PrefixSumOp::diagram_with_config( - ops, - item_count, - DiagramConfig { - plus: Cow::Borrowed("@"), - ..Default::default() - }, - ); - println!("text:\n{text}\n"); - assert_eq!(text, expected); - } - - #[test] - fn test_work_efficient_diagram_16() { - let item_count = 16; - test_diagram( - PrefixSumAlgorithm::WorkEfficient.ops(item_count), - item_count, - &r" - | | | | | | | | | | | | | | | | - ● | ● | ● | ● | ● | ● | ● | ● | - |\ | |\ | |\ | |\ | |\ | |\ | |\ | |\ | - | \| | \| | \| | \| | \| | \| | \| | \| - | @ | @ | @ | @ | @ | @ | @ | @ - | |\ | | | |\ | | | |\ | | | |\ | | - | | \| | | | \| | | | \| | | | \| | - | | X | | | X | | | X | | | X | - | | |\ | | | |\ | | | |\ | | | |\ | - | | | \| | | | \| | | | \| | | | \| - | | | @ | | | @ | | | @ | | | @ - | | | |\ | | | | | | | |\ | | | | - | | | | \| | | | | | | | \| | | | - | | | | X | | | | | | | X | | | - | | | | |\ | | | | | | | |\ | | | - | | | | | \| | | | | | | | \| | | - | | | | | X | | | | | | | X | | - | | | | | |\ | | | | | | | |\ | | - | | | | | | \| | | | | | | | \| | - | | | | | | X | | | | | | | X | - | | | | | | |\ | | | | | | | |\ | - | | | | | | | \| | | | | | | | \| - | | | | | | | @ | | | | | | | @ - | | | | | | | |\ | | | | | | | | - | | | | | | | | \| | | | | | | | - | | | | | | | | X | | | | | | | - | | | | | | | | |\ | | | | | | | - | | | | | | | | | \| | | | | | | - | | | | | | | | | X | | | | | | - | | | | | | | | | |\ | | | | | | - | | | | | | | | | | \| | | | | | - | | | | | | | | | | X | | | | | - | | | | | | | | | | |\ | | | | | - | | | | | | | | | | | \| | | | | - | | | | | | | | | | | X | | | | - | | | | | | | | | | | |\ | | | | - | | | | | | | | | | | | \| | | | - | | | | | | | | | | | | X | | | - | | | | | | | | | | | | |\ | | | - | | | | | | | | | | | | | \| | | - | | | | | | | | | | | | | X | | - | | | | | | | | | | | | | |\ | | - | | | | | | | | | | | | | | \| | - | | | | | | | | | | | | | | X | - | | | | | | | | | | | | | | |\ | - | | | | | | | | | | | | | | | \| - | | | | | | | ● | | | | | | | @ - | | | | | | | |\ | | | | | | | | - | | | | | | | | \| | | | | | | | - | | | | | | | | X | | | | | | | - | | | | | | | | |\ | | | | | | | - | | | | | | | | | \| | | | | | | - | | | | | | | | | X | | | | | | - | | | | | | | | | |\ | | | | | | - | | | | | | | | | | \| | | | | | - | | | | | | | | | | X | | | | | - | | | | | | | | | | |\ | | | | | - | | | | | | | | | | | \| | | | | - | | | ● | | | ● | | | @ | | | | - | | | |\ | | | |\ | | | |\ | | | | - | | | | \| | | | \| | | | \| | | | - | | | | X | | | X | | | X | | | - | | | | |\ | | | |\ | | | |\ | | | - | | | | | \| | | | \| | | | \| | | - | ● | ● | @ | ● | @ | ● | @ | | - | |\ | |\ | |\ | |\ | |\ | |\ | |\ | | - | | \| | \| | \| | \| | \| | \| | \| | - | | @ | @ | @ | @ | @ | @ | @ | - | | | | | | | | | | | | | | | | -"[1..], // trim newline at start - ); - } - - #[test] - fn test_low_latency_diagram_16() { - let item_count = 16; - test_diagram( - PrefixSumAlgorithm::LowLatency.ops(item_count), - item_count, - &r" - | | | | | | | | | | | | | | | | - ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● | - |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | - | \| \| \| \| \| \| \| \| \| \| \| \| \| \| \| - ● @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ - |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | | - | \| \| \| \| \| \| \| \| \| \| \| \| \| \| | - | X X X X X X X X X X X X X X | - | |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | - | | \| \| \| \| \| \| \| \| \| \| \| \| \| \| - ● ● @ @ @ @ @ @ @ @ @ @ @ @ @ @ - |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | | | | - | \| \| \| \| \| \| \| \| \| \| \| \| | | | - | X X X X X X X X X X X X | | | - | |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | | | - | | \| \| \| \| \| \| \| \| \| \| \| \| | | - | | X X X X X X X X X X X X | | - | | |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | | - | | | \| \| \| \| \| \| \| \| \| \| \| \| | - | | | X X X X X X X X X X X X | - | | | |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ |\ | - | | | | \| \| \| \| \| \| \| \| \| \| \| \| - ● ● ● ● @ @ @ @ @ @ @ @ @ @ @ @ - |\ |\ |\ |\ |\ |\ |\ |\ | | | | | | | | - | \| \| \| \| \| \| \| \| | | | | | | | - | X X X X X X X X | | | | | | | - | |\ |\ |\ |\ |\ |\ |\ |\ | | | | | | | - | | \| \| \| \| \| \| \| \| | | | | | | - | | X X X X X X X X | | | | | | - | | |\ |\ |\ |\ |\ |\ |\ |\ | | | | | | - | | | \| \| \| \| \| \| \| \| | | | | | - | | | X X X X X X X X | | | | | - | | | |\ |\ |\ |\ |\ |\ |\ |\ | | | | | - | | | | \| \| \| \| \| \| \| \| | | | | - | | | | X X X X X X X X | | | | - | | | | |\ |\ |\ |\ |\ |\ |\ |\ | | | | - | | | | | \| \| \| \| \| \| \| \| | | | - | | | | | X X X X X X X X | | | - | | | | | |\ |\ |\ |\ |\ |\ |\ |\ | | | - | | | | | | \| \| \| \| \| \| \| \| | | - | | | | | | X X X X X X X X | | - | | | | | | |\ |\ |\ |\ |\ |\ |\ |\ | | - | | | | | | | \| \| \| \| \| \| \| \| | - | | | | | | | X X X X X X X X | - | | | | | | | |\ |\ |\ |\ |\ |\ |\ |\ | - | | | | | | | | \| \| \| \| \| \| \| \| - | | | | | | | | @ @ @ @ @ @ @ @ - | | | | | | | | | | | | | | | | -"[1..], // trim newline at start - ); - } - - #[test] - fn test_work_efficient_diagram_9() { - let item_count = 9; - test_diagram( - PrefixSumAlgorithm::WorkEfficient.ops(item_count), - item_count, - &r" - | | | | | | | | | - ● | ● | ● | ● | | - |\ | |\ | |\ | |\ | | - | \| | \| | \| | \| | - | @ | @ | @ | @ | - | |\ | | | |\ | | | - | | \| | | | \| | | - | | X | | | X | | - | | |\ | | | |\ | | - | | | \| | | | \| | - | | | @ | | | @ | - | | | |\ | | | | | - | | | | \| | | | | - | | | | X | | | | - | | | | |\ | | | | - | | | | | \| | | | - | | | | | X | | | - | | | | | |\ | | | - | | | | | | \| | | - | | | | | | X | | - | | | | | | |\ | | - | | | | | | | \| | - | | | ● | | | @ | - | | | |\ | | | | | - | | | | \| | | | | - | | | | X | | | | - | | | | |\ | | | | - | | | | | \| | | | - | ● | ● | @ | ● | - | |\ | |\ | |\ | |\ | - | | \| | \| | \| | \| - | | @ | @ | @ | @ - | | | | | | | | | -"[1..], // trim newline at start - ); - } - - #[test] - fn test_low_latency_diagram_9() { - let item_count = 9; - test_diagram( - PrefixSumAlgorithm::LowLatency.ops(item_count), - item_count, - &r" - | | | | | | | | | - ● ● ● ● ● ● ● ● | - |\ |\ |\ |\ |\ |\ |\ |\ | - | \| \| \| \| \| \| \| \| - ● @ @ @ @ @ @ @ @ - |\ |\ |\ |\ |\ |\ |\ | | - | \| \| \| \| \| \| \| | - | X X X X X X X | - | |\ |\ |\ |\ |\ |\ |\ | - | | \| \| \| \| \| \| \| - ● ● @ @ @ @ @ @ @ - |\ |\ |\ |\ |\ | | | | - | \| \| \| \| \| | | | - | X X X X X | | | - | |\ |\ |\ |\ |\ | | | - | | \| \| \| \| \| | | - | | X X X X X | | - | | |\ |\ |\ |\ |\ | | - | | | \| \| \| \| \| | - | | | X X X X X | - | | | |\ |\ |\ |\ |\ | - | | | | \| \| \| \| \| - ● | | | @ @ @ @ @ - |\ | | | | | | | | - | \| | | | | | | | - | X | | | | | | | - | |\ | | | | | | | - | | \| | | | | | | - | | X | | | | | | - | | |\ | | | | | | - | | | \| | | | | | - | | | X | | | | | - | | | |\ | | | | | - | | | | \| | | | | - | | | | X | | | | - | | | | |\ | | | | - | | | | | \| | | | - | | | | | X | | | - | | | | | |\ | | | - | | | | | | \| | | - | | | | | | X | | - | | | | | | |\ | | - | | | | | | | \| | - | | | | | | | X | - | | | | | | | |\ | - | | | | | | | | \| - | | | | | | | | @ - | | | | | | | | | -"[1..], // trim newline at start - ); - } - - #[test] - fn test_reduce_diagram_16() { - let item_count = 16; - test_diagram( - reduce_ops(item_count), - item_count, - &r" - | | | | | | | | | | | | | | | | - ● | ● | ● | ● | ● | ● | ● | ● | - |\ | |\ | |\ | |\ | |\ | |\ | |\ | |\ | - | \| | \| | \| | \| | \| | \| | \| | \| - | @ | @ | @ | @ | @ | @ | @ | @ - | |\ | | | |\ | | | |\ | | | |\ | | - | | \| | | | \| | | | \| | | | \| | - | | X | | | X | | | X | | | X | - | | |\ | | | |\ | | | |\ | | | |\ | - | | | \| | | | \| | | | \| | | | \| - | | | @ | | | @ | | | @ | | | @ - | | | |\ | | | | | | | |\ | | | | - | | | | \| | | | | | | | \| | | | - | | | | X | | | | | | | X | | | - | | | | |\ | | | | | | | |\ | | | - | | | | | \| | | | | | | | \| | | - | | | | | X | | | | | | | X | | - | | | | | |\ | | | | | | | |\ | | - | | | | | | \| | | | | | | | \| | - | | | | | | X | | | | | | | X | - | | | | | | |\ | | | | | | | |\ | - | | | | | | | \| | | | | | | | \| - | | | | | | | @ | | | | | | | @ - | | | | | | | |\ | | | | | | | | - | | | | | | | | \| | | | | | | | - | | | | | | | | X | | | | | | | - | | | | | | | | |\ | | | | | | | - | | | | | | | | | \| | | | | | | - | | | | | | | | | X | | | | | | - | | | | | | | | | |\ | | | | | | - | | | | | | | | | | \| | | | | | - | | | | | | | | | | X | | | | | - | | | | | | | | | | |\ | | | | | - | | | | | | | | | | | \| | | | | - | | | | | | | | | | | X | | | | - | | | | | | | | | | | |\ | | | | - | | | | | | | | | | | | \| | | | - | | | | | | | | | | | | X | | | - | | | | | | | | | | | | |\ | | | - | | | | | | | | | | | | | \| | | - | | | | | | | | | | | | | X | | - | | | | | | | | | | | | | |\ | | - | | | | | | | | | | | | | | \| | - | | | | | | | | | | | | | | X | - | | | | | | | | | | | | | | |\ | - | | | | | | | | | | | | | | | \| - | | | | | | | | | | | | | | | @ - | | | | | | | | | | | | | | | | -"[1..], // trim newline at start - ); - } - - #[test] - fn test_reduce_diagram_9() { - let item_count = 9; - test_diagram( - reduce_ops(item_count), - item_count, - &r" - | | | | | | | | | - | ● | ● | ● | ● | - | |\ | |\ | |\ | |\ | - | | \| | \| | \| | \| - | | @ | @ | @ | @ - | | |\ | | | |\ | | - | | | \| | | | \| | - | | | X | | | X | - | | | |\ | | | |\ | - | | | | \| | | | \| - | | | | @ | | | @ - | | | | |\ | | | | - | | | | | \| | | | - | | | | | X | | | - | | | | | |\ | | | - | | | | | | \| | | - | | | | | | X | | - | | | | | | |\ | | - | | | | | | | \| | - | | | | | | | X | - | | | | | | | |\ | - | | | | | | | | \| - ● | | | | | | | @ - |\ | | | | | | | | - | \| | | | | | | | - | X | | | | | | | - | |\ | | | | | | | - | | \| | | | | | | - | | X | | | | | | - | | |\ | | | | | | - | | | \| | | | | | - | | | X | | | | | - | | | |\ | | | | | - | | | | \| | | | | - | | | | X | | | | - | | | | |\ | | | | - | | | | | \| | | | - | | | | | X | | | - | | | | | |\ | | | - | | | | | | \| | | - | | | | | | X | | - | | | | | | |\ | | - | | | | | | | \| | - | | | | | | | X | - | | | | | | | |\ | - | | | | | | | | \| - | | | | | | | | @ - | | | | | | | | | -"[1..], // trim newline at start - ); - } -} diff --git a/crates/fayalite/src/util/ready_valid.rs b/crates/fayalite/src/util/ready_valid.rs index 057af46..ac08a64 100644 --- a/crates/fayalite/src/util/ready_valid.rs +++ b/crates/fayalite/src/util/ready_valid.rs @@ -212,7 +212,9 @@ pub fn queue( mod tests { use super::*; use crate::{ - firrtl::ExportOptions, module::transform::simplify_enums::SimplifyEnumsKind, ty::StaticType, + cli::FormalMode, firrtl::ExportOptions, + module::transform::simplify_enums::SimplifyEnumsKind, testing::assert_formal, + ty::StaticType, }; use std::num::NonZero; diff --git a/crates/fayalite/src/util/test_hasher.rs b/crates/fayalite/src/util/test_hasher.rs deleted file mode 100644 index 20df5b7..0000000 --- a/crates/fayalite/src/util/test_hasher.rs +++ /dev/null @@ -1,240 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information -#![cfg(feature = "unstable-test-hasher")] - -use std::{ - fmt::Write as _, - hash::{BuildHasher, Hash, Hasher}, - io::Write as _, - marker::PhantomData, - sync::LazyLock, -}; - -type BoxDynHasher = Box; -type BoxDynBuildHasher = Box; -type BoxDynMakeBuildHasher = Box BoxDynBuildHasher + Send + Sync>; - -trait TryGetDynBuildHasher: Copy { - type Type; - fn try_get_make_build_hasher(self) -> Option; -} - -impl TryGetDynBuildHasher for PhantomData { - type Type = T; - fn try_get_make_build_hasher(self) -> Option { - None - } -} - -impl + Send + Sync + 'static + Clone> - TryGetDynBuildHasher for &'_ PhantomData -{ - type Type = T; - fn try_get_make_build_hasher(self) -> Option { - Some(Box::new(|| Box::>::default())) - } -} - -#[derive(Default, Clone)] -struct DynBuildHasher(T); - -trait DynBuildHasherTrait: BuildHasher { - fn clone_dyn_build_hasher(&self) -> BoxDynBuildHasher; -} - -impl> BuildHasher for DynBuildHasher { - type Hasher = BoxDynHasher; - - fn build_hasher(&self) -> Self::Hasher { - Box::new(self.0.build_hasher()) - } - - fn hash_one(&self, x: T) -> u64 { - self.0.hash_one(x) - } -} - -impl DynBuildHasherTrait for DynBuildHasher -where - Self: Clone + BuildHasher + Send + Sync + 'static, -{ - fn clone_dyn_build_hasher(&self) -> BoxDynBuildHasher { - Box::new(self.clone()) - } -} - -pub struct DefaultBuildHasher(BoxDynBuildHasher); - -impl Clone for DefaultBuildHasher { - fn clone(&self) -> Self { - DefaultBuildHasher(self.0.clone_dyn_build_hasher()) - } -} - -const ENV_VAR_NAME: &'static str = "FAYALITE_TEST_HASHER"; - -struct EnvVarValue { - key: &'static str, - try_get_make_build_hasher: fn() -> Option, - description: &'static str, -} - -macro_rules! env_var_value { - ( - key: $key:literal, - build_hasher: $build_hasher:ty, - description: $description:literal, - ) => { - EnvVarValue { - key: $key, - try_get_make_build_hasher: || { - // use rust method resolution to detect if $build_hasher is usable - // (e.g. hashbrown's hasher won't be usable without the right feature enabled) - (&PhantomData::>).try_get_make_build_hasher() - }, - description: $description, - } - }; -} - -#[derive(Default)] -struct AlwaysZeroHasher; - -impl Hasher for AlwaysZeroHasher { - fn write(&mut self, _bytes: &[u8]) {} - fn finish(&self) -> u64 { - 0 - } -} - -const ENV_VAR_VALUES: &'static [EnvVarValue] = &[ - env_var_value! { - key: "std", - build_hasher: std::hash::RandomState, - description: "use std::hash::RandomState", - }, - env_var_value! { - key: "hashbrown", - build_hasher: hashbrown::DefaultHashBuilder, - description: "use hashbrown's DefaultHashBuilder", - }, - env_var_value! { - key: "always_zero", - build_hasher: std::hash::BuildHasherDefault, - description: "use a hasher that always returns 0 for all hashes,\n \ - this is useful for checking that PartialEq impls are correct", - }, -]; - -fn report_bad_env_var(msg: impl std::fmt::Display) -> ! { - let mut msg = format!("{ENV_VAR_NAME}: {msg}\n"); - for &EnvVarValue { - key, - try_get_make_build_hasher, - description, - } in ENV_VAR_VALUES - { - let availability = match try_get_make_build_hasher() { - Some(_) => "available", - None => "unavailable", - }; - writeln!(msg, "{key}: ({availability})\n {description}").expect("can't fail"); - } - std::io::stderr() - .write_all(msg.as_bytes()) - .expect("should be able to write to stderr"); - std::process::abort(); -} - -impl Default for DefaultBuildHasher { - fn default() -> Self { - static DEFAULT_FN: LazyLock = LazyLock::new(|| { - let var = std::env::var_os(ENV_VAR_NAME); - let var = var.as_deref().unwrap_or("std".as_ref()); - for &EnvVarValue { - key, - try_get_make_build_hasher, - description: _, - } in ENV_VAR_VALUES - { - if var.as_encoded_bytes().eq_ignore_ascii_case(key.as_bytes()) { - return try_get_make_build_hasher().unwrap_or_else(|| { - report_bad_env_var(format_args!( - "unavailable hasher: {key} (is the appropriate feature enabled?)" - )); - }); - } - } - report_bad_env_var(format_args!("unrecognized hasher: {var:?}")); - }); - Self(DEFAULT_FN()) - } -} - -pub struct DefaultHasher(BoxDynHasher); - -impl BuildHasher for DefaultBuildHasher { - type Hasher = DefaultHasher; - - fn build_hasher(&self) -> Self::Hasher { - DefaultHasher(self.0.build_hasher()) - } -} - -impl Hasher for DefaultHasher { - fn finish(&self) -> u64 { - self.0.finish() - } - - fn write(&mut self, bytes: &[u8]) { - self.0.write(bytes) - } - - fn write_u8(&mut self, i: u8) { - self.0.write_u8(i) - } - - fn write_u16(&mut self, i: u16) { - self.0.write_u16(i) - } - - fn write_u32(&mut self, i: u32) { - self.0.write_u32(i) - } - - fn write_u64(&mut self, i: u64) { - self.0.write_u64(i) - } - - fn write_u128(&mut self, i: u128) { - self.0.write_u128(i) - } - - fn write_usize(&mut self, i: usize) { - self.0.write_usize(i) - } - - fn write_i8(&mut self, i: i8) { - self.0.write_i8(i) - } - - fn write_i16(&mut self, i: i16) { - self.0.write_i16(i) - } - - fn write_i32(&mut self, i: i32) { - self.0.write_i32(i) - } - - fn write_i64(&mut self, i: i64) { - self.0.write_i64(i) - } - - fn write_i128(&mut self, i: i128) { - self.0.write_i128(i) - } - - fn write_isize(&mut self, i: isize) { - self.0.write_isize(i) - } -} diff --git a/crates/fayalite/src/vendor.rs b/crates/fayalite/src/vendor.rs deleted file mode 100644 index cdf302d..0000000 --- a/crates/fayalite/src/vendor.rs +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -pub mod xilinx; - -pub(crate) fn built_in_job_kinds() -> impl IntoIterator { - xilinx::built_in_job_kinds() -} - -pub(crate) fn built_in_platforms() -> impl IntoIterator { - xilinx::built_in_platforms() -} diff --git a/crates/fayalite/src/vendor/xilinx.rs b/crates/fayalite/src/vendor/xilinx.rs deleted file mode 100644 index d80f388..0000000 --- a/crates/fayalite/src/vendor/xilinx.rs +++ /dev/null @@ -1,207 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - annotations::make_annotation_enum, - build::{GlobalParams, ToArgs, WriteArgs}, - intern::Interned, - prelude::{DynPlatform, Platform}, -}; -use clap::ValueEnum; -use ordered_float::NotNan; -use serde::{Deserialize, Serialize}; -use std::fmt; - -pub mod arty_a7; -pub mod primitives; -pub mod yosys_nextpnr_prjxray; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct XdcIOStandardAnnotation { - pub value: Interned, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct XdcLocationAnnotation { - pub location: Interned, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct XdcCreateClockAnnotation { - /// clock period in nanoseconds - pub period: NotNan, -} - -make_annotation_enum! { - #[non_exhaustive] - pub enum XilinxAnnotation { - XdcIOStandard(XdcIOStandardAnnotation), - XdcLocation(XdcLocationAnnotation), - XdcCreateClock(XdcCreateClockAnnotation), - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)] -pub struct XilinxArgs { - #[arg(long)] - pub device: Option, -} - -impl XilinxArgs { - pub fn require_device( - &self, - platform: Option<&DynPlatform>, - global_params: &GlobalParams, - ) -> clap::error::Result { - if let Some(device) = self.device { - return Ok(device); - } - if let Some(device) = - platform.and_then(|platform| platform.aspects().get_single_by_type::().copied()) - { - return Ok(device); - } - Err(global_params.clap_error( - clap::error::ErrorKind::MissingRequiredArgument, - "missing --device option", - )) - } -} - -impl ToArgs for XilinxArgs { - fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) { - if let Some(device) = self.device { - args.write_long_option_eq("device", device.as_str()); - } - } -} - -macro_rules! make_device_enum { - ($vis:vis enum $Device:ident { - $( - #[ - name = $name:literal, - xray_part = $xray_part:literal, - xray_device = $xray_device:literal, - xray_family = $xray_family:literal, - ] - $variant:ident, - )* - }) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, ValueEnum)] - $vis enum $Device { - $( - #[value(name = $name, alias = $xray_part)] - $variant, - )* - } - - impl $Device { - $vis fn as_str(self) -> &'static str { - match self { - $(Self::$variant => $name,)* - } - } - $vis fn xray_part(self) -> &'static str { - match self { - $(Self::$variant => $xray_part,)* - } - } - $vis fn xray_device(self) -> &'static str { - match self { - $(Self::$variant => $xray_device,)* - } - } - $vis fn xray_family(self) -> &'static str { - match self { - $(Self::$variant => $xray_family,)* - } - } - } - - struct DeviceVisitor; - - impl<'de> serde::de::Visitor<'de> for DeviceVisitor { - type Value = $Device; - - fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("a Xilinx device string") - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - match $Device::from_str(v, false) { - Ok(v) => Ok(v), - Err(_) => Err(E::invalid_value(serde::de::Unexpected::Str(v), &self)), - } - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: serde::de::Error, - { - match str::from_utf8(v).ok().and_then(|v| $Device::from_str(v, false).ok()) { - Some(v) => Ok(v), - None => Err(E::invalid_value(serde::de::Unexpected::Bytes(v), &self)), - } - } - } - - impl<'de> Deserialize<'de> for $Device { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_string(DeviceVisitor) - } - } - - impl Serialize for $Device { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.as_str().serialize(serializer) - } - } - }; -} - -make_device_enum! { - pub enum Device { - #[ - name = "xc7a35ticsg324-1L", - xray_part = "xc7a35tcsg324-1", - xray_device = "xc7a35t", - xray_family = "artix7", - ] - Xc7a35ticsg324_1l, - #[ - name = "xc7a100ticsg324-1L", - xray_part = "xc7a100tcsg324-1", - xray_device = "xc7a100t", - xray_family = "artix7", - ] - Xc7a100ticsg324_1l, - } -} - -impl fmt::Display for Device { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - -pub(crate) fn built_in_job_kinds() -> impl IntoIterator { - arty_a7::built_in_job_kinds() - .into_iter() - .chain(yosys_nextpnr_prjxray::built_in_job_kinds()) -} - -pub(crate) fn built_in_platforms() -> impl IntoIterator { - arty_a7::built_in_platforms() - .into_iter() - .chain(yosys_nextpnr_prjxray::built_in_platforms()) -} diff --git a/crates/fayalite/src/vendor/xilinx/arty_a7.rs b/crates/fayalite/src/vendor/xilinx/arty_a7.rs deleted file mode 100644 index 552eb4a..0000000 --- a/crates/fayalite/src/vendor/xilinx/arty_a7.rs +++ /dev/null @@ -1,404 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - intern::{Intern, Interned}, - module::{instance_with_loc, reg_builder_with_loc, wire_with_loc}, - platform::{ - DynPlatform, Peripheral, PeripheralRef, Peripherals, PeripheralsBuilderFactory, - PeripheralsBuilderFinished, Platform, PlatformAspectSet, - peripherals::{ClockInput, Led, RgbLed, Uart}, - }, - prelude::*, - vendor::xilinx::{ - Device, XdcCreateClockAnnotation, XdcIOStandardAnnotation, XdcLocationAnnotation, - primitives, - }, -}; -use ordered_float::NotNan; -use std::sync::OnceLock; - -macro_rules! arty_a7_platform { - ( - $vis:vis enum $ArtyA7Platform:ident { - $(#[name = $name:literal, device = $device:ident] - $Variant:ident,)* - } - ) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] - #[non_exhaustive] - $vis enum $ArtyA7Platform { - $($Variant,)* - } - - impl $ArtyA7Platform { - $vis const VARIANTS: &'static [Self] = &[$(Self::$Variant,)*]; - $vis fn device(self) -> Device { - match self { - $(Self::$Variant => Device::$device,)* - } - } - $vis const fn as_str(self) -> &'static str { - match self { - $(Self::$Variant => $name,)* - } - } - fn get_aspects(self) -> &'static PlatformAspectSet { - match self { - $(Self::$Variant => { - static ASPECTS_SET: OnceLock = OnceLock::new(); - ASPECTS_SET.get_or_init(|| self.make_aspects()) - })* - } - } - } - }; -} - -arty_a7_platform! { - pub enum ArtyA7Platform { - #[name = "arty-a7-35t", device = Xc7a35ticsg324_1l] - ArtyA7_35T, - #[name = "arty-a7-100t", device = Xc7a100ticsg324_1l] - ArtyA7_100T, - } -} - -#[derive(Debug)] -pub struct ArtyA7Peripherals { - clk100_div_pow2: [Peripheral; 4], - rst: Peripheral, - rst_sync: Peripheral, - ld0: Peripheral, - ld1: Peripheral, - ld2: Peripheral, - ld3: Peripheral, - ld4: Peripheral, - ld5: Peripheral, - ld6: Peripheral, - ld7: Peripheral, - uart: Peripheral, - // TODO: add rest of peripherals when we need them -} - -impl Peripherals for ArtyA7Peripherals { - fn append_peripherals<'a>(&'a self, peripherals: &mut Vec>) { - let Self { - clk100_div_pow2, - rst, - rst_sync, - ld0, - ld1, - ld2, - ld3, - ld4, - ld5, - ld6, - ld7, - uart, - } = self; - clk100_div_pow2.append_peripherals(peripherals); - rst.append_peripherals(peripherals); - rst_sync.append_peripherals(peripherals); - ld0.append_peripherals(peripherals); - ld1.append_peripherals(peripherals); - ld2.append_peripherals(peripherals); - ld3.append_peripherals(peripherals); - ld4.append_peripherals(peripherals); - ld5.append_peripherals(peripherals); - ld6.append_peripherals(peripherals); - ld7.append_peripherals(peripherals); - uart.append_peripherals(peripherals); - } -} - -impl ArtyA7Platform { - fn make_aspects(self) -> PlatformAspectSet { - let mut retval = PlatformAspectSet::new(); - retval.insert_new(self.device()); - retval - } -} - -#[hdl_module(extern)] -fn reset_sync() { - #[hdl] - let clk: Clock = m.input(); - #[hdl] - let inp: Bool = m.input(); - #[hdl] - let out: SyncReset = m.output(); - m.annotate_module(BlackBoxInlineAnnotation { - path: "fayalite_arty_a7_reset_sync.v".intern(), - text: r#"module __fayalite_arty_a7_reset_sync(input clk, input inp, output out); - wire reset_0_out; - (* ASYNC_REG = "TRUE" *) - FDPE #( - .INIT(1'b1) - ) reset_0 ( - .Q(reset_0_out), - .C(clk), - .CE(1'b1), - .PRE(inp), - .D(1'b0) - ); - (* ASYNC_REG = "TRUE" *) - FDPE #( - .INIT(1'b1) - ) reset_1 ( - .Q(out), - .C(clk), - .CE(1'b1), - .PRE(inp), - .D(reset_0_out) - ); -endmodule -"# - .intern(), - }); - m.verilog_name("__fayalite_arty_a7_reset_sync"); -} - -impl Platform for ArtyA7Platform { - type Peripherals = ArtyA7Peripherals; - - fn name(&self) -> Interned { - self.as_str().intern() - } - - fn new_peripherals<'builder>( - &self, - builder_factory: PeripheralsBuilderFactory<'builder>, - ) -> (Self::Peripherals, PeripheralsBuilderFinished<'builder>) { - let mut builder = builder_factory.builder(); - - let clk100_div_pow2 = std::array::from_fn(|log2_divisor| { - let divisor = 1u64 << log2_divisor; - let name = if divisor != 1 { - format!("clk100_div_{divisor}") - } else { - "clk100".into() - }; - builder.input_peripheral(name, ClockInput::new(100e6 / divisor as f64)) - }); - builder.add_conflicts(Vec::from_iter(clk100_div_pow2.iter().map(|v| v.id()))); - ( - ArtyA7Peripherals { - clk100_div_pow2, - rst: builder.input_peripheral("rst", Reset), - rst_sync: builder.input_peripheral("rst_sync", SyncReset), - ld0: builder.output_peripheral("ld0", RgbLed), - ld1: builder.output_peripheral("ld1", RgbLed), - ld2: builder.output_peripheral("ld2", RgbLed), - ld3: builder.output_peripheral("ld3", RgbLed), - ld4: builder.output_peripheral("ld4", Led), - ld5: builder.output_peripheral("ld5", Led), - ld6: builder.output_peripheral("ld6", Led), - ld7: builder.output_peripheral("ld7", Led), - uart: builder.output_peripheral("uart", Uart), - }, - builder.finish(), - ) - } - - fn source_location(&self) -> SourceLocation { - SourceLocation::builtin() - } - - fn add_peripherals_in_wrapper_module(&self, m: &ModuleBuilder, peripherals: Self::Peripherals) { - let ArtyA7Peripherals { - clk100_div_pow2, - rst, - rst_sync, - ld0, - ld1, - ld2, - ld3, - ld4, - ld5, - ld6, - ld7, - uart, - } = peripherals; - let make_buffered_input = |name: &str, location: &str, io_standard: &str, invert: bool| { - let pin = m.input_with_loc(name, SourceLocation::builtin(), Bool); - annotate( - pin, - XdcLocationAnnotation { - location: location.intern(), - }, - ); - annotate( - pin, - XdcIOStandardAnnotation { - value: io_standard.intern(), - }, - ); - let buf = instance_with_loc( - &format!("{name}_buf"), - primitives::IBUF(), - SourceLocation::builtin(), - ); - connect(buf.I, pin); - if invert { !buf.O } else { buf.O } - }; - let make_buffered_output = |name: &str, location: &str, io_standard: &str| { - let pin = m.output_with_loc(name, SourceLocation::builtin(), Bool); - annotate( - pin, - XdcLocationAnnotation { - location: location.intern(), - }, - ); - annotate( - pin, - XdcIOStandardAnnotation { - value: io_standard.intern(), - }, - ); - let buf = instance_with_loc( - &format!("{name}_buf"), - primitives::OBUFT(), - SourceLocation::builtin(), - ); - connect(pin, buf.O); - connect(buf.T, false); - buf.I - }; - let mut frequency = clk100_div_pow2[0].ty().frequency(); - let mut log2_divisor = 0; - let mut clk = None; - for (cur_log2_divisor, p) in clk100_div_pow2.into_iter().enumerate() { - let Some(p) = p.into_used() else { - continue; - }; - debug_assert!( - clk.is_none(), - "conflict-handling logic should ensure at most one clock is used", - ); - frequency = p.ty().frequency(); - clk = Some(p); - log2_divisor = cur_log2_divisor; - } - let clk100_buf = make_buffered_input("clk100", "E3", "LVCMOS33", false); - let startup = instance_with_loc( - "startup", - primitives::STARTUPE2_default_inputs(), - SourceLocation::builtin(), - ); - let clk_global_buf = instance_with_loc( - "clk_global_buf", - primitives::BUFGCE(), - SourceLocation::builtin(), - ); - connect(clk_global_buf.CE, startup.EOS); - let mut clk_global_buf_in = clk100_buf.to_clock(); - for prev_log2_divisor in 0..log2_divisor { - let prev_divisor = 1u64 << prev_log2_divisor; - let clk_in = wire_with_loc( - &format!("clk_div_{prev_divisor}"), - SourceLocation::builtin(), - Clock, - ); - connect(clk_in, clk_global_buf_in); - annotate( - clk_in, - XdcCreateClockAnnotation { - period: NotNan::new(1e9 / (100e6 / prev_divisor as f64)) - .expect("known to be valid"), - }, - ); - annotate(clk_in, DontTouchAnnotation); - let cd = wire_with_loc( - &format!("clk_div_{prev_divisor}_in"), - SourceLocation::builtin(), - ClockDomain[AsyncReset], - ); - connect(cd.clk, clk_in); - connect(cd.rst, (!startup.EOS).to_async_reset()); - let divider = reg_builder_with_loc("divider", SourceLocation::builtin()) - .clock_domain(cd) - .reset(false) - .build(); - connect(divider, !divider); - clk_global_buf_in = divider.to_clock(); - } - connect(clk_global_buf.I, clk_global_buf_in); - let clk_out = wire_with_loc("clk_out", SourceLocation::builtin(), Clock); - connect(clk_out, clk_global_buf.O); - annotate( - clk_out, - XdcCreateClockAnnotation { - period: NotNan::new(1e9 / frequency).expect("known to be valid"), - }, - ); - annotate(clk_out, DontTouchAnnotation); - if let Some(clk) = clk { - connect(clk.instance_io_field().clk, clk_out); - } - let rst_value = { - let rst_buf = make_buffered_input("rst", "C2", "LVCMOS33", true); - let rst_sync = instance_with_loc("rst_sync", reset_sync(), SourceLocation::builtin()); - connect(rst_sync.clk, clk_out); - connect(rst_sync.inp, rst_buf | !startup.EOS); - rst_sync.out - }; - if let Some(rst) = rst.into_used() { - connect(rst.instance_io_field(), rst_value.to_reset()); - } - if let Some(rst_sync) = rst_sync.into_used() { - connect(rst_sync.instance_io_field(), rst_value); - } - let rgb_leds = [ - (ld0, ("G6", "F6", "E1")), - (ld1, ("G3", "J4", "G4")), - (ld2, ("J3", "J2", "H4")), - (ld3, ("K1", "H6", "K2")), - ]; - for (rgb_led, (r_loc, g_loc, b_loc)) in rgb_leds { - let r = make_buffered_output(&format!("{}_r", rgb_led.name()), r_loc, "LVCMOS33"); - let g = make_buffered_output(&format!("{}_g", rgb_led.name()), g_loc, "LVCMOS33"); - let b = make_buffered_output(&format!("{}_b", rgb_led.name()), b_loc, "LVCMOS33"); - if let Some(rgb_led) = rgb_led.into_used() { - connect(r, rgb_led.instance_io_field().r); - connect(g, rgb_led.instance_io_field().g); - connect(b, rgb_led.instance_io_field().b); - } else { - connect(r, false); - connect(g, false); - connect(b, false); - } - } - let leds = [(ld4, "H5"), (ld5, "J5"), (ld6, "T9"), (ld7, "T10")]; - for (led, loc) in leds { - let o = make_buffered_output(&led.name(), loc, "LVCMOS33"); - if let Some(led) = led.into_used() { - connect(o, led.instance_io_field().on); - } else { - connect(o, false); - } - } - let uart_tx = make_buffered_output("uart_tx", "D10", "LVCMOS33"); - let uart_rx = make_buffered_input("uart_rx", "A9", "LVCMOS33", false); - if let Some(uart) = uart.into_used() { - connect(uart_tx, uart.instance_io_field().tx); - connect(uart.instance_io_field().rx, uart_rx); - } else { - connect(uart_tx, true); // idle - } - } - - fn aspects(&self) -> PlatformAspectSet { - self.get_aspects().clone() - } -} - -pub(crate) fn built_in_job_kinds() -> impl IntoIterator { - [] -} - -pub(crate) fn built_in_platforms() -> impl IntoIterator { - ArtyA7Platform::VARIANTS - .iter() - .map(|&v| DynPlatform::new(v)) -} diff --git a/crates/fayalite/src/vendor/xilinx/primitives.rs b/crates/fayalite/src/vendor/xilinx/primitives.rs deleted file mode 100644 index 9e22d26..0000000 --- a/crates/fayalite/src/vendor/xilinx/primitives.rs +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -#![allow(non_snake_case)] - -use crate::prelude::*; - -#[hdl_module(extern)] -pub fn IBUF() { - m.verilog_name("IBUF"); - #[hdl] - let O: Bool = m.output(); - #[hdl] - let I: Bool = m.input(); -} - -#[hdl_module(extern)] -pub fn OBUFT() { - m.verilog_name("OBUFT"); - #[hdl] - let O: Bool = m.output(); - #[hdl] - let I: Bool = m.input(); - #[hdl] - let T: Bool = m.input(); -} - -#[hdl_module(extern)] -pub fn BUFGCE() { - m.verilog_name("BUFGCE"); - #[hdl] - let O: Clock = m.output(); - #[hdl] - let CE: Bool = m.input(); - #[hdl] - let I: Clock = m.input(); -} - -#[hdl_module(extern)] -pub fn STARTUPE2_default_inputs() { - m.verilog_name("STARTUPE2"); - #[hdl] - let CFGCLK: Clock = m.output(); - #[hdl] - let CFGMCLK: Clock = m.output(); - #[hdl] - let EOS: Bool = m.output(); - #[hdl] - let PREQ: Bool = m.output(); -} diff --git a/crates/fayalite/src/vendor/xilinx/yosys_nextpnr_prjxray.rs b/crates/fayalite/src/vendor/xilinx/yosys_nextpnr_prjxray.rs deleted file mode 100644 index 3e1ac0c..0000000 --- a/crates/fayalite/src/vendor/xilinx/yosys_nextpnr_prjxray.rs +++ /dev/null @@ -1,1043 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -use crate::{ - annotations::{Annotation, TargetedAnnotation}, - build::{ - BaseJob, CommandParams, DynJobKind, GetJobPositionDependencies, GlobalParams, - JobAndDependencies, JobArgsAndDependencies, JobDependencies, JobItem, JobItemName, JobKind, - JobKindAndDependencies, ToArgs, WriteArgs, - external::{ - ExternalCommand, ExternalCommandJob, ExternalCommandJobKind, ExternalProgramTrait, - }, - verilog::{UnadjustedVerilog, VerilogDialect, VerilogJob, VerilogJobKind}, - }, - bundle::{Bundle, BundleType}, - expr::target::{Target, TargetBase}, - firrtl::{ScalarizedModuleABI, ScalarizedModuleABIAnnotations, ScalarizedModuleABIPort}, - intern::{Intern, InternSlice, Interned}, - module::{ - NameId, ScopedNameId, TargetName, - transform::visit::{Visit, Visitor}, - }, - prelude::*, - source_location::SourceLocation, - util::{HashSet, job_server::AcquiredJob}, - vendor::xilinx::{ - Device, XdcCreateClockAnnotation, XdcIOStandardAnnotation, XdcLocationAnnotation, - XilinxAnnotation, XilinxArgs, - }, -}; -use eyre::Context; -use serde::{Deserialize, Serialize}; -use std::{ - convert::Infallible, - ffi::{OsStr, OsString}, - fmt::{self, Write}, - ops::ControlFlow, - path::{Path, PathBuf}, -}; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] -pub struct YosysNextpnrXrayWriteYsFileJobKind; - -#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)] -pub struct YosysNextpnrXrayWriteYsFileArgs {} - -impl ToArgs for YosysNextpnrXrayWriteYsFileArgs { - fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) { - let Self {} = self; - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -pub struct YosysNextpnrXrayWriteYsFile { - main_verilog_file: Interned, - ys_file: Interned, - json_file: Interned, - json_file_name: Interned, -} - -impl YosysNextpnrXrayWriteYsFile { - pub fn main_verilog_file(&self) -> Interned { - self.main_verilog_file - } - pub fn ys_file(&self) -> Interned { - self.ys_file - } - pub fn json_file(&self) -> Interned { - self.json_file - } - pub fn json_file_name(&self) -> Interned { - self.json_file_name - } - fn write_ys( - &self, - output: &mut OsString, - additional_files: &[Interned], - main_module_name_id: NameId, - ) -> eyre::Result<()> { - let Self { - main_verilog_file, - ys_file: _, - json_file: _, - json_file_name, - } = self; - for verilog_file in VerilogJob::all_verilog_files(*main_verilog_file, additional_files)? { - output.push("read_verilog -sv \""); - output.push(verilog_file); - output.push("\"\n"); - } - let circuit_name = crate::firrtl::get_circuit_name(main_module_name_id); - writeln!( - output, - "synth_xilinx -flatten -abc9 -nobram -arch xc7 -top {circuit_name}" - ) - .expect("writing to OsString can't fail"); - output.push("write_json \""); - output.push(json_file_name); - output.push("\"\n"); - Ok(()) - } -} - -impl JobKind for YosysNextpnrXrayWriteYsFileJobKind { - type Args = YosysNextpnrXrayWriteYsFileArgs; - type Job = YosysNextpnrXrayWriteYsFile; - type Dependencies = JobKindAndDependencies; - - fn dependencies(self) -> Self::Dependencies { - Default::default() - } - - fn args_to_jobs( - mut args: JobArgsAndDependencies, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result> { - args.dependencies - .dependencies - .args - .args - .additional_args - .verilog_dialect - .get_or_insert(VerilogDialect::Yosys); - args.args_to_jobs_simple(params, global_params, |_kind, args, dependencies| { - let YosysNextpnrXrayWriteYsFileArgs {} = args; - let base_job = dependencies.get_job::(); - let verilog_job = dependencies.get_job::(); - let json_file = base_job.file_with_ext("json"); - Ok(YosysNextpnrXrayWriteYsFile { - main_verilog_file: verilog_job.main_verilog_file(), - ys_file: base_job.file_with_ext("ys"), - json_file, - json_file_name: json_file - .interned_file_name() - .expect("known to have file name"), - }) - }) - } - - fn inputs(self, _job: &Self::Job) -> Interned<[JobItemName]> { - [JobItemName::DynamicPaths { - source_job_name: VerilogJobKind.name(), - }] - .intern_slice() - } - - fn outputs(self, job: &Self::Job) -> Interned<[JobItemName]> { - [JobItemName::Path { path: job.ys_file }].intern_slice() - } - - fn name(self) -> Interned { - "yosys-nextpnr-xray-write-ys-file".intern() - } - - fn external_command_params(self, _job: &Self::Job) -> Option { - None - } - - fn run( - self, - job: &Self::Job, - inputs: &[JobItem], - params: &JobParams, - _global_params: &GlobalParams, - _acquired_job: &mut AcquiredJob, - ) -> eyre::Result> { - assert!(inputs.iter().map(JobItem::name).eq(self.inputs(job))); - let [additional_files] = inputs else { - unreachable!(); - }; - let additional_files = VerilogJob::unwrap_additional_files(additional_files); - let mut contents = OsString::new(); - job.write_ys( - &mut contents, - additional_files, - params.main_module().name_id(), - )?; - let path = job.ys_file; - std::fs::write(path, contents.as_encoded_bytes()) - .wrap_err_with(|| format!("writing {path:?} failed"))?; - Ok(vec![JobItem::Path { path }]) - } - - fn subcommand_hidden(self) -> bool { - true - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)] -pub struct YosysNextpnrXraySynthArgs {} - -impl ToArgs for YosysNextpnrXraySynthArgs { - fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) { - let Self {} = self; - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Deserialize, Serialize)] -pub struct YosysNextpnrXraySynth { - #[serde(flatten)] - write_ys_file: YosysNextpnrXrayWriteYsFile, - ys_file_name: Interned, -} - -impl fmt::Debug for YosysNextpnrXraySynth { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { - write_ys_file: - YosysNextpnrXrayWriteYsFile { - main_verilog_file, - ys_file, - json_file, - json_file_name, - }, - ys_file_name, - } = self; - f.debug_struct("YosysNextpnrXraySynth") - .field("main_verilog_file", main_verilog_file) - .field("ys_file", ys_file) - .field("ys_file_name", ys_file_name) - .field("json_file", json_file) - .field("json_file_name", json_file_name) - .finish() - } -} - -impl YosysNextpnrXraySynth { - pub fn main_verilog_file(&self) -> Interned { - self.write_ys_file.main_verilog_file() - } - pub fn ys_file(&self) -> Interned { - self.write_ys_file.ys_file() - } - pub fn ys_file_name(&self) -> Interned { - self.ys_file_name - } - pub fn json_file(&self) -> Interned { - self.write_ys_file.json_file() - } - pub fn json_file_name(&self) -> Interned { - self.write_ys_file.json_file_name() - } -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] -pub struct Yosys; - -impl ExternalProgramTrait for Yosys { - fn default_program_name() -> Interned { - "yosys".intern() - } -} - -impl ExternalCommand for YosysNextpnrXraySynth { - type AdditionalArgs = YosysNextpnrXraySynthArgs; - type AdditionalJobData = Self; - type BaseJobPosition = GetJobPositionDependencies< - GetJobPositionDependencies< - GetJobPositionDependencies<::BaseJobPosition>, - >, - >; - type Dependencies = JobKindAndDependencies; - type ExternalProgram = Yosys; - - fn dependencies() -> Self::Dependencies { - Default::default() - } - - fn args_to_jobs( - args: JobArgsAndDependencies>, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result<( - Self::AdditionalJobData, - ::JobsAndKinds, - )> { - args.args_to_jobs_external_simple(params, global_params, |args, dependencies| { - let YosysNextpnrXraySynthArgs {} = args.additional_args; - Ok(Self { - write_ys_file: dependencies.job.job.clone(), - ys_file_name: dependencies - .job - .job - .ys_file() - .interned_file_name() - .expect("known to have file name"), - }) - }) - } - - fn inputs(job: &ExternalCommandJob) -> Interned<[JobItemName]> { - [ - JobItemName::Path { - path: job.additional_job_data().ys_file(), - }, - JobItemName::Path { - path: job.additional_job_data().main_verilog_file(), - }, - JobItemName::DynamicPaths { - source_job_name: VerilogJobKind.name(), - }, - ] - .intern_slice() - } - - fn output_paths(job: &ExternalCommandJob) -> Interned<[Interned]> { - [job.additional_job_data().json_file()].intern_slice() - } - - fn command_line_args(job: &ExternalCommandJob, args: &mut W) { - args.write_arg("-s"); - args.write_interned_arg(job.additional_job_data().ys_file_name()); - } - - fn current_dir(job: &ExternalCommandJob) -> Option> { - Some(job.output_dir()) - } - - fn job_kind_name() -> Interned { - "yosys-nextpnr-xray-synth".intern() - } - - fn subcommand_hidden() -> bool { - true - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] -pub struct YosysNextpnrXrayWriteXdcFileJobKind; - -#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)] -pub struct YosysNextpnrXrayWriteXdcFileArgs {} - -impl ToArgs for YosysNextpnrXrayWriteXdcFileArgs { - fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) { - let Self {} = self; - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -pub struct YosysNextpnrXrayWriteXdcFile { - firrtl_export_options: crate::firrtl::ExportOptions, - output_dir: Interned, - xdc_file: Interned, -} - -struct WriteXdcContentsError(eyre::Report); - -impl From for WriteXdcContentsError { - fn from(v: eyre::Report) -> Self { - Self(v) - } -} - -impl From for WriteXdcContentsError { - fn from(_v: fmt::Error) -> Self { - unreachable!("String write can't fail") - } -} - -fn tcl_escape(s: impl AsRef) -> String { - let s = s.as_ref(); - if !s.contains(|ch: char| !ch.is_alphanumeric() && ch != '_') { - return s.into(); - } - let mut retval = String::with_capacity(s.len().saturating_add(2)); - retval.push('"'); - for ch in s.chars() { - if let '$' | '\\' | '[' = ch { - retval.push('\\'); - } - retval.push(ch); - } - retval.push('"'); - retval -} - -#[derive(Copy, Clone, Debug)] -enum AnnotationTarget { - None, - Module(Module), - Mem(Mem), - Target(Interned), -} - -impl AnnotationTarget { - fn source_location(self) -> SourceLocation { - match self { - AnnotationTarget::None => unreachable!(), - AnnotationTarget::Module(module) => module.source_location(), - AnnotationTarget::Mem(mem) => mem.source_location(), - AnnotationTarget::Target(target) => target.base().source_location(), - } - } -} - -struct XdcFileWriter { - output: W, - module_depth: usize, - annotation_target: AnnotationTarget, - dont_touch_targets: HashSet>, - required_dont_touch_targets: HashSet>, -} - -impl XdcFileWriter { - fn run(output: W, top_module: Module) -> Result<(), WriteXdcContentsError> { - let mut this = Self { - output, - module_depth: 0, - annotation_target: AnnotationTarget::None, - dont_touch_targets: HashSet::default(), - required_dont_touch_targets: HashSet::default(), - }; - top_module.visit(&mut this)?; - let Self { - output: _, - module_depth: _, - annotation_target: _, - dont_touch_targets, - required_dont_touch_targets, - } = this; - for &target in required_dont_touch_targets.difference(&dont_touch_targets) { - return Err(eyre::eyre!( - "a DontTouchAnnotation is required since the target is also annotated with a XilinxAnnotation:\ntarget: {target:?}\nat: {}", - target.base().source_location(), - ).into()); - } - Ok(()) - } - fn default_visit_with>( - &mut self, - module_depth: usize, - annotation_target: AnnotationTarget, - v: &T, - ) -> Result<(), WriteXdcContentsError> { - let Self { - output: _, - module_depth: old_module_depth, - annotation_target: old_annotation_target, - dont_touch_targets: _, - required_dont_touch_targets: _, - } = *self; - self.module_depth = module_depth; - self.annotation_target = annotation_target; - let retval = v.default_visit(self); - self.module_depth = old_module_depth; - self.annotation_target = old_annotation_target; - retval - } -} - -impl Visitor for XdcFileWriter { - type Error = WriteXdcContentsError; - - fn visit_targeted_annotation(&mut self, v: &TargetedAnnotation) -> Result<(), Self::Error> { - self.default_visit_with(self.module_depth, AnnotationTarget::Target(v.target()), v) - } - - fn visit_module(&mut self, v: &Module) -> Result<(), Self::Error> { - self.default_visit_with( - self.module_depth + 1, - AnnotationTarget::Module(v.canonical()), - v, - ) - } - - fn visit_mem( - &mut self, - v: &Mem, - ) -> Result<(), Self::Error> - where - Element: Visit, - { - self.default_visit_with( - self.module_depth + 1, - AnnotationTarget::Mem(v.canonical()), - v, - ) - } - - fn visit_dont_touch_annotation(&mut self, _v: &DontTouchAnnotation) -> Result<(), Self::Error> { - if let AnnotationTarget::Target(target) = self.annotation_target { - self.dont_touch_targets.insert(target); - } - Ok(()) - } - - fn visit_xilinx_annotation(&mut self, v: &XilinxAnnotation) -> Result<(), Self::Error> { - fn todo( - msg: &str, - annotation: &XilinxAnnotation, - source_location: SourceLocation, - ) -> Result { - Err(WriteXdcContentsError(eyre::eyre!( - "{msg}\nannotation: {annotation:?}\nat: {source_location}" - ))) - } - if self.module_depth != 1 { - match todo( - "annotations are not yet supported outside of the top module since the logic to figure out the correct name isn't implemented", - v, - self.annotation_target.source_location(), - )? {} - } - match self.annotation_target { - AnnotationTarget::None => unreachable!(), - AnnotationTarget::Module(module) => match v { - XilinxAnnotation::XdcIOStandard(_) - | XilinxAnnotation::XdcLocation(_) - | XilinxAnnotation::XdcCreateClock(_) => { - return Err(WriteXdcContentsError(eyre::eyre!( - "annotation not allowed on a module: {v:?}\nat: {}", - module.source_location(), - ))); - } - }, - AnnotationTarget::Mem(mem) => match todo( - "xilinx annotations are not yet supported on memories since the logic to figure out the correct name isn't implemented", - v, - mem.source_location(), - )? {}, - AnnotationTarget::Target(target) => { - let base = target.base(); - match *base { - TargetBase::ModuleIO(_) => { - // already handled by write_xdc_contents handling the main module's ScalarizedModuleABI - Ok(()) - } - TargetBase::MemPort(mem_port) => { - match todo( - "xilinx annotations are not yet supported on memory ports since the logic to figure out the correct name isn't implemented", - v, - mem_port.source_location(), - )? {} - } - TargetBase::Reg(_) - | TargetBase::RegSync(_) - | TargetBase::RegAsync(_) - | TargetBase::Wire(_) => { - match *target { - Target::Base(_) => {} - Target::Child(_) => match todo( - "xilinx annotations are not yet supported on parts of registers/wires since the logic to figure out the correct name isn't implemented", - v, - base.source_location(), - )? {}, - } - match base.canonical_ty() { - CanonicalType::UInt(_) - | CanonicalType::SInt(_) - | CanonicalType::Bool(_) - | CanonicalType::AsyncReset(_) - | CanonicalType::SyncReset(_) - | CanonicalType::Reset(_) - | CanonicalType::Clock(_) => {} - CanonicalType::Enum(_) - | CanonicalType::Array(_) - | CanonicalType::Bundle(_) - | CanonicalType::PhantomConst(_) - | CanonicalType::DynSimOnly(_) => match todo( - "xilinx annotations are not yet supported on types other than integers, Bool, resets, or Clock since the logic to figure out the correct name isn't implemented", - v, - base.source_location(), - )? {}, - } - self.required_dont_touch_targets.insert(target); - match v { - XilinxAnnotation::XdcIOStandard(_) - | XilinxAnnotation::XdcLocation(_) => { - return Err(WriteXdcContentsError(eyre::eyre!( - "annotation must be on a ModuleIO: {v:?}\nat: {}", - base.source_location(), - ))); - } - XilinxAnnotation::XdcCreateClock(XdcCreateClockAnnotation { - period, - }) => { - let TargetName(ScopedNameId(_, NameId(name, _)), _) = - base.target_name(); - writeln!( - self.output, - "create_clock -period {period} [get_nets {}]", - tcl_escape(name), - )?; - Ok(()) - } - } - } - TargetBase::Instance(instance) => match todo( - "xilinx annotations are not yet supported on instances' IO since the logic to figure out the correct name isn't implemented", - v, - instance.source_location(), - )? {}, - } - } - } - } -} - -impl YosysNextpnrXrayWriteXdcFile { - fn write_xdc_contents_for_port_and_annotations( - &self, - output: &mut impl fmt::Write, - port: &ScalarizedModuleABIPort, - annotations: ScalarizedModuleABIAnnotations<'_>, - ) -> Result<(), WriteXdcContentsError> { - for annotation in annotations { - match annotation.annotation() { - Annotation::DontTouch(_) - | Annotation::SVAttribute(_) - | Annotation::BlackBoxInline(_) - | Annotation::BlackBoxPath(_) - | Annotation::DocString(_) - | Annotation::CustomFirrtl(_) => {} - Annotation::Xilinx(XilinxAnnotation::XdcLocation(XdcLocationAnnotation { - location, - })) => writeln!( - output, - "set_property LOC {} [get_ports {}]", - tcl_escape(location), - tcl_escape(port.scalarized_name()), - )?, - Annotation::Xilinx(XilinxAnnotation::XdcIOStandard(XdcIOStandardAnnotation { - value, - })) => writeln!( - output, - "set_property IOSTANDARD {} [get_ports {}]", - tcl_escape(value), - tcl_escape(port.scalarized_name()), - )?, - Annotation::Xilinx(XilinxAnnotation::XdcCreateClock( - XdcCreateClockAnnotation { period }, - )) => writeln!( - output, - "create_clock -period {period} [get_ports {}]", - tcl_escape(port.scalarized_name()), - )?, - } - } - Ok(()) - } - fn write_xdc_contents( - &self, - output: &mut String, - top_module: &Module, - ) -> eyre::Result<()> { - let scalarized_module_abi = - ScalarizedModuleABI::new(top_module, self.firrtl_export_options) - .map_err(eyre::Report::from)?; - match scalarized_module_abi.for_each_port_and_annotations(|port, annotations| { - match self.write_xdc_contents_for_port_and_annotations(output, port, annotations) { - Ok(()) => ControlFlow::Continue(()), - Err(e) => ControlFlow::Break(e), - } - }) { - ControlFlow::Continue(()) => {} - ControlFlow::Break(e) => return Err(e.0), - } - XdcFileWriter::run(output, *top_module).map_err(|e| e.0) - } -} - -impl JobKind for YosysNextpnrXrayWriteXdcFileJobKind { - type Args = YosysNextpnrXrayWriteXdcFileArgs; - type Job = YosysNextpnrXrayWriteXdcFile; - type Dependencies = JobKindAndDependencies>; - - fn dependencies(self) -> Self::Dependencies { - Default::default() - } - - fn args_to_jobs( - args: JobArgsAndDependencies, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result> { - let firrtl_export_options = args - .dependencies - .dependencies - .dependencies - .dependencies - .dependencies - .args - .args - .export_options; - args.args_to_jobs_simple(params, global_params, |_kind, args, dependencies| { - let YosysNextpnrXrayWriteXdcFileArgs {} = args; - let base_job = dependencies.get_job::(); - Ok(YosysNextpnrXrayWriteXdcFile { - firrtl_export_options, - output_dir: base_job.output_dir(), - xdc_file: base_job.file_with_ext("xdc"), - }) - }) - } - - fn inputs(self, job: &Self::Job) -> Interned<[JobItemName]> { - [JobItemName::Path { - path: job.output_dir, - }] - .intern_slice() - } - - fn outputs(self, job: &Self::Job) -> Interned<[JobItemName]> { - [JobItemName::Path { path: job.xdc_file }].intern_slice() - } - - fn name(self) -> Interned { - "yosys-nextpnr-xray-write-xdc-file".intern() - } - - fn external_command_params(self, _job: &Self::Job) -> Option { - None - } - - fn run( - self, - job: &Self::Job, - inputs: &[JobItem], - params: &JobParams, - _global_params: &GlobalParams, - _acquired_job: &mut AcquiredJob, - ) -> eyre::Result> { - assert!(inputs.iter().map(JobItem::name).eq(self.inputs(job))); - let mut xdc = String::new(); - job.write_xdc_contents(&mut xdc, params.main_module())?; - std::fs::write(job.xdc_file, xdc)?; - Ok(vec![JobItem::Path { path: job.xdc_file }]) - } - - fn subcommand_hidden(self) -> bool { - true - } -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] -pub struct NextpnrXilinx; - -impl ExternalProgramTrait for NextpnrXilinx { - fn default_program_name() -> Interned { - "nextpnr-xilinx".intern() - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)] -pub struct YosysNextpnrXrayRunNextpnrArgs { - #[command(flatten)] - pub common: XilinxArgs, - #[arg(long, env = "CHIPDB_DIR", value_hint = clap::ValueHint::DirPath)] - pub nextpnr_xilinx_chipdb_dir: PathBuf, - #[arg(long, default_value_t = 0)] - pub nextpnr_xilinx_seed: i32, -} - -impl ToArgs for YosysNextpnrXrayRunNextpnrArgs { - fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) { - let Self { - common, - nextpnr_xilinx_chipdb_dir, - nextpnr_xilinx_seed, - } = self; - common.to_args(args); - args.write_long_option_eq("nextpnr-xilinx-chipdb-dir", nextpnr_xilinx_chipdb_dir); - args.write_display_arg(format_args!("--nextpnr-xilinx-seed={nextpnr_xilinx_seed}")); - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -pub struct YosysNextpnrXrayRunNextpnr { - nextpnr_xilinx_chipdb_dir: Interned, - device: Device, - nextpnr_xilinx_seed: i32, - xdc_file: Interned, - xdc_file_name: Interned, - json_file: Interned, - json_file_name: Interned, - routed_json_file: Interned, - routed_json_file_name: Interned, - fasm_file: Interned, - fasm_file_name: Interned, -} - -impl YosysNextpnrXrayRunNextpnr { - fn chipdb_file(&self) -> Interned { - let mut retval = self - .nextpnr_xilinx_chipdb_dir - .join(self.device.xray_device()); - retval.set_extension("bin"); - retval.intern_deref() - } -} - -impl ExternalCommand for YosysNextpnrXrayRunNextpnr { - type AdditionalArgs = YosysNextpnrXrayRunNextpnrArgs; - type AdditionalJobData = Self; - type BaseJobPosition = GetJobPositionDependencies< - GetJobPositionDependencies<::BaseJobPosition>, - >; - type Dependencies = JobKindAndDependencies; - type ExternalProgram = NextpnrXilinx; - - fn dependencies() -> Self::Dependencies { - Default::default() - } - - fn args_to_jobs( - args: JobArgsAndDependencies>, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result<( - Self::AdditionalJobData, - ::JobsAndKinds, - )> { - args.args_to_jobs_external_simple(params, global_params, |args, dependencies| { - let YosysNextpnrXrayRunNextpnrArgs { - common, - nextpnr_xilinx_chipdb_dir, - nextpnr_xilinx_seed, - } = args.additional_args; - let base_job = dependencies.get_job::(); - let write_xdc_file = dependencies.get_job::(); - let synth = dependencies.get_job::, _>(); - let routed_json_file = base_job.file_with_ext("routed.json"); - let fasm_file = base_job.file_with_ext("fasm"); - Ok(Self { - nextpnr_xilinx_chipdb_dir: nextpnr_xilinx_chipdb_dir.intern_deref(), - device: common.require_device(base_job.platform(), global_params)?, - nextpnr_xilinx_seed, - xdc_file: write_xdc_file.xdc_file, - xdc_file_name: write_xdc_file - .xdc_file - .interned_file_name() - .expect("known to have file name"), - json_file: synth.additional_job_data().json_file(), - json_file_name: synth.additional_job_data().json_file_name(), - routed_json_file, - routed_json_file_name: routed_json_file - .interned_file_name() - .expect("known to have file name"), - fasm_file, - fasm_file_name: fasm_file - .interned_file_name() - .expect("known to have file name"), - }) - }) - } - - fn inputs(job: &ExternalCommandJob) -> Interned<[JobItemName]> { - [ - JobItemName::Path { - path: job.additional_job_data().json_file, - }, - JobItemName::Path { - path: job.additional_job_data().xdc_file, - }, - ] - .intern_slice() - } - - fn output_paths(job: &ExternalCommandJob) -> Interned<[Interned]> { - [ - job.additional_job_data().routed_json_file, - job.additional_job_data().fasm_file, - ] - .intern_slice() - } - - fn command_line_args(job: &ExternalCommandJob, args: &mut W) { - let job_data @ YosysNextpnrXrayRunNextpnr { - nextpnr_xilinx_seed, - xdc_file_name, - json_file_name, - routed_json_file_name, - fasm_file_name, - .. - } = job.additional_job_data(); - args.write_long_option_eq("chipdb", job_data.chipdb_file()); - args.write_long_option_eq("xdc", xdc_file_name); - args.write_long_option_eq("json", json_file_name); - args.write_long_option_eq("write", routed_json_file_name); - args.write_long_option_eq("fasm", fasm_file_name); - args.write_display_arg(format_args!("--seed={nextpnr_xilinx_seed}")); - } - - fn current_dir(job: &ExternalCommandJob) -> Option> { - Some(job.output_dir()) - } - - fn job_kind_name() -> Interned { - "yosys-nextpnr-xray-run-nextpnr".intern() - } - - fn subcommand_hidden() -> bool { - true - } -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] -pub struct Xcfasm; - -impl ExternalProgramTrait for Xcfasm { - fn default_program_name() -> Interned { - "xcfasm".intern() - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)] -pub struct YosysNextpnrXrayArgs { - #[arg(long, env = "DB_DIR", value_hint = clap::ValueHint::DirPath)] - pub prjxray_db_dir: PathBuf, -} - -impl ToArgs for YosysNextpnrXrayArgs { - fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) { - let Self { prjxray_db_dir } = self; - args.write_long_option_eq("prjxray-db-dir", prjxray_db_dir); - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -pub struct YosysNextpnrXray { - prjxray_db_dir: Interned, - device: Device, - fasm_file: Interned, - fasm_file_name: Interned, - frames_file: Interned, - frames_file_name: Interned, - bit_file: Interned, - bit_file_name: Interned, -} - -impl YosysNextpnrXray { - fn db_root(&self) -> Interned { - self.prjxray_db_dir - .join(self.device.xray_family()) - .intern_deref() - } - fn part_file(&self) -> Interned { - let mut retval = self.prjxray_db_dir.join(self.device.xray_family()); - retval.push(self.device.xray_part()); - retval.push("part.yaml"); - retval.intern_deref() - } -} - -impl ExternalCommand for YosysNextpnrXray { - type AdditionalArgs = YosysNextpnrXrayArgs; - type AdditionalJobData = Self; - type BaseJobPosition = GetJobPositionDependencies< - ::BaseJobPosition, - >; - type Dependencies = JobKindAndDependencies>; - type ExternalProgram = Xcfasm; - - fn dependencies() -> Self::Dependencies { - Default::default() - } - - fn args_to_jobs( - args: JobArgsAndDependencies>, - params: &JobParams, - global_params: &GlobalParams, - ) -> eyre::Result<( - Self::AdditionalJobData, - ::JobsAndKinds, - )> { - args.args_to_jobs_external_simple(params, global_params, |args, dependencies| { - let YosysNextpnrXrayArgs { prjxray_db_dir } = args.additional_args; - let base_job = dependencies.get_job::(); - let frames_file = base_job.file_with_ext("frames"); - let bit_file = base_job.file_with_ext("bit"); - Ok(Self { - prjxray_db_dir: prjxray_db_dir.intern_deref(), - device: dependencies.job.job.additional_job_data().device, - fasm_file: dependencies.job.job.additional_job_data().fasm_file, - fasm_file_name: dependencies.job.job.additional_job_data().fasm_file_name, - frames_file, - frames_file_name: frames_file - .interned_file_name() - .expect("known to have file name"), - bit_file, - bit_file_name: bit_file - .interned_file_name() - .expect("known to have file name"), - }) - }) - } - - fn inputs(job: &ExternalCommandJob) -> Interned<[JobItemName]> { - [JobItemName::Path { - path: job.additional_job_data().fasm_file, - }] - .intern_slice() - } - - fn output_paths(job: &ExternalCommandJob) -> Interned<[Interned]> { - [ - job.additional_job_data().frames_file, - job.additional_job_data().bit_file, - ] - .intern_slice() - } - - fn command_line_args(job: &ExternalCommandJob, args: &mut W) { - let job_data @ YosysNextpnrXray { - device, - fasm_file_name, - frames_file_name, - bit_file_name, - .. - } = job.additional_job_data(); - args.write_arg("--sparse"); - args.write_long_option_eq("db-root", job_data.db_root()); - args.write_long_option_eq("part", device.xray_part()); - args.write_long_option_eq("part_file", job_data.part_file()); - args.write_long_option_eq("fn_in", fasm_file_name); - args.write_long_option_eq("frm_out", frames_file_name); - args.write_long_option_eq("bit_out", bit_file_name); - } - - fn current_dir(job: &ExternalCommandJob) -> Option> { - Some(job.output_dir()) - } - - fn job_kind_name() -> Interned { - "yosys-nextpnr-xray".intern() - } -} - -pub(crate) fn built_in_job_kinds() -> impl IntoIterator { - [ - DynJobKind::new(YosysNextpnrXrayWriteYsFileJobKind), - DynJobKind::new(ExternalCommandJobKind::::new()), - DynJobKind::new(YosysNextpnrXrayWriteXdcFileJobKind), - DynJobKind::new(ExternalCommandJobKind::::new()), - DynJobKind::new(ExternalCommandJobKind::::new()), - ] -} - -pub(crate) fn built_in_platforms() -> impl IntoIterator { - [] -} diff --git a/crates/fayalite/tests/formal.rs b/crates/fayalite/tests/formal.rs index cb78d1d..65264dc 100644 --- a/crates/fayalite/tests/formal.rs +++ b/crates/fayalite/tests/formal.rs @@ -2,7 +2,19 @@ // See Notices.txt for copyright information //! Formal tests in Fayalite -use fayalite::prelude::*; +use fayalite::{ + cli::FormalMode, + clock::{Clock, ClockDomain}, + expr::{CastTo, HdlPartialEq}, + firrtl::ExportOptions, + formal::{any_const, any_seq, formal_reset, hdl_assert, hdl_assume}, + hdl, hdl_module, + int::{Bool, DynSize, Size, UInt, UIntType}, + module::{connect, connect_any, instance, memory, reg_builder, wire}, + reset::ToReset, + testing::assert_formal, + ty::StaticType, +}; /// Test hidden state /// @@ -107,7 +119,7 @@ mod hidden_state { FormalMode::Prove, 16, None, - Default::default(), + ExportOptions::default(), ); // here a couple of cycles is enough assert_formal( @@ -116,7 +128,7 @@ mod hidden_state { FormalMode::Prove, 2, None, - Default::default(), + ExportOptions::default(), ); } } @@ -230,7 +242,7 @@ mod memory { #[hdl] let wr: WritePort = wire(WritePort[n]); connect(wr.addr, any_seq(UInt[n])); - connect(wr.data, any_seq(UInt::<8>::new_static())); + connect(wr.data, any_seq(UInt::<8>::TYPE)); connect(wr.en, any_seq(Bool)); #[hdl] let dut = instance(example_sram(n)); @@ -277,7 +289,7 @@ mod memory { FormalMode::Prove, 2, None, - Default::default(), + ExportOptions::default(), ); } } diff --git a/crates/fayalite/tests/hdl_types.rs b/crates/fayalite/tests/hdl_types.rs index 148cb64..b191016 100644 --- a/crates/fayalite/tests/hdl_types.rs +++ b/crates/fayalite/tests/hdl_types.rs @@ -9,11 +9,6 @@ use fayalite::{ }; use std::marker::PhantomData; -#[hdl(outline_generated)] -pub struct MyConstSize { - pub size: PhantomConst>, -} - #[hdl(outline_generated)] pub struct S { pub a: T, @@ -196,21 +191,3 @@ check_bounds!(CheckBoundsTTT2<#[a, Type] A: BundleType +, #[b, Type] B: Type +, check_bounds!(CheckBoundsTTT3<#[a, Type] A: EnumType +, #[b, Type] B: Type +, #[c, Type] C: Type +>); check_bounds!(CheckBoundsTTT4<#[a, Type] A: IntType +, #[b, Type] B: Type +, #[c, Type] C: Type +>); check_bounds!(CheckBoundsTTT5<#[a, Type] A: StaticType +, #[b, Type] B: Type +, #[c, Type] C: Type +>); - -#[derive(Clone, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)] -pub struct MyPhantomConstInner { - pub a: usize, - pub b: UInt, -} - -#[hdl(outline_generated, get(|v| v.a))] -pub type GetA> = DynSize; - -#[hdl(outline_generated, get(|v| v.b))] -pub type GetB> = UInt; - -#[hdl(outline_generated, no_static)] -pub struct MyTypeWithPhantomConstParameter> { - pub a: ArrayType>, - pub b: HdlOption>, -} diff --git a/crates/fayalite/tests/module.rs b/crates/fayalite/tests/module.rs index a039250..4e56df4 100644 --- a/crates/fayalite/tests/module.rs +++ b/crates/fayalite/tests/module.rs @@ -1,14 +1,8 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use fayalite::{ - assert_export_firrtl, - firrtl::ExportOptions, - int::{UIntInRange, UIntInRangeInclusive}, - intern::Intern, - module::transform::simplify_enums::SimplifyEnumsKind, - platform::PlatformIOBuilder, - prelude::*, - reset::ResetType, + assert_export_firrtl, firrtl::ExportOptions, intern::Intern, + module::transform::simplify_enums::SimplifyEnumsKind, prelude::*, reset::ResetType, ty::StaticType, }; use serde_json::json; @@ -197,14 +191,10 @@ circuit check_array_repeat: }; } -pub trait UnknownTrait {} - -impl UnknownTrait for T {} - #[hdl_module(outline_generated)] pub fn check_skipped_generics(v: U) where - T: StaticType + UnknownTrait, + T: StaticType, ConstUsize: KnownSize, U: std::fmt::Display, { @@ -386,18 +376,18 @@ circuit check_written_inside_both_if_else: }; } -#[hdl(outline_generated, cmp_eq)] +#[hdl(outline_generated)] pub struct TestStruct { pub a: T, pub b: UInt<8>, } -#[hdl(outline_generated, cmp_eq)] +#[hdl(outline_generated)] pub struct TestStruct2 { pub v: UInt<8>, } -#[hdl(outline_generated, cmp_eq)] +#[hdl(outline_generated)] pub struct TestStruct3 {} #[hdl_module(outline_generated)] @@ -4355,332 +4345,3 @@ circuit check_cfgs: ", }; } - -#[hdl_module(outline_generated)] -pub fn check_let_patterns() { - #[hdl] - let tuple_in: (UInt<1>, SInt<1>, Bool) = m.input(); - #[hdl] - let (tuple_0, tuple_1, tuple_2) = tuple_in; - #[hdl] - let tuple_0_out: UInt<1> = m.output(); - connect(tuple_0_out, tuple_0); - #[hdl] - let tuple_1_out: SInt<1> = m.output(); - connect(tuple_1_out, tuple_1); - #[hdl] - let tuple_2_out: Bool = m.output(); - connect(tuple_2_out, tuple_2); - - #[hdl] - let test_struct_in: TestStruct> = m.input(); - #[hdl] - let TestStruct::<_> { a, b } = test_struct_in; - #[hdl] - let test_struct_a_out: SInt<8> = m.output(); - connect(test_struct_a_out, a); - #[hdl] - let test_struct_b_out: UInt<8> = m.output(); - connect(test_struct_b_out, b); - - #[hdl] - let test_struct_2_in: TestStruct2 = m.input(); - #[hdl] - let TestStruct2 { v } = test_struct_2_in; - #[hdl] - let test_struct_2_v_out: UInt<8> = m.output(); - connect(test_struct_2_v_out, v); - - #[hdl] - let test_struct_3_in: TestStruct3 = m.input(); - #[hdl] - let TestStruct3 {} = test_struct_3_in; -} - -#[test] -fn test_let_patterns() { - let _n = SourceLocation::normalize_files_for_tests(); - let m = check_let_patterns(); - dbg!(m); - #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 - assert_export_firrtl! { - m => - "/test/check_let_patterns.fir": r"FIRRTL version 3.2.0 -circuit check_let_patterns: - type Ty0 = {`0`: UInt<1>, `1`: SInt<1>, `2`: UInt<1>} - type Ty1 = {a: SInt<8>, b: UInt<8>} - type Ty2 = {v: UInt<8>} - type Ty3 = {} - module check_let_patterns: @[module-XXXXXXXXXX.rs 1:1] - input tuple_in: Ty0 @[module-XXXXXXXXXX.rs 2:1] - output tuple_0_out: UInt<1> @[module-XXXXXXXXXX.rs 4:1] - output tuple_1_out: SInt<1> @[module-XXXXXXXXXX.rs 6:1] - output tuple_2_out: UInt<1> @[module-XXXXXXXXXX.rs 8:1] - input test_struct_in: Ty1 @[module-XXXXXXXXXX.rs 10:1] - output test_struct_a_out: SInt<8> @[module-XXXXXXXXXX.rs 12:1] - output test_struct_b_out: UInt<8> @[module-XXXXXXXXXX.rs 14:1] - input test_struct_2_in: Ty2 @[module-XXXXXXXXXX.rs 16:1] - output test_struct_2_v_out: UInt<8> @[module-XXXXXXXXXX.rs 18:1] - input test_struct_3_in: Ty3 @[module-XXXXXXXXXX.rs 20:1] - connect tuple_0_out, tuple_in.`0` @[module-XXXXXXXXXX.rs 5:1] - connect tuple_1_out, tuple_in.`1` @[module-XXXXXXXXXX.rs 7:1] - connect tuple_2_out, tuple_in.`2` @[module-XXXXXXXXXX.rs 9:1] - connect test_struct_a_out, test_struct_in.a @[module-XXXXXXXXXX.rs 13:1] - connect test_struct_b_out, test_struct_in.b @[module-XXXXXXXXXX.rs 15:1] - connect test_struct_2_v_out, test_struct_2_in.v @[module-XXXXXXXXXX.rs 19:1] -", - }; -} - -#[hdl_module(outline_generated)] -pub fn check_struct_cmp_eq() { - #[hdl] - let tuple_lhs: (UInt<1>, SInt<1>, Bool) = m.input(); - #[hdl] - let tuple_rhs: (UInt<1>, SInt<1>, Bool) = m.input(); - #[hdl] - let tuple_cmp_eq: Bool = m.output(); - connect(tuple_cmp_eq, tuple_lhs.cmp_eq(tuple_rhs)); - #[hdl] - let tuple_cmp_ne: Bool = m.output(); - connect(tuple_cmp_ne, tuple_lhs.cmp_ne(tuple_rhs)); - - #[hdl] - let test_struct_lhs: TestStruct> = m.input(); - #[hdl] - let test_struct_rhs: TestStruct> = m.input(); - #[hdl] - let test_struct_cmp_eq: Bool = m.output(); - connect(test_struct_cmp_eq, test_struct_lhs.cmp_eq(test_struct_rhs)); - #[hdl] - let test_struct_cmp_ne: Bool = m.output(); - connect(test_struct_cmp_ne, test_struct_lhs.cmp_ne(test_struct_rhs)); - - #[hdl] - let test_struct_2_lhs: TestStruct2 = m.input(); - #[hdl] - let test_struct_2_rhs: TestStruct2 = m.input(); - #[hdl] - let test_struct_2_cmp_eq: Bool = m.output(); - connect( - test_struct_2_cmp_eq, - test_struct_2_lhs.cmp_eq(test_struct_2_rhs), - ); - #[hdl] - let test_struct_2_cmp_ne: Bool = m.output(); - connect( - test_struct_2_cmp_ne, - test_struct_2_lhs.cmp_ne(test_struct_2_rhs), - ); - - #[hdl] - let test_struct_3_lhs: TestStruct3 = m.input(); - #[hdl] - let test_struct_3_rhs: TestStruct3 = m.input(); - #[hdl] - let test_struct_3_cmp_eq: Bool = m.output(); - connect( - test_struct_3_cmp_eq, - test_struct_3_lhs.cmp_eq(test_struct_3_rhs), - ); - #[hdl] - let test_struct_3_cmp_ne: Bool = m.output(); - connect( - test_struct_3_cmp_ne, - test_struct_3_lhs.cmp_ne(test_struct_3_rhs), - ); -} - -#[test] -fn test_struct_cmp_eq() { - let _n = SourceLocation::normalize_files_for_tests(); - let m = check_struct_cmp_eq(); - dbg!(m); - #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 - assert_export_firrtl! { - m => - "/test/check_struct_cmp_eq.fir": r"FIRRTL version 3.2.0 -circuit check_struct_cmp_eq: - type Ty0 = {`0`: UInt<1>, `1`: SInt<1>, `2`: UInt<1>} - type Ty1 = {a: SInt<8>, b: UInt<8>} - type Ty2 = {v: UInt<8>} - type Ty3 = {} - module check_struct_cmp_eq: @[module-XXXXXXXXXX.rs 1:1] - input tuple_lhs: Ty0 @[module-XXXXXXXXXX.rs 2:1] - input tuple_rhs: Ty0 @[module-XXXXXXXXXX.rs 3:1] - output tuple_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 4:1] - output tuple_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 6:1] - input test_struct_lhs: Ty1 @[module-XXXXXXXXXX.rs 8:1] - input test_struct_rhs: Ty1 @[module-XXXXXXXXXX.rs 9:1] - output test_struct_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 10:1] - output test_struct_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 12:1] - input test_struct_2_lhs: Ty2 @[module-XXXXXXXXXX.rs 14:1] - input test_struct_2_rhs: Ty2 @[module-XXXXXXXXXX.rs 15:1] - output test_struct_2_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 16:1] - output test_struct_2_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 18:1] - input test_struct_3_lhs: Ty3 @[module-XXXXXXXXXX.rs 20:1] - input test_struct_3_rhs: Ty3 @[module-XXXXXXXXXX.rs 21:1] - output test_struct_3_cmp_eq: UInt<1> @[module-XXXXXXXXXX.rs 22:1] - output test_struct_3_cmp_ne: UInt<1> @[module-XXXXXXXXXX.rs 24:1] - wire _array_literal_expr: UInt<1>[3] - connect _array_literal_expr[0], eq(tuple_lhs.`0`, tuple_rhs.`0`) - connect _array_literal_expr[1], eq(tuple_lhs.`1`, tuple_rhs.`1`) - connect _array_literal_expr[2], eq(tuple_lhs.`2`, tuple_rhs.`2`) - wire _cast_array_to_bits_expr: UInt<1>[3] - connect _cast_array_to_bits_expr[0], _array_literal_expr[0] - connect _cast_array_to_bits_expr[1], _array_literal_expr[1] - connect _cast_array_to_bits_expr[2], _array_literal_expr[2] - wire _cast_to_bits_expr: UInt<3> - connect _cast_to_bits_expr, cat(_cast_array_to_bits_expr[2], cat(_cast_array_to_bits_expr[1], _cast_array_to_bits_expr[0])) - connect tuple_cmp_eq, andr(_cast_to_bits_expr) @[module-XXXXXXXXXX.rs 5:1] - wire _array_literal_expr_1: UInt<1>[3] - connect _array_literal_expr_1[0], neq(tuple_lhs.`0`, tuple_rhs.`0`) - connect _array_literal_expr_1[1], neq(tuple_lhs.`1`, tuple_rhs.`1`) - connect _array_literal_expr_1[2], neq(tuple_lhs.`2`, tuple_rhs.`2`) - wire _cast_array_to_bits_expr_1: UInt<1>[3] - connect _cast_array_to_bits_expr_1[0], _array_literal_expr_1[0] - connect _cast_array_to_bits_expr_1[1], _array_literal_expr_1[1] - connect _cast_array_to_bits_expr_1[2], _array_literal_expr_1[2] - wire _cast_to_bits_expr_1: UInt<3> - connect _cast_to_bits_expr_1, cat(_cast_array_to_bits_expr_1[2], cat(_cast_array_to_bits_expr_1[1], _cast_array_to_bits_expr_1[0])) - connect tuple_cmp_ne, orr(_cast_to_bits_expr_1) @[module-XXXXXXXXXX.rs 7:1] - connect test_struct_cmp_eq, and(eq(test_struct_lhs.a, test_struct_rhs.a), eq(test_struct_lhs.b, test_struct_rhs.b)) @[module-XXXXXXXXXX.rs 11:1] - connect test_struct_cmp_ne, or(neq(test_struct_lhs.a, test_struct_rhs.a), neq(test_struct_lhs.b, test_struct_rhs.b)) @[module-XXXXXXXXXX.rs 13:1] - connect test_struct_2_cmp_eq, eq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 17:1] - connect test_struct_2_cmp_ne, neq(test_struct_2_lhs.v, test_struct_2_rhs.v) @[module-XXXXXXXXXX.rs 19:1] - connect test_struct_3_cmp_eq, UInt<1>(0h1) @[module-XXXXXXXXXX.rs 23:1] - connect test_struct_3_cmp_ne, UInt<1>(0h0) @[module-XXXXXXXXXX.rs 25:1] -", - }; -} - -#[hdl_module(outline_generated)] -pub fn check_uint_in_range() { - #[hdl] - let i_0_to_1: UIntInRange<0, 1> = m.input(); - #[hdl] - let i_0_to_2: UIntInRange<0, 2> = m.input(); - #[hdl] - let i_0_to_3: UIntInRange<0, 3> = m.input(); - #[hdl] - let i_0_to_4: UIntInRange<0, 4> = m.input(); - #[hdl] - let i_0_to_7: UIntInRange<0, 7> = m.input(); - #[hdl] - let i_0_to_8: UIntInRange<0, 8> = m.input(); - #[hdl] - let i_0_to_9: UIntInRange<0, 9> = m.input(); - #[hdl] - let i_0_through_0: UIntInRangeInclusive<0, 0> = m.input(); - #[hdl] - let i_0_through_1: UIntInRangeInclusive<0, 1> = m.input(); - #[hdl] - let i_0_through_2: UIntInRangeInclusive<0, 2> = m.input(); - #[hdl] - let i_0_through_3: UIntInRangeInclusive<0, 3> = m.input(); - #[hdl] - let i_0_through_4: UIntInRangeInclusive<0, 4> = m.input(); - #[hdl] - let i_0_through_7: UIntInRangeInclusive<0, 7> = m.input(); - #[hdl] - let i_0_through_8: UIntInRangeInclusive<0, 8> = m.input(); - #[hdl] - let i_0_through_9: UIntInRangeInclusive<0, 9> = m.input(); -} - -#[test] -fn test_uint_in_range() { - let _n = SourceLocation::normalize_files_for_tests(); - let m = check_uint_in_range(); - dbg!(m); - #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 - assert_export_firrtl! { - m => - "/test/check_uint_in_range.fir": r"FIRRTL version 3.2.0 -circuit check_uint_in_range: - type Ty0 = {value: UInt<0>, range: {}} - type Ty1 = {value: UInt<1>, range: {}} - type Ty2 = {value: UInt<2>, range: {}} - type Ty3 = {value: UInt<2>, range: {}} - type Ty4 = {value: UInt<3>, range: {}} - type Ty5 = {value: UInt<3>, range: {}} - type Ty6 = {value: UInt<4>, range: {}} - type Ty7 = {value: UInt<0>, range: {}} - type Ty8 = {value: UInt<1>, range: {}} - type Ty9 = {value: UInt<2>, range: {}} - type Ty10 = {value: UInt<2>, range: {}} - type Ty11 = {value: UInt<3>, range: {}} - type Ty12 = {value: UInt<3>, range: {}} - type Ty13 = {value: UInt<4>, range: {}} - type Ty14 = {value: UInt<4>, range: {}} - module check_uint_in_range: @[module-XXXXXXXXXX.rs 1:1] - input i_0_to_1: Ty0 @[module-XXXXXXXXXX.rs 2:1] - input i_0_to_2: Ty1 @[module-XXXXXXXXXX.rs 3:1] - input i_0_to_3: Ty2 @[module-XXXXXXXXXX.rs 4:1] - input i_0_to_4: Ty3 @[module-XXXXXXXXXX.rs 5:1] - input i_0_to_7: Ty4 @[module-XXXXXXXXXX.rs 6:1] - input i_0_to_8: Ty5 @[module-XXXXXXXXXX.rs 7:1] - input i_0_to_9: Ty6 @[module-XXXXXXXXXX.rs 8:1] - input i_0_through_0: Ty7 @[module-XXXXXXXXXX.rs 9:1] - input i_0_through_1: Ty8 @[module-XXXXXXXXXX.rs 10:1] - input i_0_through_2: Ty9 @[module-XXXXXXXXXX.rs 11:1] - input i_0_through_3: Ty10 @[module-XXXXXXXXXX.rs 12:1] - input i_0_through_4: Ty11 @[module-XXXXXXXXXX.rs 13:1] - input i_0_through_7: Ty12 @[module-XXXXXXXXXX.rs 14:1] - input i_0_through_8: Ty13 @[module-XXXXXXXXXX.rs 15:1] - input i_0_through_9: Ty14 @[module-XXXXXXXXXX.rs 16:1] -", - }; -} - -#[hdl_module(outline_generated)] -pub fn check_platform_io(platform_io_builder: PlatformIOBuilder<'_>) { - #[hdl] - let io = m.add_platform_io(platform_io_builder); -} - -#[cfg(todo)] -#[test] -fn test_platform_io() { - let _n = SourceLocation::normalize_files_for_tests(); - let m = check_platform_io(todo!()); - dbg!(m); - #[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161 - assert_export_firrtl! { - m => - "/test/check_platform_io.fir": r"FIRRTL version 3.2.0 -circuit check_platform_io: - type Ty0 = {value: UInt<0>, range: {}} - type Ty1 = {value: UInt<1>, range: {}} - type Ty2 = {value: UInt<2>, range: {}} - type Ty3 = {value: UInt<2>, range: {}} - type Ty4 = {value: UInt<3>, range: {}} - type Ty5 = {value: UInt<3>, range: {}} - type Ty6 = {value: UInt<4>, range: {}} - type Ty7 = {value: UInt<0>, range: {}} - type Ty8 = {value: UInt<1>, range: {}} - type Ty9 = {value: UInt<2>, range: {}} - type Ty10 = {value: UInt<2>, range: {}} - type Ty11 = {value: UInt<3>, range: {}} - type Ty12 = {value: UInt<3>, range: {}} - type Ty13 = {value: UInt<4>, range: {}} - type Ty14 = {value: UInt<4>, range: {}} - module check_platform_io: @[module-XXXXXXXXXX.rs 1:1] - input i_0_to_1: Ty0 @[module-XXXXXXXXXX.rs 2:1] - input i_0_to_2: Ty1 @[module-XXXXXXXXXX.rs 3:1] - input i_0_to_3: Ty2 @[module-XXXXXXXXXX.rs 4:1] - input i_0_to_4: Ty3 @[module-XXXXXXXXXX.rs 5:1] - input i_0_to_7: Ty4 @[module-XXXXXXXXXX.rs 6:1] - input i_0_to_8: Ty5 @[module-XXXXXXXXXX.rs 7:1] - input i_0_to_9: Ty6 @[module-XXXXXXXXXX.rs 8:1] - input i_0_through_0: Ty7 @[module-XXXXXXXXXX.rs 9:1] - input i_0_through_1: Ty8 @[module-XXXXXXXXXX.rs 10:1] - input i_0_through_2: Ty9 @[module-XXXXXXXXXX.rs 11:1] - input i_0_through_3: Ty10 @[module-XXXXXXXXXX.rs 12:1] - input i_0_through_4: Ty11 @[module-XXXXXXXXXX.rs 13:1] - input i_0_through_7: Ty12 @[module-XXXXXXXXXX.rs 14:1] - input i_0_through_8: Ty13 @[module-XXXXXXXXXX.rs 15:1] - input i_0_through_9: Ty14 @[module-XXXXXXXXXX.rs 16:1] -", - }; -} diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index 873978a..a249235 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -2,14 +2,14 @@ // See Notices.txt for copyright information use fayalite::{ - memory::{ReadStruct, ReadWriteStruct, WriteStruct}, - module::{instance_with_loc, memory_with_init_and_loc, reg_builder_with_loc}, + int::UIntValue, prelude::*, reset::ResetType, - sim::vcd::VcdWriterDecls, + sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation, ToSimValue}, + ty::StaticType, util::RcWriter, }; -use std::{collections::BTreeMap, num::NonZeroUsize, rc::Rc}; +use std::num::NonZeroUsize; #[hdl_module(outline_generated)] pub fn connect_const() { @@ -316,13 +316,8 @@ pub fn enums() { let which_out: UInt<2> = m.output(); #[hdl] let data_out: UInt<4> = m.output(); - let b_out_ty = HdlOption[(UInt[1], Bool)]; #[hdl] - let b_out: HdlOption<(UInt, Bool)> = m.output(HdlOption[(UInt[1], Bool)]); - #[hdl] - let b2_out: HdlOption<(UInt<1>, Bool)> = m.output(); - - connect_any(b2_out, b_out); + let b_out: HdlOption<(UInt<1>, Bool)> = m.output(); #[hdl] struct MyStruct { @@ -362,7 +357,7 @@ pub fn enums() { } } - connect(b_out, b_out_ty.HdlNone()); + connect(b_out, HdlNone()); #[hdl] match the_reg { @@ -373,7 +368,7 @@ pub fn enums() { MyEnum::B(v) => { connect(which_out, 1_hdl_u2); connect_any(data_out, v.0 | (v.1.cast_to_static::>() << 1)); - connect_any(b_out, HdlSome(v)); + connect(b_out, HdlSome(v)); } MyEnum::C(v) => { connect(which_out, 2_hdl_u2); @@ -389,136 +384,132 @@ fn test_enums() { let mut sim = Simulation::new(enums()); let mut writer = RcWriter::default(); sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); - sim.write(sim.io().cd.clk, false); - sim.write(sim.io().cd.rst, true); - sim.write(sim.io().en, false); - sim.write(sim.io().which_in, 0_hdl_u2); - sim.write(sim.io().data_in, 0_hdl_u4); + sim.write_clock(sim.io().cd.clk, false); + sim.write_reset(sim.io().cd.rst, true); + sim.write_bool(sim.io().en, false); + sim.write_bool_or_int(sim.io().which_in, 0_hdl_u2); + sim.write_bool_or_int(sim.io().data_in, 0_hdl_u4); sim.advance_time(SimDuration::from_micros(1)); - sim.write(sim.io().cd.clk, true); + sim.write_clock(sim.io().cd.clk, true); sim.advance_time(SimDuration::from_nanos(100)); - sim.write(sim.io().cd.rst, false); + sim.write_reset(sim.io().cd.rst, false); sim.advance_time(SimDuration::from_nanos(900)); - #[hdl(cmp_eq)] - struct IO { - en: Bool, - which_in: UInt<2>, - data_in: UInt<4>, - which_out: UInt<2>, - data_out: UInt<4>, - b_out: HdlOption<(UIntType, Bool)>, - b2_out: HdlOption<(UInt<1>, Bool)>, + type BOutTy = HdlOption<(UInt<1>, Bool)>; + #[derive(Debug)] + struct IO { + en: bool, + which_in: u8, + data_in: u8, + which_out: u8, + data_out: u8, + b_out: Expr, + } + impl PartialEq for IO { + fn eq(&self, other: &Self) -> bool { + let Self { + en, + which_in, + data_in, + which_out, + data_out, + b_out, + } = *self; + en == other.en + && which_in == other.which_in + && data_in == other.data_in + && which_out == other.which_out + && data_out == other.data_out + && b_out.to_sim_value(BOutTy::TYPE) == other.b_out.to_sim_value(BOutTy::TYPE) + } } - let io_ty = IO[1]; let io_cycles = [ - #[hdl(sim)] - IO::<_> { + IO { en: false, - which_in: 0_hdl_u2, - data_in: 0_hdl_u4, - which_out: 0_hdl_u2, - data_out: 0_hdl_u4, - b_out: #[hdl(sim)] - (io_ty.b_out).HdlNone(), - b2_out: #[hdl(sim)] - HdlNone(), + which_in: 0, + data_in: 0, + which_out: 0, + data_out: 0, + b_out: HdlNone(), }, - #[hdl(sim)] - IO::<_> { + IO { en: true, - which_in: 1_hdl_u2, - data_in: 0_hdl_u4, - which_out: 0_hdl_u2, - data_out: 0_hdl_u4, - b_out: #[hdl(sim)] - (io_ty.b_out).HdlNone(), - b2_out: #[hdl(sim)] - HdlNone(), + which_in: 1, + data_in: 0, + which_out: 0, + data_out: 0, + b_out: HdlNone(), }, - #[hdl(sim)] - IO::<_> { + IO { en: false, - which_in: 0_hdl_u2, - data_in: 0_hdl_u4, - which_out: 1_hdl_u2, - data_out: 0_hdl_u4, - b_out: #[hdl(sim)] - (io_ty.b_out).HdlSome((0u8.cast_to(UInt[1]), false)), - b2_out: #[hdl(sim)] - HdlSome((0_hdl_u1, false)), + which_in: 0, + data_in: 0, + which_out: 1, + data_out: 0, + b_out: HdlSome((0_hdl_u1, false)), }, - #[hdl(sim)] - IO::<_> { + IO { en: true, - which_in: 1_hdl_u2, - data_in: 0xF_hdl_u4, - which_out: 1_hdl_u2, - data_out: 0_hdl_u4, - b_out: #[hdl(sim)] - (io_ty.b_out).HdlSome((0u8.cast_to(UInt[1]), false)), - b2_out: #[hdl(sim)] - HdlSome((0_hdl_u1, false)), + which_in: 1, + data_in: 0xF, + which_out: 1, + data_out: 0, + b_out: HdlSome((0_hdl_u1, false)), }, - #[hdl(sim)] - IO::<_> { + IO { en: true, - which_in: 1_hdl_u2, - data_in: 0xF_hdl_u4, - which_out: 1_hdl_u2, - data_out: 0x3_hdl_u4, - b_out: #[hdl(sim)] - (io_ty.b_out).HdlSome((1u8.cast_to(UInt[1]), true)), - b2_out: #[hdl(sim)] - HdlSome((1_hdl_u1, true)), + which_in: 1, + data_in: 0xF, + which_out: 1, + data_out: 0x3, + b_out: HdlSome((1_hdl_u1, true)), }, - #[hdl(sim)] - IO::<_> { + IO { en: true, - which_in: 2_hdl_u2, - data_in: 0xF_hdl_u4, - which_out: 1_hdl_u2, - data_out: 0x3_hdl_u4, - b_out: #[hdl(sim)] - (io_ty.b_out).HdlSome((1u8.cast_to(UInt[1]), true)), - b2_out: #[hdl(sim)] - HdlSome((1_hdl_u1, true)), + which_in: 2, + data_in: 0xF, + which_out: 1, + data_out: 0x3, + b_out: HdlSome((1_hdl_u1, true)), }, - #[hdl(sim)] - IO::<_> { + IO { en: true, - which_in: 2_hdl_u2, - data_in: 0xF_hdl_u4, - which_out: 2_hdl_u2, - data_out: 0xF_hdl_u4, - b_out: #[hdl(sim)] - (io_ty.b_out).HdlNone(), - b2_out: #[hdl(sim)] - HdlNone(), + which_in: 2, + data_in: 0xF, + which_out: 2, + data_out: 0xF, + b_out: HdlNone(), }, ]; - for (cycle, expected) in io_cycles.into_iter().enumerate() { - #[hdl(sim)] - let IO::<_> { + for ( + cycle, + expected @ IO { en, which_in, data_in, which_out: _, data_out: _, b_out: _, - b2_out: _, - } = expected; - sim.write(sim.io().en, &en); - sim.write(sim.io().which_in, &which_in); - sim.write(sim.io().data_in, &data_in); - let io = #[hdl(sim)] - IO::<_> { + }, + ) in io_cycles.into_iter().enumerate() + { + sim.write_bool(sim.io().en, en); + sim.write_bool_or_int(sim.io().which_in, which_in.cast_to_static()); + sim.write_bool_or_int(sim.io().data_in, data_in.cast_to_static()); + let io = IO { en, which_in, data_in, - which_out: sim.read(sim.io().which_out), - data_out: sim.read(sim.io().data_out), - b_out: sim.read(sim.io().b_out), - b2_out: sim.read(sim.io().b2_out), + which_out: sim + .read_bool_or_int(sim.io().which_out) + .to_bigint() + .try_into() + .expect("known to be in range"), + data_out: sim + .read_bool_or_int(sim.io().data_out) + .to_bigint() + .try_into() + .expect("known to be in range"), + b_out: sim.read(sim.io().b_out).to_expr(), }; assert_eq!( expected, @@ -526,12 +517,6 @@ fn test_enums() { "vcd:\n{}\ncycle: {cycle}", String::from_utf8(writer.take()).unwrap(), ); - // make sure matching on SimValue works - #[hdl(sim)] - match io.b_out { - HdlNone => println!("io.b_out is HdlNone"), - HdlSome(v) => println!("io.b_out is HdlSome(({:?}, {:?}))", *v.0, *v.1), - } sim.write_clock(sim.io().cd.clk, false); sim.advance_time(SimDuration::from_micros(1)); sim.write_clock(sim.io().cd.clk, true); @@ -553,9 +538,9 @@ fn test_enums() { #[hdl_module(outline_generated)] pub fn memories() { #[hdl] - let r: ReadStruct<(UInt<8>, SInt<8>), ConstUsize<4>> = m.input(); + let r: fayalite::memory::ReadStruct<(UInt<8>, SInt<8>), ConstUsize<4>> = m.input(); #[hdl] - let w: WriteStruct<(UInt<8>, SInt<8>), ConstUsize<4>> = m.input(); + let w: fayalite::memory::WriteStruct<(UInt<8>, SInt<8>), ConstUsize<4>> = m.input(); #[hdl] let mut mem = memory_with_init([(0x01u8, 0x23i8); 16]); mem.read_latency(0); @@ -574,131 +559,120 @@ fn test_memories() { sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); sim.write_clock(sim.io().r.clk, false); sim.write_clock(sim.io().w.clk, false); - #[hdl(cmp_eq)] + #[derive(Debug, PartialEq, Eq)] struct IO { - r_addr: UInt<4>, - r_en: Bool, - r_data: (UInt<8>, SInt<8>), - w_addr: UInt<4>, - w_en: Bool, - w_data: (UInt<8>, SInt<8>), - w_mask: (Bool, Bool), + r_addr: u8, + r_en: bool, + r_data: (u8, i8), + w_addr: u8, + w_en: bool, + w_data: (u8, i8), + w_mask: (bool, bool), } let io_cycles = [ - #[hdl(sim)] IO { - r_addr: 0_hdl_u4, + r_addr: 0, r_en: false, - r_data: (0u8, 0i8), - w_addr: 0_hdl_u4, + r_data: (0, 0), + w_addr: 0, w_en: false, - w_data: (0u8, 0i8), + w_data: (0, 0), w_mask: (false, false), }, - #[hdl(sim)] IO { - r_addr: 0_hdl_u4, + r_addr: 0, r_en: true, - r_data: (0x1u8, 0x23i8), - w_addr: 0_hdl_u4, + r_data: (0x1, 0x23), + w_addr: 0, w_en: true, - w_data: (0x10u8, 0x20i8), + w_data: (0x10, 0x20), w_mask: (true, true), }, - #[hdl(sim)] IO { - r_addr: 0_hdl_u4, + r_addr: 0, r_en: true, - r_data: (0x10u8, 0x20i8), - w_addr: 0_hdl_u4, + r_data: (0x10, 0x20), + w_addr: 0, w_en: true, - w_data: (0x30u8, 0x40i8), + w_data: (0x30, 0x40), w_mask: (false, true), }, - #[hdl(sim)] IO { - r_addr: 0_hdl_u4, + r_addr: 0, r_en: true, - r_data: (0x10u8, 0x40i8), - w_addr: 0_hdl_u4, + r_data: (0x10, 0x40), + w_addr: 0, w_en: true, - w_data: (0x50u8, 0x60i8), + w_data: (0x50, 0x60), w_mask: (true, false), }, - #[hdl(sim)] IO { - r_addr: 0_hdl_u4, + r_addr: 0, r_en: true, - r_data: (0x50u8, 0x40i8), - w_addr: 0_hdl_u4, + r_data: (0x50, 0x40), + w_addr: 0, w_en: true, - w_data: (0x70u8, -0x80i8), + w_data: (0x70, -0x80), w_mask: (false, false), }, - #[hdl(sim)] IO { - r_addr: 0_hdl_u4, + r_addr: 0, r_en: true, - r_data: (0x50u8, 0x40i8), - w_addr: 0_hdl_u4, + r_data: (0x50, 0x40), + w_addr: 0, w_en: false, - w_data: (0x90u8, 0xA0u8 as i8), + w_data: (0x90, 0xA0u8 as i8), w_mask: (false, false), }, - #[hdl(sim)] IO { - r_addr: 0_hdl_u4, + r_addr: 0, r_en: true, - r_data: (0x50u8, 0x40i8), - w_addr: 1_hdl_u4, + r_data: (0x50, 0x40), + w_addr: 1, w_en: true, - w_data: (0x90u8, 0xA0u8 as i8), + w_data: (0x90, 0xA0u8 as i8), w_mask: (true, true), }, - #[hdl(sim)] IO { - r_addr: 0_hdl_u4, + r_addr: 0, r_en: true, - r_data: (0x50u8, 0x40i8), - w_addr: 2_hdl_u4, + r_data: (0x50, 0x40), + w_addr: 2, w_en: true, - w_data: (0xB0u8, 0xC0u8 as i8), + w_data: (0xB0, 0xC0u8 as i8), w_mask: (true, true), }, - #[hdl(sim)] IO { - r_addr: 0_hdl_u4, + r_addr: 0, r_en: true, - r_data: (0x50u8, 0x40i8), - w_addr: 2_hdl_u4, + r_data: (0x50, 0x40), + w_addr: 2, w_en: false, - w_data: (0xD0u8, 0xE0u8 as i8), + w_data: (0xD0, 0xE0u8 as i8), w_mask: (true, true), }, - #[hdl(sim)] IO { - r_addr: 1_hdl_u4, + r_addr: 1, r_en: true, - r_data: (0x90u8, 0xA0u8 as i8), - w_addr: 2_hdl_u4, + r_data: (0x90, 0xA0u8 as i8), + w_addr: 2, w_en: false, - w_data: (0xD0u8, 0xE0u8 as i8), + w_data: (0xD0, 0xE0u8 as i8), w_mask: (true, true), }, - #[hdl(sim)] IO { - r_addr: 2_hdl_u4, + r_addr: 2, r_en: true, - r_data: (0xB0u8, 0xC0u8 as i8), - w_addr: 2_hdl_u4, + r_data: (0xB0, 0xC0u8 as i8), + w_addr: 2, w_en: false, - w_data: (0xD0u8, 0xE0u8 as i8), + w_data: (0xD0, 0xE0u8 as i8), w_mask: (true, true), }, ]; - for (cycle, expected) in io_cycles.into_iter().enumerate() { - #[hdl(sim)] - let IO { + for ( + cycle, + expected @ IO { r_addr, r_en, r_data: _, @@ -706,18 +680,30 @@ fn test_memories() { w_en, w_data, w_mask, - } = expected; - sim.write(sim.io().r.addr, &r_addr); - sim.write(sim.io().r.en, &r_en); - sim.write(sim.io().w.addr, &w_addr); - sim.write(sim.io().w.en, &w_en); - sim.write(sim.io().w.data, &w_data); - sim.write(sim.io().w.mask, &w_mask); - let io = #[hdl(sim)] - IO { + }, + ) in io_cycles.into_iter().enumerate() + { + sim.write_bool_or_int(sim.io().r.addr, r_addr.cast_to_static()); + sim.write_bool(sim.io().r.en, r_en); + sim.write_bool_or_int(sim.io().w.addr, w_addr.cast_to_static()); + sim.write_bool(sim.io().w.en, w_en); + sim.write_bool_or_int(sim.io().w.data.0, w_data.0); + sim.write_bool_or_int(sim.io().w.data.1, w_data.1); + sim.write_bool(sim.io().w.mask.0, w_mask.0); + sim.write_bool(sim.io().w.mask.1, w_mask.1); + let io = IO { r_addr, r_en, - r_data: sim.read(sim.io().r.data), + r_data: ( + sim.read_bool_or_int(sim.io().r.data.0) + .to_bigint() + .try_into() + .expect("known to be in range"), + sim.read_bool_or_int(sim.io().r.data.1) + .to_bigint() + .try_into() + .expect("known to be in range"), + ), w_addr, w_en, w_data, @@ -730,11 +716,11 @@ fn test_memories() { String::from_utf8(writer.take()).unwrap(), ); sim.advance_time(SimDuration::from_micros(1)); - sim.write(sim.io().r.clk, true); - sim.write(sim.io().w.clk, true); + sim.write_clock(sim.io().r.clk, true); + sim.write_clock(sim.io().w.clk, true); sim.advance_time(SimDuration::from_micros(1)); - sim.write(sim.io().r.clk, false); - sim.write(sim.io().w.clk, false); + sim.write_clock(sim.io().r.clk, false); + sim.write_clock(sim.io().w.clk, false); } sim.flush_traces().unwrap(); let vcd = String::from_utf8(writer.take()).unwrap(); @@ -752,7 +738,7 @@ fn test_memories() { #[hdl_module(outline_generated)] pub fn memories2() { #[hdl] - let rw: ReadWriteStruct, ConstUsize<3>> = m.input(); + let rw: fayalite::memory::ReadWriteStruct, ConstUsize<3>> = m.input(); #[hdl] let mut mem = memory_with_init([HdlSome(true); 5]); mem.read_latency(1); @@ -1025,9 +1011,9 @@ fn test_memories2() { #[hdl_module(outline_generated)] pub fn memories3() { #[hdl] - let r: ReadStruct, 8>, ConstUsize<3>> = m.input(); + let r: fayalite::memory::ReadStruct, 8>, ConstUsize<3>> = m.input(); #[hdl] - let w: WriteStruct, 8>, ConstUsize<3>> = m.input(); + let w: fayalite::memory::WriteStruct, 8>, ConstUsize<3>> = m.input(); #[hdl] let mut mem: MemBuilder, 8>> = memory(); mem.depth(8); @@ -1260,769 +1246,3 @@ fn test_memories3() { panic!(); } } - -#[hdl_module(outline_generated)] -pub fn many_memories() { - #[hdl] - let r: Array>, 8> = m.input(); - #[hdl] - let w: Array>, 8> = m.input(); - for (mem_index, (r, w)) in r.into_iter().zip(w).enumerate() { - let mut mem = memory_with_init_and_loc( - &format!("mem_{mem_index}"), - (0..16) - .map(|bit_index| mem_index.pow(5).to_expr()[bit_index]) - .collect::>(), - SourceLocation::caller(), - ); - connect_any(mem.new_read_port(), r); - connect_any(mem.new_write_port(), w); - } -} - -#[hdl] -#[test] -fn test_many_memories() { - let _n = SourceLocation::normalize_files_for_tests(); - let mut sim = Simulation::new(many_memories()); - let mut writer = RcWriter::default(); - sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); - for r in sim.io().r { - sim.write_clock(r.clk, false); - } - for w in sim.io().w { - sim.write_clock(w.clk, false); - } - #[hdl(cmp_eq)] - struct IO { - r_addr: UInt<4>, - r_en: Bool, - r_data: Array, - w_addr: UInt<4>, - w_en: Bool, - w_data: Array, - w_mask: Array, - } - let io_cycles = [ - #[hdl(sim)] - IO { - r_addr: 0_hdl_u4, - r_en: false, - r_data: [false; 8], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [false; 8], - }, - #[hdl(sim)] - IO { - r_addr: 0_hdl_u4, - r_en: true, - r_data: [false, true, false, true, false, true, false, true], - w_addr: 0_hdl_u4, - w_en: true, - w_data: [true; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 0_hdl_u4, - r_en: true, - r_data: [true; 8], - w_addr: 0_hdl_u4, - w_en: true, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 0_hdl_u4, - r_en: true, - r_data: [false; 8], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 1_hdl_u4, - r_en: true, - r_data: [false, false, false, true, false, false, false, true], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 2_hdl_u4, - r_en: true, - r_data: [false, false, false, false, false, true, false, true], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 3_hdl_u4, - r_en: true, - r_data: [false, false, false, false, false, false, false, false], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 4_hdl_u4, - r_en: true, - r_data: [false, false, false, true, false, true, false, false], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 5_hdl_u4, - r_en: true, - r_data: [false, false, true, true, false, true, true, true], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 6_hdl_u4, - r_en: true, - r_data: [false, false, false, true, false, false, true, false], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 7_hdl_u4, - r_en: true, - r_data: [false, false, false, true, false, false, false, true], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 8_hdl_u4, - r_en: true, - r_data: [false, false, false, false, false, false, false, true], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 9_hdl_u4, - r_en: true, - r_data: [false, false, false, false, false, false, true, false], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 0xA_hdl_u4, - r_en: true, - r_data: [false, false, false, false, true, true, true, false], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 0xB_hdl_u4, - r_en: true, - r_data: [false, false, false, false, false, true, true, false], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 0xC_hdl_u4, - r_en: true, - r_data: [false, false, false, false, false, false, true, false], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 0xD_hdl_u4, - r_en: true, - r_data: [false, false, false, false, false, false, false, false], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 0xE_hdl_u4, - r_en: true, - r_data: [false, false, false, false, false, false, false, true], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - #[hdl(sim)] - IO { - r_addr: 0xF_hdl_u4, - r_en: true, - r_data: [false, false, false, false, false, false, false, false], - w_addr: 0_hdl_u4, - w_en: false, - w_data: [false; 8], - w_mask: [true; 8], - }, - ]; - for (cycle, expected) in io_cycles.into_iter().enumerate() { - #[hdl(sim)] - let IO { - r_addr, - r_en, - r_data: _, - w_addr, - w_en, - w_data, - w_mask, - } = expected; - for (((r, w), w_data), w_mask) in sim - .io() - .r - .into_iter() - .zip(sim.io().w) - .zip(w_data.iter()) - .zip(w_mask.iter()) - { - sim.write(r.addr, &r_addr); - sim.write(r.en, &r_en); - sim.write(w.addr, &w_addr); - sim.write(w.en, &w_en); - sim.write(w.data, w_data); - sim.write(w.mask, w_mask); - } - let io = #[hdl(sim)] - IO { - r_addr, - r_en, - r_data: std::array::from_fn(|i| sim.read(sim.io().r[i].data)), - w_addr, - w_en, - w_data, - w_mask, - }; - assert_eq!( - expected, - io, - "vcd:\n{}\ncycle: {cycle}", - String::from_utf8(writer.take()).unwrap(), - ); - sim.advance_time(SimDuration::from_micros(1)); - for r in sim.io().r { - sim.write_clock(r.clk, true); - } - for w in sim.io().w { - sim.write_clock(w.clk, true); - } - sim.advance_time(SimDuration::from_micros(1)); - for r in sim.io().r { - sim.write_clock(r.clk, false); - } - for w in sim.io().w { - sim.write_clock(w.clk, false); - } - } - sim.flush_traces().unwrap(); - let vcd = String::from_utf8(writer.take()).unwrap(); - println!("####### VCD:\n{vcd}\n#######"); - if vcd != include_str!("sim/expected/many_memories.vcd") { - panic!(); - } - let sim_debug = format!("{sim:#?}"); - println!("#######\n{sim_debug}\n#######"); - if sim_debug != include_str!("sim/expected/many_memories.txt") { - panic!(); - } -} - -#[hdl_module(outline_generated)] -pub fn duplicate_names() { - #[hdl] - let w = wire(); - connect(w, 5u8); - #[hdl] - let w = wire(); - connect(w, 6u8); -} - -#[test] -fn test_duplicate_names() { - let _n = SourceLocation::normalize_files_for_tests(); - let mut sim = Simulation::new(duplicate_names()); - let mut writer = RcWriter::default(); - sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); - sim.advance_time(SimDuration::from_micros(1)); - sim.flush_traces().unwrap(); - let vcd = String::from_utf8(writer.take()).unwrap(); - println!("####### VCD:\n{vcd}\n#######"); - if vcd != include_str!("sim/expected/duplicate_names.vcd") { - panic!(); - } - let sim_debug = format!("{sim:#?}"); - println!("#######\n{sim_debug}\n#######"); - if sim_debug != include_str!("sim/expected/duplicate_names.txt") { - panic!(); - } -} - -#[hdl_module(outline_generated)] -pub fn array_rw() { - #[hdl] - let array_in: Array, 16> = m.input(); - #[hdl] - let array_out: Array, 16> = m.output(); - #[hdl] - let read_index: UInt<8> = m.input(); - #[hdl] - let read_data: UInt<8> = m.output(); - #[hdl] - let write_index: UInt<8> = m.input(); - #[hdl] - let write_data: UInt<8> = m.input(); - #[hdl] - let write_en: Bool = m.input(); - #[hdl] - let array_wire = wire(); - connect(array_wire, array_in); - connect(array_out, array_wire); - #[hdl] - if write_en { - connect(array_wire[write_index], write_data); - } - connect(read_data, array_wire[read_index]); -} - -#[test] -fn test_array_rw() { - let _n = SourceLocation::normalize_files_for_tests(); - let mut sim = Simulation::new(array_rw()); - let mut writer = RcWriter::default(); - sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); - #[derive(Debug, PartialEq)] - struct State { - array_in: [u8; 16], - array_out: [u8; 16], - read_index: u8, - read_data: u8, - write_index: u8, - write_data: u8, - write_en: bool, - } - let mut states = Vec::new(); - let array_in = [ - 0xFFu8, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, // - 0x00u8, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, - ]; - for i in 0..=16 { - states.push(State { - array_in, - array_out: array_in, - read_index: i, - read_data: array_in.get(i as usize).copied().unwrap_or(0), - write_index: 0, - write_data: 0, - write_en: false, - }); - } - for i in 0..=16u8 { - let mut array_out = array_in; - let write_data = i.wrapping_mul(i); - if let Some(v) = array_out.get_mut(i as usize) { - *v = write_data; - } - states.push(State { - array_in, - array_out, - read_index: 0, - read_data: array_out[0], - write_index: i, - write_data, - write_en: true, - }); - } - for (cycle, expected) in states.into_iter().enumerate() { - let State { - array_in, - array_out: _, - read_index, - read_data: _, - write_index, - write_data, - write_en, - } = expected; - sim.write(sim.io().array_in, array_in); - sim.write(sim.io().read_index, read_index); - sim.write(sim.io().write_index, write_index); - sim.write(sim.io().write_data, write_data); - sim.write(sim.io().write_en, write_en); - sim.advance_time(SimDuration::from_micros(1)); - let array_out = std::array::from_fn(|index| { - sim.read_bool_or_int(sim.io().array_out[index]) - .to_bigint() - .try_into() - .expect("known to be in range") - }); - let read_data = sim - .read_bool_or_int(sim.io().read_data) - .to_bigint() - .try_into() - .expect("known to be in range"); - let state = State { - array_in, - array_out, - read_index, - read_data, - write_index, - write_data, - write_en, - }; - assert_eq!( - state, - expected, - "vcd:\n{}\ncycle: {cycle}", - String::from_utf8(writer.take()).unwrap(), - ); - } - sim.flush_traces().unwrap(); - let vcd = String::from_utf8(writer.take()).unwrap(); - println!("####### VCD:\n{vcd}\n#######"); - if vcd != include_str!("sim/expected/array_rw.vcd") { - panic!(); - } - let sim_debug = format!("{sim:#?}"); - println!("#######\n{sim_debug}\n#######"); - if sim_debug != include_str!("sim/expected/array_rw.txt") { - panic!(); - } -} - -#[hdl_module(outline_generated)] -pub fn conditional_assignment_last() { - #[hdl] - let i: Bool = m.input(); - #[hdl] - let w = wire(); - connect(w, true); - #[hdl] - if i { - connect(w, false); - } -} - -#[test] -fn test_conditional_assignment_last() { - let _n = SourceLocation::normalize_files_for_tests(); - let mut sim = Simulation::new(conditional_assignment_last()); - let mut writer = RcWriter::default(); - sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); - sim.write(sim.io().i, false); - sim.advance_time(SimDuration::from_micros(1)); - sim.write(sim.io().i, true); - sim.advance_time(SimDuration::from_micros(1)); - sim.flush_traces().unwrap(); - let vcd = String::from_utf8(writer.take()).unwrap(); - println!("####### VCD:\n{vcd}\n#######"); - if vcd != include_str!("sim/expected/conditional_assignment_last.vcd") { - panic!(); - } - let sim_debug = format!("{sim:#?}"); - println!("#######\n{sim_debug}\n#######"); - if sim_debug != include_str!("sim/expected/conditional_assignment_last.txt") { - panic!(); - } -} - -#[hdl_module(outline_generated, extern)] -pub fn extern_module() { - #[hdl] - let i: Bool = m.input(); - #[hdl] - let o: Bool = m.output(); - m.extern_module_simulation_fn((i, o), |(i, o), mut sim| async move { - sim.write(o, true).await; - sim.advance_time(SimDuration::from_nanos(500)).await; - let mut invert = false; - loop { - sim.advance_time(SimDuration::from_micros(1)).await; - let v = sim.read_bool(i).await; - sim.write(o, v ^ invert).await; - invert = !invert; - } - }); -} - -#[test] -fn test_extern_module() { - let _n = SourceLocation::normalize_files_for_tests(); - let mut sim = Simulation::new(extern_module()); - let mut writer = RcWriter::default(); - sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); - sim.write(sim.io().i, false); - sim.advance_time(SimDuration::from_micros(10)); - sim.write(sim.io().i, true); - sim.advance_time(SimDuration::from_micros(10)); - sim.flush_traces().unwrap(); - let vcd = String::from_utf8(writer.take()).unwrap(); - println!("####### VCD:\n{vcd}\n#######"); - if vcd != include_str!("sim/expected/extern_module.vcd") { - panic!(); - } - let sim_debug = format!("{sim:#?}"); - println!("#######\n{sim_debug}\n#######"); - if sim_debug != include_str!("sim/expected/extern_module.txt") { - panic!(); - } -} - -#[hdl_module(outline_generated, extern)] -pub fn extern_module2() { - #[hdl] - let en: Bool = m.input(); - #[hdl] - let clk: Clock = m.input(); - #[hdl] - let o: UInt<8> = m.output(); - m.extern_module_simulation_fn((en, clk, o), |(en, clk, o), mut sim| async move { - for b in "Hello, World!\n".bytes().cycle() { - sim.write(o, b).await; - loop { - sim.wait_for_clock_edge(clk).await; - if sim.read_bool(en).await { - break; - } - } - } - }); -} - -#[test] -fn test_extern_module2() { - let _n = SourceLocation::normalize_files_for_tests(); - let mut sim = Simulation::new(extern_module2()); - let mut writer = RcWriter::default(); - sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); - for i in 0..30 { - sim.write(sim.io().en, i % 10 < 5); - sim.write(sim.io().clk, false); - sim.advance_time(SimDuration::from_micros(1)); - sim.write(sim.io().clk, true); - sim.advance_time(SimDuration::from_micros(1)); - } - sim.flush_traces().unwrap(); - let vcd = String::from_utf8(writer.take()).unwrap(); - println!("####### VCD:\n{vcd}\n#######"); - if vcd != include_str!("sim/expected/extern_module2.vcd") { - panic!(); - } - let sim_debug = format!("{sim:#?}"); - println!("#######\n{sim_debug}\n#######"); - if sim_debug != include_str!("sim/expected/extern_module2.txt") { - panic!(); - } -} - -// use an extern module to simulate a register to test that the -// simulator can handle chains of alternating circuits and extern modules. -#[hdl_module(outline_generated, extern)] -pub fn sw_reg() { - #[hdl] - let clk: Clock = m.input(); - #[hdl] - let o: Bool = m.output(); - m.extern_module_simulation_fn((clk, o), |(clk, o), mut sim| async move { - let mut state = false; - loop { - sim.write(o, state).await; - sim.wait_for_clock_edge(clk).await; - state = !state; - } - }); -} - -#[hdl_module(outline_generated)] -pub fn ripple_counter() { - #[hdl] - let clk: Clock = m.input(); - #[hdl] - let o: UInt<6> = m.output(); - - #[hdl] - let bits: Array = wire(); - - connect_any(o, bits.cast_to_bits()); - - let mut clk_in = clk; - for (i, bit) in bits.into_iter().enumerate() { - if i % 2 == 0 { - let bit_reg = reg_builder_with_loc(&format!("bit_reg_{i}"), SourceLocation::caller()) - .clock_domain( - #[hdl] - ClockDomain { - clk: clk_in, - rst: false.to_sync_reset(), - }, - ) - .no_reset(Bool) - .build(); - connect(bit, bit_reg); - connect(bit_reg, !bit_reg); - } else { - let bit_reg = - instance_with_loc(&format!("bit_reg_{i}"), sw_reg(), SourceLocation::caller()); - connect(bit_reg.clk, clk_in); - connect(bit, bit_reg.o); - } - clk_in = bit.to_clock(); - } -} - -#[test] -fn test_ripple_counter() { - let _n = SourceLocation::normalize_files_for_tests(); - let mut sim = Simulation::new(ripple_counter()); - let mut writer = RcWriter::default(); - sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); - for _ in 0..0x80 { - sim.write(sim.io().clk, false); - sim.advance_time(SimDuration::from_micros(1)); - sim.write(sim.io().clk, true); - sim.advance_time(SimDuration::from_micros(1)); - } - sim.flush_traces().unwrap(); - let vcd = String::from_utf8(writer.take()).unwrap(); - println!("####### VCD:\n{vcd}\n#######"); - if vcd != include_str!("sim/expected/ripple_counter.vcd") { - panic!(); - } - let sim_debug = format!("{sim:#?}"); - println!("#######\n{sim_debug}\n#######"); - if sim_debug != include_str!("sim/expected/ripple_counter.txt") { - panic!(); - } -} - -/// use `Rc` to ensure you can use `!Send + !Sync` types -type SimOnlyTestMap = BTreeMap>; - -#[hdl_module(outline_generated, extern)] -fn sim_only_connects_helper() { - #[hdl] - let cd: ClockDomain = m.input(); - #[hdl] - let inp: SimOnly = m.input(); - #[hdl] - let out: SimOnly = m.output(); - m.extern_module_simulation_fn((cd, inp, out), |(cd, inp, out), mut sim| async move { - sim.write(out, SimOnlyValue::default()).await; - loop { - sim.wait_for_clock_edge(cd.clk).await; - let mut map = sim.read(inp).await; - let foo = map.get("foo").cloned().unwrap_or_default(); - map.insert(String::from("bar"), foo); - map.insert(String::from("foo"), Rc::from("baz")); - sim.write(out, map).await; - } - }); -} - -#[hdl_module(outline_generated)] -pub fn sim_only_connects() { - #[hdl] - let cd: ClockDomain = m.input(); - #[hdl] - let inp: SimOnly = m.input(); - #[hdl] - let out1: SimOnly = m.output(); - #[hdl] - let out2: SimOnly = m.output(); - #[hdl] - let out3: SimOnly = m.output(); - #[hdl] - let helper1 = instance(sim_only_connects_helper()); - #[hdl] - let delay1: SimOnly = reg_builder() - .clock_domain(cd) - .reset(SimOnly::::new().uninit()); - #[hdl] - let delay1_empty: Bool = reg_builder().clock_domain(cd).reset(true); - connect(helper1.cd, cd); - connect(helper1.inp, delay1); - connect(out1, delay1); - #[hdl] - if delay1_empty { - connect(helper1.inp, inp); - connect(out1, inp); - } - connect(delay1, inp); - connect(delay1_empty, false); - connect(out2, helper1.out); - #[hdl] - let helper2 = instance(sim_only_connects_helper()); - connect(helper2.cd, cd); - connect(helper2.inp, out2); - connect(out3, helper2.out); -} - -#[test] -fn test_sim_only_connects() { - let _n = SourceLocation::normalize_files_for_tests(); - let mut sim = Simulation::new(sim_only_connects()); - let mut writer = RcWriter::default(); - sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); - sim.write(sim.io().cd.rst, true); - sim.write( - sim.io().inp, - SimOnlyValue::new(BTreeMap::from_iter([( - String::from("extra"), - Rc::from("value"), - )])), - ); - for _ in 0..8 { - sim.write(sim.io().cd.clk, false); - sim.advance_time(SimDuration::from_micros(1)); - sim.write(sim.io().cd.clk, true); - sim.advance_time(SimDuration::from_micros(1)); - sim.write(sim.io().cd.rst, false); - } - sim.flush_traces().unwrap(); - let vcd = String::from_utf8(writer.take()).unwrap(); - println!("####### VCD:\n{vcd}\n#######"); - if vcd != include_str!("sim/expected/sim_only_connects.vcd") { - panic!(); - } - let sim_debug = format!("{sim:#?}"); - println!("#######\n{sim_debug}\n#######"); - if sim_debug != include_str!("sim/expected/sim_only_connects.txt") { - panic!(); - } -} diff --git a/crates/fayalite/tests/sim/expected/array_rw.txt b/crates/fayalite/tests/sim/expected/array_rw.txt deleted file mode 100644 index 12e86f3..0000000 --- a/crates/fayalite/tests/sim/expected/array_rw.txt +++ /dev/null @@ -1,1705 +0,0 @@ -Simulation { - state: State { - insns: Insns { - state_layout: StateLayout { - ty: TypeLayout { - small_slots: StatePartLayout { - len: 2, - debug_data: [ - SlotDebugData { - name: "", - ty: UInt<8>, - }, - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - big_slots: StatePartLayout { - len: 54, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[0]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[1]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[2]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[3]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[4]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[5]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[6]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[7]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[8]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[9]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[10]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[11]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[12]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[13]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[14]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[15]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[0]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[1]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[2]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[3]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[4]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[5]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[6]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[7]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[8]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[9]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[10]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[11]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[12]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[13]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[14]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[15]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::read_index", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::read_data", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::write_index", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::write_data", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::write_en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[0]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[1]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[2]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[3]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[4]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[5]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[6]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[7]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[8]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[9]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[10]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[11]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[12]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[13]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[14]", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[15]", - ty: UInt<8>, - }, - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - memories: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - insns: [ - // at: module-XXXXXXXXXX.rs:1:1 - 0: CastBigToArrayIndex { - dest: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: UInt<8> }, - src: StatePartIndex(32), // (0x0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::read_index", ty: UInt<8> }, - }, - 1: CastBigToArrayIndex { - dest: StatePartIndex(0), // (0x10 16) SlotDebugData { name: "", ty: UInt<8> }, - src: StatePartIndex(34), // (0x10) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::write_index", ty: UInt<8> }, - }, - // at: module-XXXXXXXXXX.rs:10:1 - 2: Copy { - dest: StatePartIndex(37), // (0xff) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[0]", ty: UInt<8> }, - src: StatePartIndex(0), // (0xff) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[0]", ty: UInt<8> }, - }, - 3: Copy { - dest: StatePartIndex(38), // (0x7f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[1]", ty: UInt<8> }, - src: StatePartIndex(1), // (0x7f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[1]", ty: UInt<8> }, - }, - 4: Copy { - dest: StatePartIndex(39), // (0x3f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[2]", ty: UInt<8> }, - src: StatePartIndex(2), // (0x3f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[2]", ty: UInt<8> }, - }, - 5: Copy { - dest: StatePartIndex(40), // (0x1f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[3]", ty: UInt<8> }, - src: StatePartIndex(3), // (0x1f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[3]", ty: UInt<8> }, - }, - 6: Copy { - dest: StatePartIndex(41), // (0xf) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[4]", ty: UInt<8> }, - src: StatePartIndex(4), // (0xf) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[4]", ty: UInt<8> }, - }, - 7: Copy { - dest: StatePartIndex(42), // (0x7) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[5]", ty: UInt<8> }, - src: StatePartIndex(5), // (0x7) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[5]", ty: UInt<8> }, - }, - 8: Copy { - dest: StatePartIndex(43), // (0x3) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[6]", ty: UInt<8> }, - src: StatePartIndex(6), // (0x3) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[6]", ty: UInt<8> }, - }, - 9: Copy { - dest: StatePartIndex(44), // (0x1) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[7]", ty: UInt<8> }, - src: StatePartIndex(7), // (0x1) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[7]", ty: UInt<8> }, - }, - 10: Copy { - dest: StatePartIndex(45), // (0x0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[8]", ty: UInt<8> }, - src: StatePartIndex(8), // (0x0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[8]", ty: UInt<8> }, - }, - 11: Copy { - dest: StatePartIndex(46), // (0x80) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[9]", ty: UInt<8> }, - src: StatePartIndex(9), // (0x80) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[9]", ty: UInt<8> }, - }, - 12: Copy { - dest: StatePartIndex(47), // (0xc0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[10]", ty: UInt<8> }, - src: StatePartIndex(10), // (0xc0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[10]", ty: UInt<8> }, - }, - 13: Copy { - dest: StatePartIndex(48), // (0xe0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[11]", ty: UInt<8> }, - src: StatePartIndex(11), // (0xe0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[11]", ty: UInt<8> }, - }, - 14: Copy { - dest: StatePartIndex(49), // (0xf0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[12]", ty: UInt<8> }, - src: StatePartIndex(12), // (0xf0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[12]", ty: UInt<8> }, - }, - 15: Copy { - dest: StatePartIndex(50), // (0xf8) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[13]", ty: UInt<8> }, - src: StatePartIndex(13), // (0xf8) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[13]", ty: UInt<8> }, - }, - 16: Copy { - dest: StatePartIndex(51), // (0xfc) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[14]", ty: UInt<8> }, - src: StatePartIndex(14), // (0xfc) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[14]", ty: UInt<8> }, - }, - 17: Copy { - dest: StatePartIndex(52), // (0xfe) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[15]", ty: UInt<8> }, - src: StatePartIndex(15), // (0xfe) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_in[15]", ty: UInt<8> }, - }, - // at: module-XXXXXXXXXX.rs:12:1 - 18: BranchIfZero { - target: 20, - value: StatePartIndex(36), // (0x1) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::write_en", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:13:1 - 19: WriteIndexed { - dest: StatePartIndex(37) /* (0xff) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[0]", ty: UInt<8> } */ [StatePartIndex(0) /* (0x10 16) SlotDebugData { name: "", ty: UInt<8> } */ , len=16, stride=1],, - src: StatePartIndex(35), // (0x0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::write_data", ty: UInt<8> }, - }, - // at: module-XXXXXXXXXX.rs:11:1 - 20: Copy { - dest: StatePartIndex(16), // (0xff) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[0]", ty: UInt<8> }, - src: StatePartIndex(37), // (0xff) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[0]", ty: UInt<8> }, - }, - 21: Copy { - dest: StatePartIndex(17), // (0x7f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[1]", ty: UInt<8> }, - src: StatePartIndex(38), // (0x7f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[1]", ty: UInt<8> }, - }, - 22: Copy { - dest: StatePartIndex(18), // (0x3f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[2]", ty: UInt<8> }, - src: StatePartIndex(39), // (0x3f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[2]", ty: UInt<8> }, - }, - 23: Copy { - dest: StatePartIndex(19), // (0x1f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[3]", ty: UInt<8> }, - src: StatePartIndex(40), // (0x1f) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[3]", ty: UInt<8> }, - }, - 24: Copy { - dest: StatePartIndex(20), // (0xf) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[4]", ty: UInt<8> }, - src: StatePartIndex(41), // (0xf) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[4]", ty: UInt<8> }, - }, - 25: Copy { - dest: StatePartIndex(21), // (0x7) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[5]", ty: UInt<8> }, - src: StatePartIndex(42), // (0x7) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[5]", ty: UInt<8> }, - }, - 26: Copy { - dest: StatePartIndex(22), // (0x3) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[6]", ty: UInt<8> }, - src: StatePartIndex(43), // (0x3) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[6]", ty: UInt<8> }, - }, - 27: Copy { - dest: StatePartIndex(23), // (0x1) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[7]", ty: UInt<8> }, - src: StatePartIndex(44), // (0x1) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[7]", ty: UInt<8> }, - }, - 28: Copy { - dest: StatePartIndex(24), // (0x0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[8]", ty: UInt<8> }, - src: StatePartIndex(45), // (0x0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[8]", ty: UInt<8> }, - }, - 29: Copy { - dest: StatePartIndex(25), // (0x80) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[9]", ty: UInt<8> }, - src: StatePartIndex(46), // (0x80) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[9]", ty: UInt<8> }, - }, - 30: Copy { - dest: StatePartIndex(26), // (0xc0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[10]", ty: UInt<8> }, - src: StatePartIndex(47), // (0xc0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[10]", ty: UInt<8> }, - }, - 31: Copy { - dest: StatePartIndex(27), // (0xe0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[11]", ty: UInt<8> }, - src: StatePartIndex(48), // (0xe0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[11]", ty: UInt<8> }, - }, - 32: Copy { - dest: StatePartIndex(28), // (0xf0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[12]", ty: UInt<8> }, - src: StatePartIndex(49), // (0xf0) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[12]", ty: UInt<8> }, - }, - 33: Copy { - dest: StatePartIndex(29), // (0xf8) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[13]", ty: UInt<8> }, - src: StatePartIndex(50), // (0xf8) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[13]", ty: UInt<8> }, - }, - 34: Copy { - dest: StatePartIndex(30), // (0xfc) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[14]", ty: UInt<8> }, - src: StatePartIndex(51), // (0xfc) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[14]", ty: UInt<8> }, - }, - 35: Copy { - dest: StatePartIndex(31), // (0xfe) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_out[15]", ty: UInt<8> }, - src: StatePartIndex(52), // (0xfe) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[15]", ty: UInt<8> }, - }, - // at: module-XXXXXXXXXX.rs:14:1 - 36: ReadIndexed { - dest: StatePartIndex(53), // (0xff) SlotDebugData { name: "", ty: UInt<8> }, - src: StatePartIndex(37) /* (0xff) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::array_wire[0]", ty: UInt<8> } */ [StatePartIndex(1) /* (0x0 0) SlotDebugData { name: "", ty: UInt<8> } */ , len=16, stride=1],, - }, - 37: Copy { - dest: StatePartIndex(33), // (0xff) SlotDebugData { name: "InstantiatedModule(array_rw: array_rw).array_rw::read_data", ty: UInt<8> }, - src: StatePartIndex(53), // (0xff) SlotDebugData { name: "", ty: UInt<8> }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 38: Return, - ], - .. - }, - pc: 38, - memory_write_log: [], - memories: StatePart { - value: [], - }, - small_slots: StatePart { - value: [ - 16, - 0, - ], - }, - big_slots: StatePart { - value: [ - 255, - 127, - 63, - 31, - 15, - 7, - 3, - 1, - 0, - 128, - 192, - 224, - 240, - 248, - 252, - 254, - 255, - 127, - 63, - 31, - 15, - 7, - 3, - 1, - 0, - 128, - 192, - 224, - 240, - 248, - 252, - 254, - 0, - 255, - 16, - 0, - 1, - 255, - 127, - 63, - 31, - 15, - 7, - 3, - 1, - 0, - 128, - 192, - 224, - 240, - 248, - 252, - 254, - 255, - ], - }, - sim_only_slots: StatePart { - value: [], - }, - }, - io: Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.read_index, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.read_data, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.write_index, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.write_data, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.write_en, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[0], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[10], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[11], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[12], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[13], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[14], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[15], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[1], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[2], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[3], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[4], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[5], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[6], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[7], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[8], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_in[9], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[0], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[10], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[11], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[12], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[13], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[14], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[15], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[1], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[2], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[3], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[4], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[5], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[6], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[7], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[8], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.array_out[9], - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.read_data, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.read_index, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.write_data, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.write_en, - Instance { - name: ::array_rw, - instantiated: Module { - name: array_rw, - .. - }, - }.write_index, - }, - did_initial_settle: true, - }, - extern_modules: [], - state_ready_to_run: false, - trace_decls: TraceModule { - name: "array_rw", - children: [ - TraceModuleIO { - name: "array_in", - child: TraceArray { - name: "array_in", - elements: [ - TraceUInt { - location: TraceScalarId(0), - name: "[0]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(1), - name: "[1]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(2), - name: "[2]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(3), - name: "[3]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(4), - name: "[4]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(5), - name: "[5]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(6), - name: "[6]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(7), - name: "[7]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(8), - name: "[8]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(9), - name: "[9]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(10), - name: "[10]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(11), - name: "[11]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(12), - name: "[12]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(13), - name: "[13]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(14), - name: "[14]", - ty: UInt<8>, - flow: Source, - }, - TraceUInt { - location: TraceScalarId(15), - name: "[15]", - ty: UInt<8>, - flow: Source, - }, - ], - ty: Array, 16>, - flow: Source, - }, - ty: Array, 16>, - flow: Source, - }, - TraceModuleIO { - name: "array_out", - child: TraceArray { - name: "array_out", - elements: [ - TraceUInt { - location: TraceScalarId(16), - name: "[0]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(17), - name: "[1]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(18), - name: "[2]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(19), - name: "[3]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(20), - name: "[4]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(21), - name: "[5]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(22), - name: "[6]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(23), - name: "[7]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(24), - name: "[8]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(25), - name: "[9]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(26), - name: "[10]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(27), - name: "[11]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(28), - name: "[12]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(29), - name: "[13]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(30), - name: "[14]", - ty: UInt<8>, - flow: Sink, - }, - TraceUInt { - location: TraceScalarId(31), - name: "[15]", - ty: UInt<8>, - flow: Sink, - }, - ], - ty: Array, 16>, - flow: Sink, - }, - ty: Array, 16>, - flow: Sink, - }, - TraceModuleIO { - name: "read_index", - child: TraceUInt { - location: TraceScalarId(32), - name: "read_index", - ty: UInt<8>, - flow: Source, - }, - ty: UInt<8>, - flow: Source, - }, - TraceModuleIO { - name: "read_data", - child: TraceUInt { - location: TraceScalarId(33), - name: "read_data", - ty: UInt<8>, - flow: Sink, - }, - ty: UInt<8>, - flow: Sink, - }, - TraceModuleIO { - name: "write_index", - child: TraceUInt { - location: TraceScalarId(34), - name: "write_index", - ty: UInt<8>, - flow: Source, - }, - ty: UInt<8>, - flow: Source, - }, - TraceModuleIO { - name: "write_data", - child: TraceUInt { - location: TraceScalarId(35), - name: "write_data", - ty: UInt<8>, - flow: Source, - }, - ty: UInt<8>, - flow: Source, - }, - TraceModuleIO { - name: "write_en", - child: TraceBool { - location: TraceScalarId(36), - name: "write_en", - flow: Source, - }, - ty: Bool, - flow: Source, - }, - TraceWire { - name: "array_wire", - child: TraceArray { - name: "array_wire", - elements: [ - TraceUInt { - location: TraceScalarId(37), - name: "[0]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(38), - name: "[1]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(39), - name: "[2]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(40), - name: "[3]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(41), - name: "[4]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(42), - name: "[5]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(43), - name: "[6]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(44), - name: "[7]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(45), - name: "[8]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(46), - name: "[9]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(47), - name: "[10]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(48), - name: "[11]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(49), - name: "[12]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(50), - name: "[13]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(51), - name: "[14]", - ty: UInt<8>, - flow: Duplex, - }, - TraceUInt { - location: TraceScalarId(52), - name: "[15]", - ty: UInt<8>, - flow: Duplex, - }, - ], - ty: Array, 16>, - flow: Duplex, - }, - ty: Array, 16>, - }, - ], - }, - traces: [ - SimTrace { - id: TraceScalarId(0), - kind: BigUInt { - index: StatePartIndex(0), - ty: UInt<8>, - }, - state: 0xff, - last_state: 0xff, - }, - SimTrace { - id: TraceScalarId(1), - kind: BigUInt { - index: StatePartIndex(1), - ty: UInt<8>, - }, - state: 0x7f, - last_state: 0x7f, - }, - SimTrace { - id: TraceScalarId(2), - kind: BigUInt { - index: StatePartIndex(2), - ty: UInt<8>, - }, - state: 0x3f, - last_state: 0x3f, - }, - SimTrace { - id: TraceScalarId(3), - kind: BigUInt { - index: StatePartIndex(3), - ty: UInt<8>, - }, - state: 0x1f, - last_state: 0x1f, - }, - SimTrace { - id: TraceScalarId(4), - kind: BigUInt { - index: StatePartIndex(4), - ty: UInt<8>, - }, - state: 0x0f, - last_state: 0x0f, - }, - SimTrace { - id: TraceScalarId(5), - kind: BigUInt { - index: StatePartIndex(5), - ty: UInt<8>, - }, - state: 0x07, - last_state: 0x07, - }, - SimTrace { - id: TraceScalarId(6), - kind: BigUInt { - index: StatePartIndex(6), - ty: UInt<8>, - }, - state: 0x03, - last_state: 0x03, - }, - SimTrace { - id: TraceScalarId(7), - kind: BigUInt { - index: StatePartIndex(7), - ty: UInt<8>, - }, - state: 0x01, - last_state: 0x01, - }, - SimTrace { - id: TraceScalarId(8), - kind: BigUInt { - index: StatePartIndex(8), - ty: UInt<8>, - }, - state: 0x00, - last_state: 0x00, - }, - SimTrace { - id: TraceScalarId(9), - kind: BigUInt { - index: StatePartIndex(9), - ty: UInt<8>, - }, - state: 0x80, - last_state: 0x80, - }, - SimTrace { - id: TraceScalarId(10), - kind: BigUInt { - index: StatePartIndex(10), - ty: UInt<8>, - }, - state: 0xc0, - last_state: 0xc0, - }, - SimTrace { - id: TraceScalarId(11), - kind: BigUInt { - index: StatePartIndex(11), - ty: UInt<8>, - }, - state: 0xe0, - last_state: 0xe0, - }, - SimTrace { - id: TraceScalarId(12), - kind: BigUInt { - index: StatePartIndex(12), - ty: UInt<8>, - }, - state: 0xf0, - last_state: 0xf0, - }, - SimTrace { - id: TraceScalarId(13), - kind: BigUInt { - index: StatePartIndex(13), - ty: UInt<8>, - }, - state: 0xf8, - last_state: 0xf8, - }, - SimTrace { - id: TraceScalarId(14), - kind: BigUInt { - index: StatePartIndex(14), - ty: UInt<8>, - }, - state: 0xfc, - last_state: 0xfc, - }, - SimTrace { - id: TraceScalarId(15), - kind: BigUInt { - index: StatePartIndex(15), - ty: UInt<8>, - }, - state: 0xfe, - last_state: 0xfe, - }, - SimTrace { - id: TraceScalarId(16), - kind: BigUInt { - index: StatePartIndex(16), - ty: UInt<8>, - }, - state: 0xff, - last_state: 0xff, - }, - SimTrace { - id: TraceScalarId(17), - kind: BigUInt { - index: StatePartIndex(17), - ty: UInt<8>, - }, - state: 0x7f, - last_state: 0x7f, - }, - SimTrace { - id: TraceScalarId(18), - kind: BigUInt { - index: StatePartIndex(18), - ty: UInt<8>, - }, - state: 0x3f, - last_state: 0x3f, - }, - SimTrace { - id: TraceScalarId(19), - kind: BigUInt { - index: StatePartIndex(19), - ty: UInt<8>, - }, - state: 0x1f, - last_state: 0x1f, - }, - SimTrace { - id: TraceScalarId(20), - kind: BigUInt { - index: StatePartIndex(20), - ty: UInt<8>, - }, - state: 0x0f, - last_state: 0x0f, - }, - SimTrace { - id: TraceScalarId(21), - kind: BigUInt { - index: StatePartIndex(21), - ty: UInt<8>, - }, - state: 0x07, - last_state: 0x07, - }, - SimTrace { - id: TraceScalarId(22), - kind: BigUInt { - index: StatePartIndex(22), - ty: UInt<8>, - }, - state: 0x03, - last_state: 0x03, - }, - SimTrace { - id: TraceScalarId(23), - kind: BigUInt { - index: StatePartIndex(23), - ty: UInt<8>, - }, - state: 0x01, - last_state: 0x01, - }, - SimTrace { - id: TraceScalarId(24), - kind: BigUInt { - index: StatePartIndex(24), - ty: UInt<8>, - }, - state: 0x00, - last_state: 0x00, - }, - SimTrace { - id: TraceScalarId(25), - kind: BigUInt { - index: StatePartIndex(25), - ty: UInt<8>, - }, - state: 0x80, - last_state: 0x80, - }, - SimTrace { - id: TraceScalarId(26), - kind: BigUInt { - index: StatePartIndex(26), - ty: UInt<8>, - }, - state: 0xc0, - last_state: 0xc0, - }, - SimTrace { - id: TraceScalarId(27), - kind: BigUInt { - index: StatePartIndex(27), - ty: UInt<8>, - }, - state: 0xe0, - last_state: 0xe0, - }, - SimTrace { - id: TraceScalarId(28), - kind: BigUInt { - index: StatePartIndex(28), - ty: UInt<8>, - }, - state: 0xf0, - last_state: 0xf0, - }, - SimTrace { - id: TraceScalarId(29), - kind: BigUInt { - index: StatePartIndex(29), - ty: UInt<8>, - }, - state: 0xf8, - last_state: 0xf8, - }, - SimTrace { - id: TraceScalarId(30), - kind: BigUInt { - index: StatePartIndex(30), - ty: UInt<8>, - }, - state: 0xfc, - last_state: 0xfc, - }, - SimTrace { - id: TraceScalarId(31), - kind: BigUInt { - index: StatePartIndex(31), - ty: UInt<8>, - }, - state: 0xfe, - last_state: 0xe1, - }, - SimTrace { - id: TraceScalarId(32), - kind: BigUInt { - index: StatePartIndex(32), - ty: UInt<8>, - }, - state: 0x00, - last_state: 0x00, - }, - SimTrace { - id: TraceScalarId(33), - kind: BigUInt { - index: StatePartIndex(33), - ty: UInt<8>, - }, - state: 0xff, - last_state: 0xff, - }, - SimTrace { - id: TraceScalarId(34), - kind: BigUInt { - index: StatePartIndex(34), - ty: UInt<8>, - }, - state: 0x10, - last_state: 0x0f, - }, - SimTrace { - id: TraceScalarId(35), - kind: BigUInt { - index: StatePartIndex(35), - ty: UInt<8>, - }, - state: 0x00, - last_state: 0xe1, - }, - SimTrace { - id: TraceScalarId(36), - kind: BigBool { - index: StatePartIndex(36), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(37), - kind: BigUInt { - index: StatePartIndex(37), - ty: UInt<8>, - }, - state: 0xff, - last_state: 0xff, - }, - SimTrace { - id: TraceScalarId(38), - kind: BigUInt { - index: StatePartIndex(38), - ty: UInt<8>, - }, - state: 0x7f, - last_state: 0x7f, - }, - SimTrace { - id: TraceScalarId(39), - kind: BigUInt { - index: StatePartIndex(39), - ty: UInt<8>, - }, - state: 0x3f, - last_state: 0x3f, - }, - SimTrace { - id: TraceScalarId(40), - kind: BigUInt { - index: StatePartIndex(40), - ty: UInt<8>, - }, - state: 0x1f, - last_state: 0x1f, - }, - SimTrace { - id: TraceScalarId(41), - kind: BigUInt { - index: StatePartIndex(41), - ty: UInt<8>, - }, - state: 0x0f, - last_state: 0x0f, - }, - SimTrace { - id: TraceScalarId(42), - kind: BigUInt { - index: StatePartIndex(42), - ty: UInt<8>, - }, - state: 0x07, - last_state: 0x07, - }, - SimTrace { - id: TraceScalarId(43), - kind: BigUInt { - index: StatePartIndex(43), - ty: UInt<8>, - }, - state: 0x03, - last_state: 0x03, - }, - SimTrace { - id: TraceScalarId(44), - kind: BigUInt { - index: StatePartIndex(44), - ty: UInt<8>, - }, - state: 0x01, - last_state: 0x01, - }, - SimTrace { - id: TraceScalarId(45), - kind: BigUInt { - index: StatePartIndex(45), - ty: UInt<8>, - }, - state: 0x00, - last_state: 0x00, - }, - SimTrace { - id: TraceScalarId(46), - kind: BigUInt { - index: StatePartIndex(46), - ty: UInt<8>, - }, - state: 0x80, - last_state: 0x80, - }, - SimTrace { - id: TraceScalarId(47), - kind: BigUInt { - index: StatePartIndex(47), - ty: UInt<8>, - }, - state: 0xc0, - last_state: 0xc0, - }, - SimTrace { - id: TraceScalarId(48), - kind: BigUInt { - index: StatePartIndex(48), - ty: UInt<8>, - }, - state: 0xe0, - last_state: 0xe0, - }, - SimTrace { - id: TraceScalarId(49), - kind: BigUInt { - index: StatePartIndex(49), - ty: UInt<8>, - }, - state: 0xf0, - last_state: 0xf0, - }, - SimTrace { - id: TraceScalarId(50), - kind: BigUInt { - index: StatePartIndex(50), - ty: UInt<8>, - }, - state: 0xf8, - last_state: 0xf8, - }, - SimTrace { - id: TraceScalarId(51), - kind: BigUInt { - index: StatePartIndex(51), - ty: UInt<8>, - }, - state: 0xfc, - last_state: 0xfc, - }, - SimTrace { - id: TraceScalarId(52), - kind: BigUInt { - index: StatePartIndex(52), - ty: UInt<8>, - }, - state: 0xfe, - last_state: 0xe1, - }, - ], - trace_memories: {}, - trace_writers: [ - Running( - VcdWriter { - finished_init: true, - timescale: 1 ps, - .. - }, - ), - ], - instant: 34 μs, - clocks_triggered: [], - .. -} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/array_rw.vcd b/crates/fayalite/tests/sim/expected/array_rw.vcd deleted file mode 100644 index 8ede394..0000000 --- a/crates/fayalite/tests/sim/expected/array_rw.vcd +++ /dev/null @@ -1,283 +0,0 @@ -$timescale 1 ps $end -$scope module array_rw $end -$scope struct array_in $end -$var wire 8 ! \[0] $end -$var wire 8 " \[1] $end -$var wire 8 # \[2] $end -$var wire 8 $ \[3] $end -$var wire 8 % \[4] $end -$var wire 8 & \[5] $end -$var wire 8 ' \[6] $end -$var wire 8 ( \[7] $end -$var wire 8 ) \[8] $end -$var wire 8 * \[9] $end -$var wire 8 + \[10] $end -$var wire 8 , \[11] $end -$var wire 8 - \[12] $end -$var wire 8 . \[13] $end -$var wire 8 / \[14] $end -$var wire 8 0 \[15] $end -$upscope $end -$scope struct array_out $end -$var wire 8 1 \[0] $end -$var wire 8 2 \[1] $end -$var wire 8 3 \[2] $end -$var wire 8 4 \[3] $end -$var wire 8 5 \[4] $end -$var wire 8 6 \[5] $end -$var wire 8 7 \[6] $end -$var wire 8 8 \[7] $end -$var wire 8 9 \[8] $end -$var wire 8 : \[9] $end -$var wire 8 ; \[10] $end -$var wire 8 < \[11] $end -$var wire 8 = \[12] $end -$var wire 8 > \[13] $end -$var wire 8 ? \[14] $end -$var wire 8 @ \[15] $end -$upscope $end -$var wire 8 A read_index $end -$var wire 8 B read_data $end -$var wire 8 C write_index $end -$var wire 8 D write_data $end -$var wire 1 E write_en $end -$scope struct array_wire $end -$var wire 8 F \[0] $end -$var wire 8 G \[1] $end -$var wire 8 H \[2] $end -$var wire 8 I \[3] $end -$var wire 8 J \[4] $end -$var wire 8 K \[5] $end -$var wire 8 L \[6] $end -$var wire 8 M \[7] $end -$var wire 8 N \[8] $end -$var wire 8 O \[9] $end -$var wire 8 P \[10] $end -$var wire 8 Q \[11] $end -$var wire 8 R \[12] $end -$var wire 8 S \[13] $end -$var wire 8 T \[14] $end -$var wire 8 U \[15] $end -$upscope $end -$upscope $end -$enddefinitions $end -$dumpvars -b11111111 ! -b1111111 " -b111111 # -b11111 $ -b1111 % -b111 & -b11 ' -b1 ( -b0 ) -b10000000 * -b11000000 + -b11100000 , -b11110000 - -b11111000 . -b11111100 / -b11111110 0 -b11111111 1 -b1111111 2 -b111111 3 -b11111 4 -b1111 5 -b111 6 -b11 7 -b1 8 -b0 9 -b10000000 : -b11000000 ; -b11100000 < -b11110000 = -b11111000 > -b11111100 ? -b11111110 @ -b0 A -b11111111 B -b0 C -b0 D -0E -b11111111 F -b1111111 G -b111111 H -b11111 I -b1111 J -b111 K -b11 L -b1 M -b0 N -b10000000 O -b11000000 P -b11100000 Q -b11110000 R -b11111000 S -b11111100 T -b11111110 U -$end -#1000000 -b1 A -b1111111 B -#2000000 -b10 A -b111111 B -#3000000 -b11 A -b11111 B -#4000000 -b100 A -b1111 B -#5000000 -b101 A -b111 B -#6000000 -b110 A -b11 B -#7000000 -b111 A -b1 B -#8000000 -b1000 A -b0 B -#9000000 -b1001 A -b10000000 B -#10000000 -b1010 A -b11000000 B -#11000000 -b1011 A -b11100000 B -#12000000 -b1100 A -b11110000 B -#13000000 -b1101 A -b11111000 B -#14000000 -b1110 A -b11111100 B -#15000000 -b1111 A -b11111110 B -#16000000 -b10000 A -b0 B -#17000000 -b0 1 -b0 A -1E -b0 F -#18000000 -b11111111 1 -b1 2 -b11111111 B -b1 C -b1 D -b11111111 F -b1 G -#19000000 -b1111111 2 -b100 3 -b10 C -b100 D -b1111111 G -b100 H -#20000000 -b111111 3 -b1001 4 -b11 C -b1001 D -b111111 H -b1001 I -#21000000 -b11111 4 -b10000 5 -b100 C -b10000 D -b11111 I -b10000 J -#22000000 -b1111 5 -b11001 6 -b101 C -b11001 D -b1111 J -b11001 K -#23000000 -b111 6 -b100100 7 -b110 C -b100100 D -b111 K -b100100 L -#24000000 -b11 7 -b110001 8 -b111 C -b110001 D -b11 L -b110001 M -#25000000 -b1 8 -b1000000 9 -b1000 C -b1000000 D -b1 M -b1000000 N -#26000000 -b0 9 -b1010001 : -b1001 C -b1010001 D -b0 N -b1010001 O -#27000000 -b10000000 : -b1100100 ; -b1010 C -b1100100 D -b10000000 O -b1100100 P -#28000000 -b11000000 ; -b1111001 < -b1011 C -b1111001 D -b11000000 P -b1111001 Q -#29000000 -b11100000 < -b10010000 = -b1100 C -b10010000 D -b11100000 Q -b10010000 R -#30000000 -b11110000 = -b10101001 > -b1101 C -b10101001 D -b11110000 R -b10101001 S -#31000000 -b11111000 > -b11000100 ? -b1110 C -b11000100 D -b11111000 S -b11000100 T -#32000000 -b11111100 ? -b11100001 @ -b1111 C -b11100001 D -b11111100 T -b11100001 U -#33000000 -b11111110 @ -b10000 C -b0 D -b11111110 U -#34000000 diff --git a/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt b/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt deleted file mode 100644 index 58b2d20..0000000 --- a/crates/fayalite/tests/sim/expected/conditional_assignment_last.txt +++ /dev/null @@ -1,183 +0,0 @@ -Simulation { - state: State { - insns: Insns { - state_layout: StateLayout { - ty: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 4, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::i", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::w", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - memories: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - insns: [ - // at: module-XXXXXXXXXX.rs:1:1 - 0: Const { - dest: StatePartIndex(3), // (0x0) SlotDebugData { name: "", ty: Bool }, - value: 0x0, - }, - 1: Const { - dest: StatePartIndex(2), // (0x1) SlotDebugData { name: "", ty: Bool }, - value: 0x1, - }, - // at: module-XXXXXXXXXX.rs:4:1 - 2: Copy { - dest: StatePartIndex(1), // (0x0) SlotDebugData { name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::w", ty: Bool }, - src: StatePartIndex(2), // (0x1) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:5:1 - 3: BranchIfZero { - target: 5, - value: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::i", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 4: Copy { - dest: StatePartIndex(1), // (0x0) SlotDebugData { name: "InstantiatedModule(conditional_assignment_last: conditional_assignment_last).conditional_assignment_last::w", ty: Bool }, - src: StatePartIndex(3), // (0x0) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 5: Return, - ], - .. - }, - pc: 5, - memory_write_log: [], - memories: StatePart { - value: [], - }, - small_slots: StatePart { - value: [], - }, - big_slots: StatePart { - value: [ - 1, - 0, - 1, - 0, - ], - }, - sim_only_slots: StatePart { - value: [], - }, - }, - io: Instance { - name: ::conditional_assignment_last, - instantiated: Module { - name: conditional_assignment_last, - .. - }, - }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::conditional_assignment_last, - instantiated: Module { - name: conditional_assignment_last, - .. - }, - }.i, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::conditional_assignment_last, - instantiated: Module { - name: conditional_assignment_last, - .. - }, - }.i, - }, - did_initial_settle: true, - }, - extern_modules: [], - state_ready_to_run: false, - trace_decls: TraceModule { - name: "conditional_assignment_last", - children: [ - TraceModuleIO { - name: "i", - child: TraceBool { - location: TraceScalarId(0), - name: "i", - flow: Source, - }, - ty: Bool, - flow: Source, - }, - TraceWire { - name: "w", - child: TraceBool { - location: TraceScalarId(1), - name: "w", - flow: Duplex, - }, - ty: Bool, - }, - ], - }, - traces: [ - SimTrace { - id: TraceScalarId(0), - kind: BigBool { - index: StatePartIndex(0), - }, - state: 0x1, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(1), - kind: BigBool { - index: StatePartIndex(1), - }, - state: 0x0, - last_state: 0x1, - }, - ], - trace_memories: {}, - trace_writers: [ - Running( - VcdWriter { - finished_init: true, - timescale: 1 ps, - .. - }, - ), - ], - instant: 2 μs, - clocks_triggered: [], - .. -} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/conditional_assignment_last.vcd b/crates/fayalite/tests/sim/expected/conditional_assignment_last.vcd deleted file mode 100644 index dd9a85a..0000000 --- a/crates/fayalite/tests/sim/expected/conditional_assignment_last.vcd +++ /dev/null @@ -1,14 +0,0 @@ -$timescale 1 ps $end -$scope module conditional_assignment_last $end -$var wire 1 ! i $end -$var wire 1 " w $end -$upscope $end -$enddefinitions $end -$dumpvars -0! -1" -$end -#1000000 -1! -0" -#2000000 diff --git a/crates/fayalite/tests/sim/expected/connect_const.txt b/crates/fayalite/tests/sim/expected/connect_const.txt index 182ed84..e44c50d 100644 --- a/crates/fayalite/tests/sim/expected/connect_const.txt +++ b/crates/fayalite/tests/sim/expected/connect_const.txt @@ -22,12 +22,6 @@ Simulation { ], .. }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, }, memories: StatePartLayout { len: 0, @@ -66,9 +60,6 @@ Simulation { 5, ], }, - sim_only_slots: StatePart { - value: [], - }, }, io: Instance { name: ::connect_const, @@ -77,30 +68,45 @@ Simulation { .. }, }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::connect_const, - instantiated: Module { - name: connect_const, - .. + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::connect_const, + instantiated: Module { + name: connect_const, + .. + }, + }.o: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(connect_const: connect_const).connect_const::o", + ty: UInt<8>, + }, + ], + .. + }, }, - }.o, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::connect_const, - instantiated: Module { - name: connect_const, - .. - }, - }.o, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, }, - did_initial_settle: true, }, - extern_modules: [], - state_ready_to_run: false, + made_initial_step: true, + needs_settle: false, trace_decls: TraceModule { name: "connect_const", children: [ diff --git a/crates/fayalite/tests/sim/expected/connect_const_reset.txt b/crates/fayalite/tests/sim/expected/connect_const_reset.txt index f56a6b4..d1ab998 100644 --- a/crates/fayalite/tests/sim/expected/connect_const_reset.txt +++ b/crates/fayalite/tests/sim/expected/connect_const_reset.txt @@ -34,12 +34,6 @@ Simulation { ], .. }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, }, memories: StatePartLayout { len: 0, @@ -95,9 +89,6 @@ Simulation { 1, ], }, - sim_only_slots: StatePart { - value: [], - }, }, io: Instance { name: ::connect_const_reset, @@ -106,44 +97,79 @@ Simulation { .. }, }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::connect_const_reset, - instantiated: Module { - name: connect_const_reset, - .. + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::connect_const_reset, + instantiated: Module { + name: connect_const_reset, + .. + }, + }.bit_out: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(connect_const_reset: connect_const_reset).connect_const_reset::bit_out", + ty: Bool, + }, + ], + .. + }, }, - }.reset_out, - Instance { - name: ::connect_const_reset, - instantiated: Module { - name: connect_const_reset, - .. - }, - }.bit_out, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::connect_const_reset, - instantiated: Module { - name: connect_const_reset, - .. - }, - }.bit_out, - Instance { - name: ::connect_const_reset, - instantiated: Module { - name: connect_const_reset, - .. - }, - }.reset_out, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 1, len: 1 }, + }, + write: None, + }, + Instance { + name: ::connect_const_reset, + instantiated: Module { + name: connect_const_reset, + .. + }, + }.reset_out: CompiledValue { + layout: CompiledTypeLayout { + ty: AsyncReset, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(connect_const_reset: connect_const_reset).connect_const_reset::reset_out", + ty: AsyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, }, - did_initial_settle: true, }, - extern_modules: [], - state_ready_to_run: false, + made_initial_step: true, + needs_settle: false, trace_decls: TraceModule { name: "connect_const_reset", children: [ diff --git a/crates/fayalite/tests/sim/expected/counter_async.txt b/crates/fayalite/tests/sim/expected/counter_async.txt index 8c8809a..2e005a0 100644 --- a/crates/fayalite/tests/sim/expected/counter_async.txt +++ b/crates/fayalite/tests/sim/expected/counter_async.txt @@ -71,12 +71,6 @@ Simulation { ], .. }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, }, memories: StatePartLayout { len: 0, @@ -201,9 +195,6 @@ Simulation { 4, ], }, - sim_only_slots: StatePart { - value: [], - }, }, io: Instance { name: ::counter, @@ -212,58 +203,213 @@ Simulation { .. }, }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + rst: AsyncReset, }, - }.cd, - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::cd.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::cd.rst", + ty: AsyncReset, + }, + ], + .. + }, }, - }.count, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: AsyncReset, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: AsyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], }, - }.cd, - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. - }, - }.cd.clk, - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. - }, - }.cd.rst, - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. - }, - }.count, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 2 }, + }, + write: None, + }, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd.clk: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, + }, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd.rst: CompiledValue { + layout: CompiledTypeLayout { + ty: AsyncReset, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: AsyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 1, len: 1 }, + }, + write: None, + }, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.count: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<4>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::count", + ty: UInt<4>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 2, len: 1 }, + }, + write: None, }, - did_initial_settle: true, }, - extern_modules: [], - state_ready_to_run: false, + made_initial_step: true, + needs_settle: false, trace_decls: TraceModule { name: "counter", children: [ diff --git a/crates/fayalite/tests/sim/expected/counter_sync.txt b/crates/fayalite/tests/sim/expected/counter_sync.txt index 1d975b3..78fc200 100644 --- a/crates/fayalite/tests/sim/expected/counter_sync.txt +++ b/crates/fayalite/tests/sim/expected/counter_sync.txt @@ -67,12 +67,6 @@ Simulation { ], .. }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, }, memories: StatePartLayout { len: 0, @@ -182,9 +176,6 @@ Simulation { 4, ], }, - sim_only_slots: StatePart { - value: [], - }, }, io: Instance { name: ::counter, @@ -193,58 +184,213 @@ Simulation { .. }, }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + rst: SyncReset, }, - }.cd, - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::cd.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::cd.rst", + ty: SyncReset, + }, + ], + .. + }, }, - }.count, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: SyncReset, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], }, - }.cd, - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. - }, - }.cd.clk, - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. - }, - }.cd.rst, - Instance { - name: ::counter, - instantiated: Module { - name: counter, - .. - }, - }.count, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 2 }, + }, + write: None, + }, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd.clk: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, + }, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd.rst: CompiledValue { + layout: CompiledTypeLayout { + ty: SyncReset, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 1, len: 1 }, + }, + write: None, + }, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.count: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<4>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::count", + ty: UInt<4>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 2, len: 1 }, + }, + write: None, }, - did_initial_settle: true, }, - extern_modules: [], - state_ready_to_run: false, + made_initial_step: true, + needs_settle: false, trace_decls: TraceModule { name: "counter", children: [ diff --git a/crates/fayalite/tests/sim/expected/duplicate_names.txt b/crates/fayalite/tests/sim/expected/duplicate_names.txt deleted file mode 100644 index 4c54aa8..0000000 --- a/crates/fayalite/tests/sim/expected/duplicate_names.txt +++ /dev/null @@ -1,166 +0,0 @@ -Simulation { - state: State { - insns: Insns { - state_layout: StateLayout { - ty: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 4, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w", - ty: UInt<8>, - }, - SlotDebugData { - name: "", - ty: UInt<8>, - }, - SlotDebugData { - name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w", - ty: UInt<8>, - }, - SlotDebugData { - name: "", - ty: UInt<8>, - }, - ], - .. - }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - memories: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - insns: [ - // at: module-XXXXXXXXXX.rs:1:1 - 0: Const { - dest: StatePartIndex(3), // (0x6) SlotDebugData { name: "", ty: UInt<8> }, - value: 0x6, - }, - // at: module-XXXXXXXXXX.rs:5:1 - 1: Copy { - dest: StatePartIndex(2), // (0x6) SlotDebugData { name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w", ty: UInt<8> }, - src: StatePartIndex(3), // (0x6) SlotDebugData { name: "", ty: UInt<8> }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 2: Const { - dest: StatePartIndex(1), // (0x5) SlotDebugData { name: "", ty: UInt<8> }, - value: 0x5, - }, - // at: module-XXXXXXXXXX.rs:3:1 - 3: Copy { - dest: StatePartIndex(0), // (0x5) SlotDebugData { name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w", ty: UInt<8> }, - src: StatePartIndex(1), // (0x5) SlotDebugData { name: "", ty: UInt<8> }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 4: Return, - ], - .. - }, - pc: 4, - memory_write_log: [], - memories: StatePart { - value: [], - }, - small_slots: StatePart { - value: [], - }, - big_slots: StatePart { - value: [ - 5, - 5, - 6, - 6, - ], - }, - sim_only_slots: StatePart { - value: [], - }, - }, - io: Instance { - name: ::duplicate_names, - instantiated: Module { - name: duplicate_names, - .. - }, - }, - main_module: SimulationModuleState { - base_targets: [], - uninitialized_ios: {}, - io_targets: {}, - did_initial_settle: true, - }, - extern_modules: [], - state_ready_to_run: false, - trace_decls: TraceModule { - name: "duplicate_names", - children: [ - TraceWire { - name: "w", - child: TraceUInt { - location: TraceScalarId(0), - name: "w", - ty: UInt<8>, - flow: Duplex, - }, - ty: UInt<8>, - }, - TraceWire { - name: "w", - child: TraceUInt { - location: TraceScalarId(1), - name: "w", - ty: UInt<8>, - flow: Duplex, - }, - ty: UInt<8>, - }, - ], - }, - traces: [ - SimTrace { - id: TraceScalarId(0), - kind: BigUInt { - index: StatePartIndex(0), - ty: UInt<8>, - }, - state: 0x05, - last_state: 0x05, - }, - SimTrace { - id: TraceScalarId(1), - kind: BigUInt { - index: StatePartIndex(2), - ty: UInt<8>, - }, - state: 0x06, - last_state: 0x06, - }, - ], - trace_memories: {}, - trace_writers: [ - Running( - VcdWriter { - finished_init: true, - timescale: 1 ps, - .. - }, - ), - ], - instant: 1 μs, - clocks_triggered: [], - .. -} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/duplicate_names.vcd b/crates/fayalite/tests/sim/expected/duplicate_names.vcd deleted file mode 100644 index 1e9f6c6..0000000 --- a/crates/fayalite/tests/sim/expected/duplicate_names.vcd +++ /dev/null @@ -1,11 +0,0 @@ -$timescale 1 ps $end -$scope module duplicate_names $end -$var wire 8 ! w $end -$var wire 8 " w_2 $end -$upscope $end -$enddefinitions $end -$dumpvars -b101 ! -b110 " -$end -#1000000 diff --git a/crates/fayalite/tests/sim/expected/enums.txt b/crates/fayalite/tests/sim/expected/enums.txt index 4850a21..ebfae3e 100644 --- a/crates/fayalite/tests/sim/expected/enums.txt +++ b/crates/fayalite/tests/sim/expected/enums.txt @@ -4,7 +4,7 @@ Simulation { state_layout: StateLayout { ty: TypeLayout { small_slots: StatePartLayout { - len: 7, + len: 6, debug_data: [ SlotDebugData { name: "", @@ -13,13 +13,6 @@ Simulation { HdlSome, }, }, - SlotDebugData { - name: "", - ty: Enum { - HdlNone, - HdlSome, - }, - }, SlotDebugData { name: "", ty: Bool, @@ -48,7 +41,7 @@ Simulation { .. }, big_slots: StatePartLayout { - len: 111, + len: 103, debug_data: [ SlotDebugData { name: "InstantiatedModule(enums: enums).enums::cd.clk", @@ -113,41 +106,6 @@ Simulation { name: "", ty: Bool, }, - SlotDebugData { - name: "InstantiatedModule(enums: enums).enums::b2_out", - ty: Enum { - HdlNone, - HdlSome(Bundle {0: UInt<1>, 1: Bool}), - }, - }, - SlotDebugData { - name: ".0", - ty: UInt<1>, - }, - SlotDebugData { - name: ".1", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<3>, - }, - SlotDebugData { - name: "", - ty: UInt<2>, - }, - SlotDebugData { - name: "", - ty: UInt<1>, - }, - SlotDebugData { - name: "", - ty: UInt<1>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg", ty: Enum { @@ -529,12 +487,6 @@ Simulation { ], .. }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, }, memories: StatePartLayout { len: 0, @@ -546,640 +498,594 @@ Simulation { insns: [ // at: module-XXXXXXXXXX.rs:1:1 0: Const { - dest: StatePartIndex(98), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + dest: StatePartIndex(90), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, value: 0x1, }, 1: Const { - dest: StatePartIndex(90), // (0x0) SlotDebugData { name: "", ty: UInt<4> }, + dest: StatePartIndex(82), // (0x0) SlotDebugData { name: "", ty: UInt<4> }, value: 0x0, }, 2: Const { - dest: StatePartIndex(88), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, + dest: StatePartIndex(80), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, value: 0x0, }, 3: Copy { - dest: StatePartIndex(89), // (0x0) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, - src: StatePartIndex(88), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, + dest: StatePartIndex(81), // (0x0) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, + src: StatePartIndex(80), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, }, - // at: module-XXXXXXXXXX.rs:18:1 + // at: module-XXXXXXXXXX.rs:16:1 4: Copy { dest: StatePartIndex(7), // (0x0) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::b_out", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, - src: StatePartIndex(89), // (0x0) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, + src: StatePartIndex(81), // (0x0) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, }, // at: module-XXXXXXXXXX.rs:1:1 5: SliceInt { - dest: StatePartIndex(77), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(69), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, src: StatePartIndex(4), // (0xf) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::data_in", ty: UInt<4> }, start: 2, len: 2, }, 6: CastToSInt { - dest: StatePartIndex(78), // (-0x1) SlotDebugData { name: "", ty: SInt<2> }, - src: StatePartIndex(77), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(70), // (-0x1) SlotDebugData { name: "", ty: SInt<2> }, + src: StatePartIndex(69), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, dest_width: 2, }, 7: Const { - dest: StatePartIndex(70), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(62), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, value: 0x2, }, 8: SliceInt { - dest: StatePartIndex(57), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + dest: StatePartIndex(49), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, src: StatePartIndex(4), // (0xf) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::data_in", ty: UInt<4> }, start: 1, len: 1, }, 9: Copy { - dest: StatePartIndex(58), // (0x1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(57), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + dest: StatePartIndex(50), // (0x1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(49), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, }, 10: Copy { - dest: StatePartIndex(76), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(58), // (0x1) SlotDebugData { name: "", ty: Bool }, + dest: StatePartIndex(68), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(50), // (0x1) SlotDebugData { name: "", ty: Bool }, }, 11: SliceInt { - dest: StatePartIndex(54), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + dest: StatePartIndex(46), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, src: StatePartIndex(4), // (0xf) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::data_in", ty: UInt<4> }, start: 0, len: 1, }, 12: Copy { - dest: StatePartIndex(55), // (0x1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(54), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + dest: StatePartIndex(47), // (0x1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(46), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, }, 13: Copy { - dest: StatePartIndex(56), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(55), // (0x1) SlotDebugData { name: "", ty: Bool }, + dest: StatePartIndex(48), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(47), // (0x1) SlotDebugData { name: "", ty: Bool }, }, 14: Copy { - dest: StatePartIndex(52), // (0x1) SlotDebugData { name: ".0", ty: UInt<1> }, - src: StatePartIndex(56), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + dest: StatePartIndex(44), // (0x1) SlotDebugData { name: ".0", ty: UInt<1> }, + src: StatePartIndex(48), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, }, 15: Copy { - dest: StatePartIndex(53), // (0x1) SlotDebugData { name: ".1", ty: Bool }, - src: StatePartIndex(58), // (0x1) SlotDebugData { name: "", ty: Bool }, + dest: StatePartIndex(45), // (0x1) SlotDebugData { name: ".1", ty: Bool }, + src: StatePartIndex(50), // (0x1) SlotDebugData { name: "", ty: Bool }, }, 16: Copy { - dest: StatePartIndex(74), // (0x1) SlotDebugData { name: "[0]", ty: UInt<1> }, - src: StatePartIndex(56), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + dest: StatePartIndex(66), // (0x1) SlotDebugData { name: "[0]", ty: UInt<1> }, + src: StatePartIndex(48), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, }, 17: Copy { - dest: StatePartIndex(75), // (0x1) SlotDebugData { name: "[1]", ty: UInt<1> }, - src: StatePartIndex(76), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + dest: StatePartIndex(67), // (0x1) SlotDebugData { name: "[1]", ty: UInt<1> }, + src: StatePartIndex(68), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, }, 18: Copy { - dest: StatePartIndex(71), // (0x1) SlotDebugData { name: ".a[0]", ty: UInt<1> }, - src: StatePartIndex(74), // (0x1) SlotDebugData { name: "[0]", ty: UInt<1> }, + dest: StatePartIndex(63), // (0x1) SlotDebugData { name: ".a[0]", ty: UInt<1> }, + src: StatePartIndex(66), // (0x1) SlotDebugData { name: "[0]", ty: UInt<1> }, }, 19: Copy { - dest: StatePartIndex(72), // (0x1) SlotDebugData { name: ".a[1]", ty: UInt<1> }, - src: StatePartIndex(75), // (0x1) SlotDebugData { name: "[1]", ty: UInt<1> }, + dest: StatePartIndex(64), // (0x1) SlotDebugData { name: ".a[1]", ty: UInt<1> }, + src: StatePartIndex(67), // (0x1) SlotDebugData { name: "[1]", ty: UInt<1> }, }, 20: Copy { - dest: StatePartIndex(73), // (-0x1) SlotDebugData { name: ".b", ty: SInt<2> }, - src: StatePartIndex(78), // (-0x1) SlotDebugData { name: "", ty: SInt<2> }, + dest: StatePartIndex(65), // (-0x1) SlotDebugData { name: ".b", ty: SInt<2> }, + src: StatePartIndex(70), // (-0x1) SlotDebugData { name: "", ty: SInt<2> }, }, 21: Copy { - dest: StatePartIndex(66), // (0x2) SlotDebugData { name: ".0", ty: UInt<2> }, - src: StatePartIndex(70), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(58), // (0x2) SlotDebugData { name: ".0", ty: UInt<2> }, + src: StatePartIndex(62), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, }, 22: Copy { - dest: StatePartIndex(67), // (0x1) SlotDebugData { name: ".1.a[0]", ty: UInt<1> }, - src: StatePartIndex(71), // (0x1) SlotDebugData { name: ".a[0]", ty: UInt<1> }, + dest: StatePartIndex(59), // (0x1) SlotDebugData { name: ".1.a[0]", ty: UInt<1> }, + src: StatePartIndex(63), // (0x1) SlotDebugData { name: ".a[0]", ty: UInt<1> }, }, 23: Copy { - dest: StatePartIndex(68), // (0x1) SlotDebugData { name: ".1.a[1]", ty: UInt<1> }, - src: StatePartIndex(72), // (0x1) SlotDebugData { name: ".a[1]", ty: UInt<1> }, + dest: StatePartIndex(60), // (0x1) SlotDebugData { name: ".1.a[1]", ty: UInt<1> }, + src: StatePartIndex(64), // (0x1) SlotDebugData { name: ".a[1]", ty: UInt<1> }, }, 24: Copy { - dest: StatePartIndex(69), // (-0x1) SlotDebugData { name: ".1.b", ty: SInt<2> }, - src: StatePartIndex(73), // (-0x1) SlotDebugData { name: ".b", ty: SInt<2> }, + dest: StatePartIndex(61), // (-0x1) SlotDebugData { name: ".1.b", ty: SInt<2> }, + src: StatePartIndex(65), // (-0x1) SlotDebugData { name: ".b", ty: SInt<2> }, }, 25: Shl { - dest: StatePartIndex(79), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, - lhs: StatePartIndex(68), // (0x1) SlotDebugData { name: ".1.a[1]", ty: UInt<1> }, + dest: StatePartIndex(71), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, + lhs: StatePartIndex(60), // (0x1) SlotDebugData { name: ".1.a[1]", ty: UInt<1> }, rhs: 1, }, 26: Or { - dest: StatePartIndex(80), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, - lhs: StatePartIndex(67), // (0x1) SlotDebugData { name: ".1.a[0]", ty: UInt<1> }, - rhs: StatePartIndex(79), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(72), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + lhs: StatePartIndex(59), // (0x1) SlotDebugData { name: ".1.a[0]", ty: UInt<1> }, + rhs: StatePartIndex(71), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, }, 27: CastToUInt { - dest: StatePartIndex(81), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, - src: StatePartIndex(69), // (-0x1) SlotDebugData { name: ".1.b", ty: SInt<2> }, + dest: StatePartIndex(73), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(61), // (-0x1) SlotDebugData { name: ".1.b", ty: SInt<2> }, dest_width: 2, }, 28: Shl { - dest: StatePartIndex(82), // (0xc) SlotDebugData { name: "", ty: UInt<4> }, - lhs: StatePartIndex(81), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(74), // (0xc) SlotDebugData { name: "", ty: UInt<4> }, + lhs: StatePartIndex(73), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, rhs: 2, }, 29: Or { - dest: StatePartIndex(83), // (0xf) SlotDebugData { name: "", ty: UInt<4> }, - lhs: StatePartIndex(80), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, - rhs: StatePartIndex(82), // (0xc) SlotDebugData { name: "", ty: UInt<4> }, + dest: StatePartIndex(75), // (0xf) SlotDebugData { name: "", ty: UInt<4> }, + lhs: StatePartIndex(72), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + rhs: StatePartIndex(74), // (0xc) SlotDebugData { name: "", ty: UInt<4> }, }, 30: Shl { - dest: StatePartIndex(84), // (0x3c) SlotDebugData { name: "", ty: UInt<6> }, - lhs: StatePartIndex(83), // (0xf) SlotDebugData { name: "", ty: UInt<4> }, + dest: StatePartIndex(76), // (0x3c) SlotDebugData { name: "", ty: UInt<6> }, + lhs: StatePartIndex(75), // (0xf) SlotDebugData { name: "", ty: UInt<4> }, rhs: 2, }, 31: Or { - dest: StatePartIndex(85), // (0x3e) SlotDebugData { name: "", ty: UInt<6> }, - lhs: StatePartIndex(66), // (0x2) SlotDebugData { name: ".0", ty: UInt<2> }, - rhs: StatePartIndex(84), // (0x3c) SlotDebugData { name: "", ty: UInt<6> }, + dest: StatePartIndex(77), // (0x3e) SlotDebugData { name: "", ty: UInt<6> }, + lhs: StatePartIndex(58), // (0x2) SlotDebugData { name: ".0", ty: UInt<2> }, + rhs: StatePartIndex(76), // (0x3c) SlotDebugData { name: "", ty: UInt<6> }, }, 32: CastToUInt { - dest: StatePartIndex(86), // (0x3e) SlotDebugData { name: "", ty: UInt<6> }, - src: StatePartIndex(85), // (0x3e) SlotDebugData { name: "", ty: UInt<6> }, + dest: StatePartIndex(78), // (0x3e) SlotDebugData { name: "", ty: UInt<6> }, + src: StatePartIndex(77), // (0x3e) SlotDebugData { name: "", ty: UInt<6> }, dest_width: 6, }, 33: Copy { - dest: StatePartIndex(87), // (0x3e) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, - src: StatePartIndex(86), // (0x3e) SlotDebugData { name: "", ty: UInt<6> }, + dest: StatePartIndex(79), // (0x3e) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + src: StatePartIndex(78), // (0x3e) SlotDebugData { name: "", ty: UInt<6> }, }, 34: Const { - dest: StatePartIndex(47), // (0x1) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(39), // (0x1) SlotDebugData { name: "", ty: UInt<2> }, value: 0x1, }, 35: CmpEq { - dest: StatePartIndex(48), // (0x0) SlotDebugData { name: "", ty: Bool }, + dest: StatePartIndex(40), // (0x0) SlotDebugData { name: "", ty: Bool }, lhs: StatePartIndex(3), // (0x2) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::which_in", ty: UInt<2> }, - rhs: StatePartIndex(47), // (0x1) SlotDebugData { name: "", ty: UInt<2> }, + rhs: StatePartIndex(39), // (0x1) SlotDebugData { name: "", ty: UInt<2> }, }, 36: Copy { - dest: StatePartIndex(49), // (0x1) SlotDebugData { name: ".0", ty: UInt<2> }, - src: StatePartIndex(47), // (0x1) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(41), // (0x1) SlotDebugData { name: ".0", ty: UInt<2> }, + src: StatePartIndex(39), // (0x1) SlotDebugData { name: "", ty: UInt<2> }, }, 37: Copy { - dest: StatePartIndex(50), // (0x1) SlotDebugData { name: ".1.0", ty: UInt<1> }, - src: StatePartIndex(52), // (0x1) SlotDebugData { name: ".0", ty: UInt<1> }, + dest: StatePartIndex(42), // (0x1) SlotDebugData { name: ".1.0", ty: UInt<1> }, + src: StatePartIndex(44), // (0x1) SlotDebugData { name: ".0", ty: UInt<1> }, }, 38: Copy { - dest: StatePartIndex(51), // (0x1) SlotDebugData { name: ".1.1", ty: Bool }, - src: StatePartIndex(53), // (0x1) SlotDebugData { name: ".1", ty: Bool }, + dest: StatePartIndex(43), // (0x1) SlotDebugData { name: ".1.1", ty: Bool }, + src: StatePartIndex(45), // (0x1) SlotDebugData { name: ".1", ty: Bool }, }, 39: Copy { - dest: StatePartIndex(59), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(51), // (0x1) SlotDebugData { name: ".1.1", ty: Bool }, + dest: StatePartIndex(51), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(43), // (0x1) SlotDebugData { name: ".1.1", ty: Bool }, }, 40: Shl { - dest: StatePartIndex(60), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, - lhs: StatePartIndex(59), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + dest: StatePartIndex(52), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, + lhs: StatePartIndex(51), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, rhs: 1, }, 41: Or { - dest: StatePartIndex(61), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, - lhs: StatePartIndex(50), // (0x1) SlotDebugData { name: ".1.0", ty: UInt<1> }, - rhs: StatePartIndex(60), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(53), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + lhs: StatePartIndex(42), // (0x1) SlotDebugData { name: ".1.0", ty: UInt<1> }, + rhs: StatePartIndex(52), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, }, 42: Shl { - dest: StatePartIndex(62), // (0xc) SlotDebugData { name: "", ty: UInt<4> }, - lhs: StatePartIndex(61), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(54), // (0xc) SlotDebugData { name: "", ty: UInt<4> }, + lhs: StatePartIndex(53), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, rhs: 2, }, 43: Or { - dest: StatePartIndex(63), // (0xd) SlotDebugData { name: "", ty: UInt<4> }, - lhs: StatePartIndex(49), // (0x1) SlotDebugData { name: ".0", ty: UInt<2> }, - rhs: StatePartIndex(62), // (0xc) SlotDebugData { name: "", ty: UInt<4> }, + dest: StatePartIndex(55), // (0xd) SlotDebugData { name: "", ty: UInt<4> }, + lhs: StatePartIndex(41), // (0x1) SlotDebugData { name: ".0", ty: UInt<2> }, + rhs: StatePartIndex(54), // (0xc) SlotDebugData { name: "", ty: UInt<4> }, }, 44: CastToUInt { - dest: StatePartIndex(64), // (0xd) SlotDebugData { name: "", ty: UInt<6> }, - src: StatePartIndex(63), // (0xd) SlotDebugData { name: "", ty: UInt<4> }, + dest: StatePartIndex(56), // (0xd) SlotDebugData { name: "", ty: UInt<6> }, + src: StatePartIndex(55), // (0xd) SlotDebugData { name: "", ty: UInt<4> }, dest_width: 6, }, 45: Copy { - dest: StatePartIndex(65), // (0xd) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, - src: StatePartIndex(64), // (0xd) SlotDebugData { name: "", ty: UInt<6> }, + dest: StatePartIndex(57), // (0xd) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + src: StatePartIndex(56), // (0xd) SlotDebugData { name: "", ty: UInt<6> }, }, 46: Const { - dest: StatePartIndex(45), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(37), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, value: 0x0, }, 47: CmpEq { - dest: StatePartIndex(46), // (0x0) SlotDebugData { name: "", ty: Bool }, + dest: StatePartIndex(38), // (0x0) SlotDebugData { name: "", ty: Bool }, lhs: StatePartIndex(3), // (0x2) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::which_in", ty: UInt<2> }, - rhs: StatePartIndex(45), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, + rhs: StatePartIndex(37), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, }, 48: Copy { - dest: StatePartIndex(29), // (0x3e) SlotDebugData { name: "", ty: UInt<6> }, - src: StatePartIndex(23), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + dest: StatePartIndex(21), // (0x3e) SlotDebugData { name: "", ty: UInt<6> }, + src: StatePartIndex(15), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, }, 49: SliceInt { - dest: StatePartIndex(30), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, - src: StatePartIndex(29), // (0x3e) SlotDebugData { name: "", ty: UInt<6> }, + dest: StatePartIndex(22), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(21), // (0x3e) SlotDebugData { name: "", ty: UInt<6> }, start: 2, len: 2, }, 50: SliceInt { - dest: StatePartIndex(31), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(30), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(23), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(22), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, start: 0, len: 1, }, 51: SliceInt { - dest: StatePartIndex(32), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(30), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(24), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(22), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, start: 1, len: 1, }, 52: Copy { - dest: StatePartIndex(33), // (0x1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(32), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + dest: StatePartIndex(25), // (0x1) SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(24), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, }, 53: Copy { - dest: StatePartIndex(27), // (0x1) SlotDebugData { name: ".0", ty: UInt<1> }, - src: StatePartIndex(31), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + dest: StatePartIndex(19), // (0x1) SlotDebugData { name: ".0", ty: UInt<1> }, + src: StatePartIndex(23), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, }, 54: Copy { - dest: StatePartIndex(28), // (0x1) SlotDebugData { name: ".1", ty: Bool }, - src: StatePartIndex(33), // (0x1) SlotDebugData { name: "", ty: Bool }, + dest: StatePartIndex(20), // (0x1) SlotDebugData { name: ".1", ty: Bool }, + src: StatePartIndex(25), // (0x1) SlotDebugData { name: "", ty: Bool }, }, 55: Copy { - dest: StatePartIndex(91), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(28), // (0x1) SlotDebugData { name: ".1", ty: Bool }, + dest: StatePartIndex(83), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(20), // (0x1) SlotDebugData { name: ".1", ty: Bool }, }, 56: Shl { + dest: StatePartIndex(84), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, + lhs: StatePartIndex(83), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + rhs: 1, + }, + 57: Or { + dest: StatePartIndex(85), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + lhs: StatePartIndex(19), // (0x1) SlotDebugData { name: ".0", ty: UInt<1> }, + rhs: StatePartIndex(84), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, + }, + 58: CastToUInt { + dest: StatePartIndex(86), // (0x3) SlotDebugData { name: "", ty: UInt<4> }, + src: StatePartIndex(85), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + dest_width: 4, + }, + 59: Copy { + dest: StatePartIndex(87), // (0x1) SlotDebugData { name: ".0", ty: UInt<1> }, + src: StatePartIndex(90), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + }, + 60: Copy { + dest: StatePartIndex(88), // (0x1) SlotDebugData { name: ".1.0", ty: UInt<1> }, + src: StatePartIndex(19), // (0x1) SlotDebugData { name: ".0", ty: UInt<1> }, + }, + 61: Copy { + dest: StatePartIndex(89), // (0x1) SlotDebugData { name: ".1.1", ty: Bool }, + src: StatePartIndex(20), // (0x1) SlotDebugData { name: ".1", ty: Bool }, + }, + 62: Copy { + dest: StatePartIndex(91), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(89), // (0x1) SlotDebugData { name: ".1.1", ty: Bool }, + }, + 63: Shl { dest: StatePartIndex(92), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, lhs: StatePartIndex(91), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, rhs: 1, }, - 57: Or { + 64: Or { dest: StatePartIndex(93), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, - lhs: StatePartIndex(27), // (0x1) SlotDebugData { name: ".0", ty: UInt<1> }, + lhs: StatePartIndex(88), // (0x1) SlotDebugData { name: ".1.0", ty: UInt<1> }, rhs: StatePartIndex(92), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, }, - 58: CastToUInt { - dest: StatePartIndex(94), // (0x3) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(93), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, - dest_width: 4, - }, - 59: Copy { - dest: StatePartIndex(95), // (0x1) SlotDebugData { name: ".0", ty: UInt<1> }, - src: StatePartIndex(98), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, - }, - 60: Copy { - dest: StatePartIndex(96), // (0x1) SlotDebugData { name: ".1.0", ty: UInt<1> }, - src: StatePartIndex(27), // (0x1) SlotDebugData { name: ".0", ty: UInt<1> }, - }, - 61: Copy { - dest: StatePartIndex(97), // (0x1) SlotDebugData { name: ".1.1", ty: Bool }, - src: StatePartIndex(28), // (0x1) SlotDebugData { name: ".1", ty: Bool }, - }, - 62: Copy { - dest: StatePartIndex(99), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(97), // (0x1) SlotDebugData { name: ".1.1", ty: Bool }, - }, - 63: Shl { - dest: StatePartIndex(100), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, - lhs: StatePartIndex(99), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, - rhs: 1, - }, - 64: Or { - dest: StatePartIndex(101), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, - lhs: StatePartIndex(96), // (0x1) SlotDebugData { name: ".1.0", ty: UInt<1> }, - rhs: StatePartIndex(100), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, - }, 65: Shl { - dest: StatePartIndex(102), // (0x6) SlotDebugData { name: "", ty: UInt<3> }, - lhs: StatePartIndex(101), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(94), // (0x6) SlotDebugData { name: "", ty: UInt<3> }, + lhs: StatePartIndex(93), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, rhs: 1, }, 66: Or { - dest: StatePartIndex(103), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, - lhs: StatePartIndex(95), // (0x1) SlotDebugData { name: ".0", ty: UInt<1> }, - rhs: StatePartIndex(102), // (0x6) SlotDebugData { name: "", ty: UInt<3> }, + dest: StatePartIndex(95), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + lhs: StatePartIndex(87), // (0x1) SlotDebugData { name: ".0", ty: UInt<1> }, + rhs: StatePartIndex(94), // (0x6) SlotDebugData { name: "", ty: UInt<3> }, }, 67: CastToUInt { - dest: StatePartIndex(104), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, - src: StatePartIndex(103), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + dest: StatePartIndex(96), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + src: StatePartIndex(95), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, dest_width: 3, }, 68: Copy { - dest: StatePartIndex(105), // (0x7) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, - src: StatePartIndex(104), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, + dest: StatePartIndex(97), // (0x7) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, + src: StatePartIndex(96), // (0x7) SlotDebugData { name: "", ty: UInt<3> }, }, 69: SliceInt { - dest: StatePartIndex(39), // (0xf) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(29), // (0x3e) SlotDebugData { name: "", ty: UInt<6> }, + dest: StatePartIndex(31), // (0xf) SlotDebugData { name: "", ty: UInt<4> }, + src: StatePartIndex(21), // (0x3e) SlotDebugData { name: "", ty: UInt<6> }, start: 2, len: 4, }, 70: SliceInt { - dest: StatePartIndex(40), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, - src: StatePartIndex(39), // (0xf) SlotDebugData { name: "", ty: UInt<4> }, + dest: StatePartIndex(32), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(31), // (0xf) SlotDebugData { name: "", ty: UInt<4> }, start: 0, len: 2, }, 71: SliceInt { - dest: StatePartIndex(41), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(40), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(33), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(32), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, start: 0, len: 1, }, 72: SliceInt { - dest: StatePartIndex(42), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(40), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(34), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + src: StatePartIndex(32), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, start: 1, len: 1, }, 73: Copy { - dest: StatePartIndex(37), // (0x1) SlotDebugData { name: "[0]", ty: UInt<1> }, - src: StatePartIndex(41), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + dest: StatePartIndex(29), // (0x1) SlotDebugData { name: "[0]", ty: UInt<1> }, + src: StatePartIndex(33), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, }, 74: Copy { - dest: StatePartIndex(38), // (0x1) SlotDebugData { name: "[1]", ty: UInt<1> }, - src: StatePartIndex(42), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, + dest: StatePartIndex(30), // (0x1) SlotDebugData { name: "[1]", ty: UInt<1> }, + src: StatePartIndex(34), // (0x1) SlotDebugData { name: "", ty: UInt<1> }, }, 75: SliceInt { - dest: StatePartIndex(43), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, - src: StatePartIndex(39), // (0xf) SlotDebugData { name: "", ty: UInt<4> }, + dest: StatePartIndex(35), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(31), // (0xf) SlotDebugData { name: "", ty: UInt<4> }, start: 2, len: 2, }, 76: CastToSInt { - dest: StatePartIndex(44), // (-0x1) SlotDebugData { name: "", ty: SInt<2> }, - src: StatePartIndex(43), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(36), // (-0x1) SlotDebugData { name: "", ty: SInt<2> }, + src: StatePartIndex(35), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, dest_width: 2, }, 77: Copy { - dest: StatePartIndex(34), // (0x1) SlotDebugData { name: ".a[0]", ty: UInt<1> }, - src: StatePartIndex(37), // (0x1) SlotDebugData { name: "[0]", ty: UInt<1> }, + dest: StatePartIndex(26), // (0x1) SlotDebugData { name: ".a[0]", ty: UInt<1> }, + src: StatePartIndex(29), // (0x1) SlotDebugData { name: "[0]", ty: UInt<1> }, }, 78: Copy { - dest: StatePartIndex(35), // (0x1) SlotDebugData { name: ".a[1]", ty: UInt<1> }, - src: StatePartIndex(38), // (0x1) SlotDebugData { name: "[1]", ty: UInt<1> }, + dest: StatePartIndex(27), // (0x1) SlotDebugData { name: ".a[1]", ty: UInt<1> }, + src: StatePartIndex(30), // (0x1) SlotDebugData { name: "[1]", ty: UInt<1> }, }, 79: Copy { - dest: StatePartIndex(36), // (-0x1) SlotDebugData { name: ".b", ty: SInt<2> }, - src: StatePartIndex(44), // (-0x1) SlotDebugData { name: "", ty: SInt<2> }, + dest: StatePartIndex(28), // (-0x1) SlotDebugData { name: ".b", ty: SInt<2> }, + src: StatePartIndex(36), // (-0x1) SlotDebugData { name: "", ty: SInt<2> }, }, 80: Shl { - dest: StatePartIndex(106), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, - lhs: StatePartIndex(35), // (0x1) SlotDebugData { name: ".a[1]", ty: UInt<1> }, + dest: StatePartIndex(98), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, + lhs: StatePartIndex(27), // (0x1) SlotDebugData { name: ".a[1]", ty: UInt<1> }, rhs: 1, }, 81: Or { - dest: StatePartIndex(107), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, - lhs: StatePartIndex(34), // (0x1) SlotDebugData { name: ".a[0]", ty: UInt<1> }, - rhs: StatePartIndex(106), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(99), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + lhs: StatePartIndex(26), // (0x1) SlotDebugData { name: ".a[0]", ty: UInt<1> }, + rhs: StatePartIndex(98), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, }, 82: CastToUInt { - dest: StatePartIndex(108), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, - src: StatePartIndex(36), // (-0x1) SlotDebugData { name: ".b", ty: SInt<2> }, + dest: StatePartIndex(100), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(28), // (-0x1) SlotDebugData { name: ".b", ty: SInt<2> }, dest_width: 2, }, 83: Shl { - dest: StatePartIndex(109), // (0xc) SlotDebugData { name: "", ty: UInt<4> }, - lhs: StatePartIndex(108), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + dest: StatePartIndex(101), // (0xc) SlotDebugData { name: "", ty: UInt<4> }, + lhs: StatePartIndex(100), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, rhs: 2, }, 84: Or { - dest: StatePartIndex(110), // (0xf) SlotDebugData { name: "", ty: UInt<4> }, - lhs: StatePartIndex(107), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, - rhs: StatePartIndex(109), // (0xc) SlotDebugData { name: "", ty: UInt<4> }, + dest: StatePartIndex(102), // (0xf) SlotDebugData { name: "", ty: UInt<4> }, + lhs: StatePartIndex(99), // (0x3) SlotDebugData { name: "", ty: UInt<2> }, + rhs: StatePartIndex(101), // (0xc) SlotDebugData { name: "", ty: UInt<4> }, }, - // at: module-XXXXXXXXXX.rs:11:1 + // at: module-XXXXXXXXXX.rs:9:1 85: AndBigWithSmallImmediate { - dest: StatePartIndex(6), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} }, - lhs: StatePartIndex(23), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + dest: StatePartIndex(5), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} }, + lhs: StatePartIndex(15), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, rhs: 0x3, }, - // at: module-XXXXXXXXXX.rs:19:1 + // at: module-XXXXXXXXXX.rs:17:1 86: BranchIfSmallNeImmediate { target: 89, - lhs: StatePartIndex(6), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} }, + lhs: StatePartIndex(5), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} }, rhs: 0x0, }, - // at: module-XXXXXXXXXX.rs:20:1 + // at: module-XXXXXXXXXX.rs:18:1 87: Copy { dest: StatePartIndex(5), // (0x2) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::which_out", ty: UInt<2> }, - src: StatePartIndex(45), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(37), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, }, - // at: module-XXXXXXXXXX.rs:21:1 + // at: module-XXXXXXXXXX.rs:19:1 88: Copy { dest: StatePartIndex(6), // (0xf) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::data_out", ty: UInt<4> }, - src: StatePartIndex(90), // (0x0) SlotDebugData { name: "", ty: UInt<4> }, + src: StatePartIndex(82), // (0x0) SlotDebugData { name: "", ty: UInt<4> }, }, - // at: module-XXXXXXXXXX.rs:19:1 + // at: module-XXXXXXXXXX.rs:17:1 89: BranchIfSmallNeImmediate { target: 93, - lhs: StatePartIndex(6), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} }, + lhs: StatePartIndex(5), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} }, rhs: 0x1, }, - // at: module-XXXXXXXXXX.rs:22:1 + // at: module-XXXXXXXXXX.rs:20:1 90: Copy { dest: StatePartIndex(5), // (0x2) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::which_out", ty: UInt<2> }, - src: StatePartIndex(47), // (0x1) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(39), // (0x1) SlotDebugData { name: "", ty: UInt<2> }, }, - // at: module-XXXXXXXXXX.rs:23:1 + // at: module-XXXXXXXXXX.rs:21:1 91: Copy { dest: StatePartIndex(6), // (0xf) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::data_out", ty: UInt<4> }, - src: StatePartIndex(94), // (0x3) SlotDebugData { name: "", ty: UInt<4> }, + src: StatePartIndex(86), // (0x3) SlotDebugData { name: "", ty: UInt<4> }, }, - // at: module-XXXXXXXXXX.rs:24:1 + // at: module-XXXXXXXXXX.rs:22:1 92: Copy { dest: StatePartIndex(7), // (0x0) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::b_out", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, - src: StatePartIndex(105), // (0x7) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, + src: StatePartIndex(97), // (0x7) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, }, - // at: module-XXXXXXXXXX.rs:19:1 + // at: module-XXXXXXXXXX.rs:17:1 93: BranchIfSmallNeImmediate { target: 96, - lhs: StatePartIndex(6), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} }, + lhs: StatePartIndex(5), // (0x2 2) SlotDebugData { name: "", ty: Enum {A, B, C} }, rhs: 0x2, }, - // at: module-XXXXXXXXXX.rs:25:1 + // at: module-XXXXXXXXXX.rs:23:1 94: Copy { dest: StatePartIndex(5), // (0x2) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::which_out", ty: UInt<2> }, - src: StatePartIndex(70), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, + src: StatePartIndex(62), // (0x2) SlotDebugData { name: "", ty: UInt<2> }, }, - // at: module-XXXXXXXXXX.rs:26:1 + // at: module-XXXXXXXXXX.rs:24:1 95: Copy { dest: StatePartIndex(6), // (0xf) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::data_out", ty: UInt<4> }, - src: StatePartIndex(110), // (0xf) SlotDebugData { name: "", ty: UInt<4> }, + src: StatePartIndex(102), // (0xf) SlotDebugData { name: "", ty: UInt<4> }, }, - // at: module-XXXXXXXXXX.rs:11:1 + // at: module-XXXXXXXXXX.rs:9:1 96: IsNonZeroDestIsSmall { - dest: StatePartIndex(5), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + dest: StatePartIndex(4), // (0x0 0) SlotDebugData { name: "", ty: Bool }, src: StatePartIndex(1), // (0x0) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::cd.rst", ty: SyncReset }, }, // at: module-XXXXXXXXXX.rs:1:1 97: Const { - dest: StatePartIndex(25), // (0x0) SlotDebugData { name: "", ty: UInt<6> }, + dest: StatePartIndex(17), // (0x0) SlotDebugData { name: "", ty: UInt<6> }, value: 0x0, }, 98: Copy { - dest: StatePartIndex(26), // (0x0) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, - src: StatePartIndex(25), // (0x0) SlotDebugData { name: "", ty: UInt<6> }, + dest: StatePartIndex(18), // (0x0) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + src: StatePartIndex(17), // (0x0) SlotDebugData { name: "", ty: UInt<6> }, }, - // at: module-XXXXXXXXXX.rs:12:1 + // at: module-XXXXXXXXXX.rs:10:1 99: BranchIfZero { target: 107, value: StatePartIndex(2), // (0x1) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::en", ty: Bool }, }, - // at: module-XXXXXXXXXX.rs:13:1 + // at: module-XXXXXXXXXX.rs:11:1 100: BranchIfZero { target: 102, - value: StatePartIndex(46), // (0x0) SlotDebugData { name: "", ty: Bool }, + value: StatePartIndex(38), // (0x0) SlotDebugData { name: "", ty: Bool }, }, - // at: module-XXXXXXXXXX.rs:14:1 + // at: module-XXXXXXXXXX.rs:12:1 101: Copy { - dest: StatePartIndex(24), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg$next", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, - src: StatePartIndex(26), // (0x0) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, - }, - // at: module-XXXXXXXXXX.rs:13:1 - 102: BranchIfNonZero { - target: 107, - value: StatePartIndex(46), // (0x0) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:15:1 - 103: BranchIfZero { - target: 105, - value: StatePartIndex(48), // (0x0) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:16:1 - 104: Copy { - dest: StatePartIndex(24), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg$next", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, - src: StatePartIndex(65), // (0xd) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, - }, - // at: module-XXXXXXXXXX.rs:15:1 - 105: BranchIfNonZero { - target: 107, - value: StatePartIndex(48), // (0x0) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:17:1 - 106: Copy { - dest: StatePartIndex(24), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg$next", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, - src: StatePartIndex(87), // (0x3e) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + dest: StatePartIndex(16), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg$next", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + src: StatePartIndex(18), // (0x0) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, }, // at: module-XXXXXXXXXX.rs:11:1 + 102: BranchIfNonZero { + target: 107, + value: StatePartIndex(38), // (0x0) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:13:1 + 103: BranchIfZero { + target: 105, + value: StatePartIndex(40), // (0x0) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:14:1 + 104: Copy { + dest: StatePartIndex(16), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg$next", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + src: StatePartIndex(57), // (0xd) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + }, + // at: module-XXXXXXXXXX.rs:13:1 + 105: BranchIfNonZero { + target: 107, + value: StatePartIndex(40), // (0x0) SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:15:1 + 106: Copy { + dest: StatePartIndex(16), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg$next", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + src: StatePartIndex(79), // (0x3e) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + }, + // at: module-XXXXXXXXXX.rs:9:1 107: IsNonZeroDestIsSmall { - dest: StatePartIndex(4), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + dest: StatePartIndex(3), // (0x1 1) SlotDebugData { name: "", ty: Bool }, src: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::cd.clk", ty: Clock }, }, 108: AndSmall { - dest: StatePartIndex(3), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(4), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(2), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + dest: StatePartIndex(2), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(3), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + rhs: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, }, - // at: module-XXXXXXXXXX.rs:10:1 + // at: module-XXXXXXXXXX.rs:1:1 109: Copy { - dest: StatePartIndex(15), // (0x0) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::b2_out", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, - src: StatePartIndex(7), // (0x0) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::b_out", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 110: Copy { - dest: StatePartIndex(18), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, - src: StatePartIndex(15), // (0x0) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::b2_out", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, - }, - 111: SliceInt { - dest: StatePartIndex(19), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, - src: StatePartIndex(18), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, - start: 1, - len: 2, - }, - 112: SliceInt { - dest: StatePartIndex(20), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(19), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, - start: 0, - len: 1, - }, - 113: SliceInt { - dest: StatePartIndex(21), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(19), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, - start: 1, - len: 1, - }, - 114: Copy { - dest: StatePartIndex(22), // (0x0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(21), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - }, - 115: Copy { - dest: StatePartIndex(16), // (0x0) SlotDebugData { name: ".0", ty: UInt<1> }, - src: StatePartIndex(20), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - }, - 116: Copy { - dest: StatePartIndex(17), // (0x0) SlotDebugData { name: ".1", ty: Bool }, - src: StatePartIndex(22), // (0x0) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:9:1 - 117: AndBigWithSmallImmediate { - dest: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} }, - lhs: StatePartIndex(15), // (0x0) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::b2_out", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, - rhs: 0x1, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 118: Copy { dest: StatePartIndex(10), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, src: StatePartIndex(7), // (0x0) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::b_out", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, }, - 119: SliceInt { + 110: SliceInt { dest: StatePartIndex(11), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, src: StatePartIndex(10), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, start: 1, len: 2, }, - 120: SliceInt { + 111: SliceInt { dest: StatePartIndex(12), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, src: StatePartIndex(11), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, start: 0, len: 1, }, - 121: SliceInt { + 112: SliceInt { dest: StatePartIndex(13), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, src: StatePartIndex(11), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, start: 1, len: 1, }, - 122: Copy { + 113: Copy { dest: StatePartIndex(14), // (0x0) SlotDebugData { name: "", ty: Bool }, src: StatePartIndex(13), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, }, - 123: Copy { + 114: Copy { dest: StatePartIndex(8), // (0x0) SlotDebugData { name: ".0", ty: UInt<1> }, src: StatePartIndex(12), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, }, - 124: Copy { + 115: Copy { dest: StatePartIndex(9), // (0x0) SlotDebugData { name: ".1", ty: Bool }, src: StatePartIndex(14), // (0x0) SlotDebugData { name: "", ty: Bool }, }, // at: module-XXXXXXXXXX.rs:8:1 - 125: AndBigWithSmallImmediate { + 116: AndBigWithSmallImmediate { dest: StatePartIndex(0), // (0x0 0) SlotDebugData { name: "", ty: Enum {HdlNone, HdlSome} }, lhs: StatePartIndex(7), // (0x0) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::b_out", ty: Enum {HdlNone, HdlSome(Bundle {0: UInt<1>, 1: Bool})} }, rhs: 0x1, }, - // at: module-XXXXXXXXXX.rs:11:1 - 126: BranchIfSmallZero { - target: 131, - value: StatePartIndex(3), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + // at: module-XXXXXXXXXX.rs:9:1 + 117: BranchIfSmallZero { + target: 122, + value: StatePartIndex(2), // (0x0 0) SlotDebugData { name: "", ty: Bool }, }, - 127: BranchIfSmallNonZero { - target: 130, - value: StatePartIndex(5), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + 118: BranchIfSmallNonZero { + target: 121, + value: StatePartIndex(4), // (0x0 0) SlotDebugData { name: "", ty: Bool }, }, - 128: Copy { - dest: StatePartIndex(23), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, - src: StatePartIndex(24), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg$next", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + 119: Copy { + dest: StatePartIndex(15), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + src: StatePartIndex(16), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg$next", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, }, - 129: Branch { - target: 131, + 120: Branch { + target: 122, }, - 130: Copy { - dest: StatePartIndex(23), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, - src: StatePartIndex(26), // (0x0) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + 121: Copy { + dest: StatePartIndex(15), // (0x3e) SlotDebugData { name: "InstantiatedModule(enums: enums).enums::the_reg", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, + src: StatePartIndex(18), // (0x0) SlotDebugData { name: "", ty: Enum {A, B(Bundle {0: UInt<1>, 1: Bool}), C(Bundle {a: Array, 2>, b: SInt<2>})} }, }, - 131: XorSmallImmediate { - dest: StatePartIndex(2), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(4), // (0x1 1) SlotDebugData { name: "", ty: Bool }, + 122: XorSmallImmediate { + dest: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(3), // (0x1 1) SlotDebugData { name: "", ty: Bool }, rhs: 0x1, }, // at: module-XXXXXXXXXX.rs:1:1 - 132: Return, + 123: Return, ], .. }, - pc: 132, + pc: 123, memory_write_log: [], memories: StatePart { value: [], @@ -1189,7 +1095,6 @@ Simulation { 0, 0, 0, - 0, 1, 0, 2, @@ -1212,14 +1117,6 @@ Simulation { 0, 0, 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, 62, 62, 0, @@ -1310,9 +1207,6 @@ Simulation { 15, ], }, - sim_only_slots: StatePart { - value: [], - }, }, io: Instance { name: ::enums, @@ -1321,142 +1215,389 @@ Simulation { .. }, }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.b_out: CompiledValue { + layout: CompiledTypeLayout { + ty: Enum { + HdlNone, + HdlSome(Bundle {0: UInt<1>, 1: Bool}), }, - }.cd, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(enums: enums).enums::b_out", + ty: Enum { + HdlNone, + HdlSome(Bundle {0: UInt<1>, 1: Bool}), + }, + }, + ], + .. + }, }, - }.en, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.which_in, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.data_in, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.which_out, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.data_out, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.b_out, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.b2_out, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.b2_out, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.b_out, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.cd, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.cd.clk, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.cd.rst, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.data_in, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.data_out, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.en, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.which_in, - Instance { - name: ::enums, - instantiated: Module { - name: enums, - .. - }, - }.which_out, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 7, len: 1 }, + }, + write: None, + }, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.cd: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + rst: SyncReset, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(enums: enums).enums::cd.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(enums: enums).enums::cd.rst", + ty: SyncReset, + }, + ], + .. + }, + }, + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: SyncReset, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 2 }, + }, + write: None, + }, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.cd.clk: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, + }, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.cd.rst: CompiledValue { + layout: CompiledTypeLayout { + ty: SyncReset, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 1, len: 1 }, + }, + write: None, + }, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.data_in: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<4>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(enums: enums).enums::data_in", + ty: UInt<4>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 4, len: 1 }, + }, + write: None, + }, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.data_out: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<4>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(enums: enums).enums::data_out", + ty: UInt<4>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 6, len: 1 }, + }, + write: None, + }, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.en: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(enums: enums).enums::en", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 2, len: 1 }, + }, + write: None, + }, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.which_in: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<2>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(enums: enums).enums::which_in", + ty: UInt<2>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 3, len: 1 }, + }, + write: None, + }, + Instance { + name: ::enums, + instantiated: Module { + name: enums, + .. + }, + }.which_out: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<2>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(enums: enums).enums::which_out", + ty: UInt<2>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 5, len: 1 }, + }, + write: None, }, - did_initial_settle: true, }, - extern_modules: [], - state_ready_to_run: false, + made_initial_step: true, + needs_settle: false, trace_decls: TraceModule { name: "enums", children: [ @@ -1596,22 +1737,23 @@ Simulation { }, flow: Sink, }, - TraceModuleIO { - name: "b2_out", + TraceReg { + name: "the_reg", child: TraceEnumWithFields { - name: "b2_out", + name: "the_reg", discriminant: TraceEnumDiscriminant { location: TraceScalarId(10), name: "$tag", ty: Enum { - HdlNone, - HdlSome(Bundle {0: UInt<1>, 1: Bool}), + A, + B(Bundle {0: UInt<1>, 1: Bool}), + C(Bundle {a: Array, 2>, b: SInt<2>}), }, - flow: Sink, + flow: Duplex, }, non_empty_fields: [ TraceBundle { - name: "HdlSome", + name: "B", fields: [ TraceUInt { location: TraceScalarId(11), @@ -1633,57 +1775,6 @@ Simulation { }, flow: Source, }, - ], - ty: Enum { - HdlNone, - HdlSome(Bundle {0: UInt<1>, 1: Bool}), - }, - flow: Sink, - }, - ty: Enum { - HdlNone, - HdlSome(Bundle {0: UInt<1>, 1: Bool}), - }, - flow: Sink, - }, - TraceReg { - name: "the_reg", - child: TraceEnumWithFields { - name: "the_reg", - discriminant: TraceEnumDiscriminant { - location: TraceScalarId(13), - name: "$tag", - ty: Enum { - A, - B(Bundle {0: UInt<1>, 1: Bool}), - C(Bundle {a: Array, 2>, b: SInt<2>}), - }, - flow: Duplex, - }, - non_empty_fields: [ - TraceBundle { - name: "B", - fields: [ - TraceUInt { - location: TraceScalarId(14), - name: "0", - ty: UInt<1>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(15), - name: "1", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - 0: UInt<1>, - /* offset = 1 */ - 1: Bool, - }, - flow: Source, - }, TraceBundle { name: "C", fields: [ @@ -1691,13 +1782,13 @@ Simulation { name: "a", elements: [ TraceUInt { - location: TraceScalarId(16), + location: TraceScalarId(13), name: "[0]", ty: UInt<1>, flow: Source, }, TraceUInt { - location: TraceScalarId(17), + location: TraceScalarId(14), name: "[1]", ty: UInt<1>, flow: Source, @@ -1707,7 +1798,7 @@ Simulation { flow: Source, }, TraceSInt { - location: TraceScalarId(18), + location: TraceScalarId(15), name: "b", ty: SInt<2>, flow: Source, @@ -1830,36 +1921,7 @@ Simulation { SimTrace { id: TraceScalarId(10), kind: EnumDiscriminant { - index: StatePartIndex(1), - ty: Enum { - HdlNone, - HdlSome(Bundle {0: UInt<1>, 1: Bool}), - }, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(11), - kind: BigUInt { - index: StatePartIndex(16), - ty: UInt<1>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(12), - kind: BigBool { - index: StatePartIndex(17), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(13), - kind: EnumDiscriminant { - index: StatePartIndex(6), + index: StatePartIndex(5), ty: Enum { A, B(Bundle {0: UInt<1>, 1: Bool}), @@ -1869,6 +1931,32 @@ Simulation { state: 0x2, last_state: 0x2, }, + SimTrace { + id: TraceScalarId(11), + kind: BigUInt { + index: StatePartIndex(19), + ty: UInt<1>, + }, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(12), + kind: BigBool { + index: StatePartIndex(20), + }, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(13), + kind: BigUInt { + index: StatePartIndex(26), + ty: UInt<1>, + }, + state: 0x1, + last_state: 0x1, + }, SimTrace { id: TraceScalarId(14), kind: BigUInt { @@ -1880,34 +1968,8 @@ Simulation { }, SimTrace { id: TraceScalarId(15), - kind: BigBool { - index: StatePartIndex(28), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(16), - kind: BigUInt { - index: StatePartIndex(34), - ty: UInt<1>, - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(17), - kind: BigUInt { - index: StatePartIndex(35), - ty: UInt<1>, - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(18), kind: BigSInt { - index: StatePartIndex(36), + index: StatePartIndex(28), ty: SInt<2>, }, state: 0x3, @@ -1926,7 +1988,7 @@ Simulation { ], instant: 16 μs, clocks_triggered: [ - StatePartIndex(3), + StatePartIndex(2), ], .. } \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/enums.vcd b/crates/fayalite/tests/sim/expected/enums.vcd index aff867b..07cbd32 100644 --- a/crates/fayalite/tests/sim/expected/enums.vcd +++ b/crates/fayalite/tests/sim/expected/enums.vcd @@ -16,25 +16,18 @@ $var wire 1 ) \0 $end $var wire 1 * \1 $end $upscope $end $upscope $end -$scope struct b2_out $end -$var string 1 + \$tag $end -$scope struct HdlSome $end -$var wire 1 , \0 $end -$var wire 1 - \1 $end -$upscope $end -$upscope $end $scope struct the_reg $end -$var string 1 . \$tag $end +$var string 1 + \$tag $end $scope struct B $end -$var reg 1 / \0 $end -$var reg 1 0 \1 $end +$var reg 1 , \0 $end +$var reg 1 - \1 $end $upscope $end $scope struct C $end $scope struct a $end -$var reg 1 1 \[0] $end -$var reg 1 2 \[1] $end +$var reg 1 . \[0] $end +$var reg 1 / \[1] $end $upscope $end -$var reg 2 3 b $end +$var reg 2 0 b $end $upscope $end $upscope $end $upscope $end @@ -50,15 +43,12 @@ b0 ' sHdlNone\x20(0) ( 0) 0* -sHdlNone\x20(0) + +sA\x20(0) + 0, 0- -sA\x20(0) . +0. 0/ -00 -01 -02 -b0 3 +b0 0 $end #1000000 1! @@ -76,8 +66,7 @@ b1 $ 1! b1 & sHdlSome\x20(1) ( -sHdlSome\x20(1) + -sB\x20(1) . +sB\x20(1) + #6000000 0# b0 $ @@ -96,10 +85,8 @@ b11 ' 1* 1, 1- +1. 1/ -10 -11 -12 #10000000 0! #11000000 @@ -114,11 +101,8 @@ b1111 ' sHdlNone\x20(0) ( 0) 0* -sHdlNone\x20(0) + -0, -0- -sC\x20(2) . -b11 3 +sC\x20(2) + +b11 0 #14000000 0! #15000000 diff --git a/crates/fayalite/tests/sim/expected/extern_module.txt b/crates/fayalite/tests/sim/expected/extern_module.txt deleted file mode 100644 index e09a767..0000000 --- a/crates/fayalite/tests/sim/expected/extern_module.txt +++ /dev/null @@ -1,253 +0,0 @@ -Simulation { - state: State { - insns: Insns { - state_layout: StateLayout { - ty: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 2, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(extern_module: extern_module).extern_module::i", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(extern_module: extern_module).extern_module::o", - ty: Bool, - }, - ], - .. - }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - memories: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - insns: [ - // at: module-XXXXXXXXXX.rs:1:1 - 0: Return, - ], - .. - }, - pc: 0, - memory_write_log: [], - memories: StatePart { - value: [], - }, - small_slots: StatePart { - value: [], - }, - big_slots: StatePart { - value: [ - 1, - 1, - ], - }, - sim_only_slots: StatePart { - value: [], - }, - }, - io: Instance { - name: ::extern_module, - instantiated: Module { - name: extern_module, - .. - }, - }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::extern_module, - instantiated: Module { - name: extern_module, - .. - }, - }.i, - Instance { - name: ::extern_module, - instantiated: Module { - name: extern_module, - .. - }, - }.o, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::extern_module, - instantiated: Module { - name: extern_module, - .. - }, - }.i, - Instance { - name: ::extern_module, - instantiated: Module { - name: extern_module, - .. - }, - }.o, - }, - did_initial_settle: true, - }, - extern_modules: [ - SimulationExternModuleState { - module_state: SimulationModuleState { - base_targets: [ - ModuleIO { - name: extern_module::i, - is_input: true, - ty: Bool, - .. - }, - ModuleIO { - name: extern_module::o, - is_input: false, - ty: Bool, - .. - }, - ], - uninitialized_ios: {}, - io_targets: { - ModuleIO { - name: extern_module::i, - is_input: true, - ty: Bool, - .. - }, - ModuleIO { - name: extern_module::o, - is_input: false, - ty: Bool, - .. - }, - }, - did_initial_settle: true, - }, - sim: ExternModuleSimulation { - generator: SimGeneratorFn { - args: ( - ModuleIO { - name: extern_module::i, - is_input: true, - ty: Bool, - .. - }, - ModuleIO { - name: extern_module::o, - is_input: false, - ty: Bool, - .. - }, - ), - f: ..., - }, - sim_io_to_generator_map: { - ModuleIO { - name: extern_module::i, - is_input: true, - ty: Bool, - .. - }: ModuleIO { - name: extern_module::i, - is_input: true, - ty: Bool, - .. - }, - ModuleIO { - name: extern_module::o, - is_input: false, - ty: Bool, - .. - }: ModuleIO { - name: extern_module::o, - is_input: false, - ty: Bool, - .. - }, - }, - source_location: SourceLocation( - module-XXXXXXXXXX.rs:4:1, - ), - }, - running_generator: Some( - ..., - ), - wait_targets: { - Instant( - 20.500000000000 μs, - ), - }, - }, - ], - state_ready_to_run: false, - trace_decls: TraceModule { - name: "extern_module", - children: [ - TraceModuleIO { - name: "i", - child: TraceBool { - location: TraceScalarId(0), - name: "i", - flow: Source, - }, - ty: Bool, - flow: Source, - }, - TraceModuleIO { - name: "o", - child: TraceBool { - location: TraceScalarId(1), - name: "o", - flow: Sink, - }, - ty: Bool, - flow: Sink, - }, - ], - }, - traces: [ - SimTrace { - id: TraceScalarId(0), - kind: BigBool { - index: StatePartIndex(0), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(1), - kind: BigBool { - index: StatePartIndex(1), - }, - state: 0x1, - last_state: 0x1, - }, - ], - trace_memories: {}, - trace_writers: [ - Running( - VcdWriter { - finished_init: true, - timescale: 1 ps, - .. - }, - ), - ], - instant: 20 μs, - clocks_triggered: [], - .. -} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/extern_module.vcd b/crates/fayalite/tests/sim/expected/extern_module.vcd deleted file mode 100644 index e026a50..0000000 --- a/crates/fayalite/tests/sim/expected/extern_module.vcd +++ /dev/null @@ -1,51 +0,0 @@ -$timescale 1 ps $end -$scope module extern_module $end -$var wire 1 ! i $end -$var wire 1 " o $end -$upscope $end -$enddefinitions $end -$dumpvars -0! -1" -$end -#500000 -#1500000 -0" -#2500000 -1" -#3500000 -0" -#4500000 -1" -#5500000 -0" -#6500000 -1" -#7500000 -0" -#8500000 -1" -#9500000 -0" -#10000000 -1! -#10500000 -#11500000 -1" -#12500000 -0" -#13500000 -1" -#14500000 -0" -#15500000 -1" -#16500000 -0" -#17500000 -1" -#18500000 -0" -#19500000 -1" -#20000000 diff --git a/crates/fayalite/tests/sim/expected/extern_module2.txt b/crates/fayalite/tests/sim/expected/extern_module2.txt deleted file mode 100644 index 1023b2b..0000000 --- a/crates/fayalite/tests/sim/expected/extern_module2.txt +++ /dev/null @@ -1,362 +0,0 @@ -Simulation { - state: State { - insns: Insns { - state_layout: StateLayout { - ty: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 3, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(extern_module2: extern_module2).extern_module2::en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(extern_module2: extern_module2).extern_module2::clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(extern_module2: extern_module2).extern_module2::o", - ty: UInt<8>, - }, - ], - .. - }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - memories: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - insns: [ - // at: module-XXXXXXXXXX.rs:1:1 - 0: Return, - ], - .. - }, - pc: 0, - memory_write_log: [], - memories: StatePart { - value: [], - }, - small_slots: StatePart { - value: [], - }, - big_slots: StatePart { - value: [ - 0, - 1, - 101, - ], - }, - sim_only_slots: StatePart { - value: [], - }, - }, - io: Instance { - name: ::extern_module2, - instantiated: Module { - name: extern_module2, - .. - }, - }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::extern_module2, - instantiated: Module { - name: extern_module2, - .. - }, - }.en, - Instance { - name: ::extern_module2, - instantiated: Module { - name: extern_module2, - .. - }, - }.clk, - Instance { - name: ::extern_module2, - instantiated: Module { - name: extern_module2, - .. - }, - }.o, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::extern_module2, - instantiated: Module { - name: extern_module2, - .. - }, - }.clk, - Instance { - name: ::extern_module2, - instantiated: Module { - name: extern_module2, - .. - }, - }.en, - Instance { - name: ::extern_module2, - instantiated: Module { - name: extern_module2, - .. - }, - }.o, - }, - did_initial_settle: true, - }, - extern_modules: [ - SimulationExternModuleState { - module_state: SimulationModuleState { - base_targets: [ - ModuleIO { - name: extern_module2::en, - is_input: true, - ty: Bool, - .. - }, - ModuleIO { - name: extern_module2::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: extern_module2::o, - is_input: false, - ty: UInt<8>, - .. - }, - ], - uninitialized_ios: {}, - io_targets: { - ModuleIO { - name: extern_module2::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: extern_module2::en, - is_input: true, - ty: Bool, - .. - }, - ModuleIO { - name: extern_module2::o, - is_input: false, - ty: UInt<8>, - .. - }, - }, - did_initial_settle: true, - }, - sim: ExternModuleSimulation { - generator: SimGeneratorFn { - args: ( - ModuleIO { - name: extern_module2::en, - is_input: true, - ty: Bool, - .. - }, - ModuleIO { - name: extern_module2::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: extern_module2::o, - is_input: false, - ty: UInt<8>, - .. - }, - ), - f: ..., - }, - sim_io_to_generator_map: { - ModuleIO { - name: extern_module2::clk, - is_input: true, - ty: Clock, - .. - }: ModuleIO { - name: extern_module2::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: extern_module2::en, - is_input: true, - ty: Bool, - .. - }: ModuleIO { - name: extern_module2::en, - is_input: true, - ty: Bool, - .. - }, - ModuleIO { - name: extern_module2::o, - is_input: false, - ty: UInt<8>, - .. - }: ModuleIO { - name: extern_module2::o, - is_input: false, - ty: UInt<8>, - .. - }, - }, - source_location: SourceLocation( - module-XXXXXXXXXX.rs:5:1, - ), - }, - running_generator: Some( - ..., - ), - wait_targets: { - Change { - key: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(extern_module2: extern_module2).extern_module2::clk", - ty: Clock, - }, - ], - .. - }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 1, len: 1 }, - sim_only_slots: StatePartIndexRange { start: 0, len: 0 }, - }, - write: None, - }, - value: SimValue { - ty: Clock, - value: OpaqueSimValue { - bits: 0x1_u1, - sim_only_values: [], - }, - }, - }, - }, - }, - ], - state_ready_to_run: false, - trace_decls: TraceModule { - name: "extern_module2", - children: [ - TraceModuleIO { - name: "en", - child: TraceBool { - location: TraceScalarId(0), - name: "en", - flow: Source, - }, - ty: Bool, - flow: Source, - }, - TraceModuleIO { - name: "clk", - child: TraceClock { - location: TraceScalarId(1), - name: "clk", - flow: Source, - }, - ty: Clock, - flow: Source, - }, - TraceModuleIO { - name: "o", - child: TraceUInt { - location: TraceScalarId(2), - name: "o", - ty: UInt<8>, - flow: Sink, - }, - ty: UInt<8>, - flow: Sink, - }, - ], - }, - traces: [ - SimTrace { - id: TraceScalarId(0), - kind: BigBool { - index: StatePartIndex(0), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(1), - kind: BigClock { - index: StatePartIndex(1), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(2), - kind: BigUInt { - index: StatePartIndex(2), - ty: UInt<8>, - }, - state: 0x65, - last_state: 0x65, - }, - ], - trace_memories: {}, - trace_writers: [ - Running( - VcdWriter { - finished_init: true, - timescale: 1 ps, - .. - }, - ), - ], - instant: 60 μs, - clocks_triggered: [], - .. -} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/extern_module2.vcd b/crates/fayalite/tests/sim/expected/extern_module2.vcd deleted file mode 100644 index 464f4bd..0000000 --- a/crates/fayalite/tests/sim/expected/extern_module2.vcd +++ /dev/null @@ -1,150 +0,0 @@ -$timescale 1 ps $end -$scope module extern_module2 $end -$var wire 1 ! en $end -$var wire 1 " clk $end -$var wire 8 # o $end -$upscope $end -$enddefinitions $end -$dumpvars -1! -0" -b1001000 # -$end -#1000000 -1" -b1100101 # -#2000000 -0" -#3000000 -1" -b1101100 # -#4000000 -0" -#5000000 -1" -#6000000 -0" -#7000000 -1" -b1101111 # -#8000000 -0" -#9000000 -1" -b101100 # -#10000000 -0! -0" -#11000000 -1" -#12000000 -0" -#13000000 -1" -#14000000 -0" -#15000000 -1" -#16000000 -0" -#17000000 -1" -#18000000 -0" -#19000000 -1" -#20000000 -1! -0" -#21000000 -1" -b100000 # -#22000000 -0" -#23000000 -1" -b1010111 # -#24000000 -0" -#25000000 -1" -b1101111 # -#26000000 -0" -#27000000 -1" -b1110010 # -#28000000 -0" -#29000000 -1" -b1101100 # -#30000000 -0! -0" -#31000000 -1" -#32000000 -0" -#33000000 -1" -#34000000 -0" -#35000000 -1" -#36000000 -0" -#37000000 -1" -#38000000 -0" -#39000000 -1" -#40000000 -1! -0" -#41000000 -1" -b1100100 # -#42000000 -0" -#43000000 -1" -b100001 # -#44000000 -0" -#45000000 -1" -b1010 # -#46000000 -0" -#47000000 -1" -b1001000 # -#48000000 -0" -#49000000 -1" -b1100101 # -#50000000 -0! -0" -#51000000 -1" -#52000000 -0" -#53000000 -1" -#54000000 -0" -#55000000 -1" -#56000000 -0" -#57000000 -1" -#58000000 -0" -#59000000 -1" -#60000000 diff --git a/crates/fayalite/tests/sim/expected/many_memories.txt b/crates/fayalite/tests/sim/expected/many_memories.txt deleted file mode 100644 index fbbc581..0000000 --- a/crates/fayalite/tests/sim/expected/many_memories.txt +++ /dev/null @@ -1,7782 +0,0 @@ -Simulation { - state: State { - insns: Insns { - state_layout: StateLayout { - ty: TypeLayout { - small_slots: StatePartLayout { - len: 96, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - big_slots: StatePartLayout { - len: 160, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[0].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[0].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[0].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[0].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[1].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[1].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[1].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[1].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[2].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[2].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[2].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[2].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[3].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[3].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[3].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[3].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[4].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[4].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[4].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[4].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[5].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[5].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[5].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[5].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[6].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[6].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[6].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[6].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[7].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[7].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[7].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::r[7].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[0].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[0].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[0].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[0].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[0].mask", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[1].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[1].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[1].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[1].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[1].mask", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[2].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[2].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[2].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[2].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[2].mask", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[3].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[3].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[3].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[3].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[3].mask", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[4].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[4].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[4].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[4].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[4].mask", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[5].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[5].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[5].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[5].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[5].mask", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[6].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[6].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[6].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[6].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[6].mask", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[7].addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[7].en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[7].clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[7].data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::w[7].mask", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::r0.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::r0.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::r0.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::r0.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.mask", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::r0.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::r0.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::r0.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::r0.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.mask", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::r0.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::r0.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::r0.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::r0.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.mask", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::r0.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::r0.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::r0.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::r0.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.mask", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::r0.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::r0.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::r0.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::r0.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.mask", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::r0.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::r0.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::r0.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::r0.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.mask", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::r0.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::r0.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::r0.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::r0.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.mask", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::r0.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::r0.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::r0.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::r0.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.addr", - ty: UInt<4>, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.en", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.data", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.mask", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - memories: StatePartLayout { - len: 8, - debug_data: [ - (), - (), - (), - (), - (), - (), - (), - (), - ], - layout_data: [ - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x0, - [0x1]: 0x0, - [0x2]: 0x0, - [0x3]: 0x0, - [0x4]: 0x0, - [0x5]: 0x0, - [0x6]: 0x0, - [0x7]: 0x0, - [0x8]: 0x0, - [0x9]: 0x0, - [0xa]: 0x0, - [0xb]: 0x0, - [0xc]: 0x0, - [0xd]: 0x0, - [0xe]: 0x0, - [0xf]: 0x0, - ], - }, - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x1, - [0x1]: 0x0, - [0x2]: 0x0, - [0x3]: 0x0, - [0x4]: 0x0, - [0x5]: 0x0, - [0x6]: 0x0, - [0x7]: 0x0, - [0x8]: 0x0, - [0x9]: 0x0, - [0xa]: 0x0, - [0xb]: 0x0, - [0xc]: 0x0, - [0xd]: 0x0, - [0xe]: 0x0, - [0xf]: 0x0, - ], - }, - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x0, - [0x1]: 0x0, - [0x2]: 0x0, - [0x3]: 0x0, - [0x4]: 0x0, - [0x5]: 0x1, - [0x6]: 0x0, - [0x7]: 0x0, - [0x8]: 0x0, - [0x9]: 0x0, - [0xa]: 0x0, - [0xb]: 0x0, - [0xc]: 0x0, - [0xd]: 0x0, - [0xe]: 0x0, - [0xf]: 0x0, - ], - }, - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x1, - [0x1]: 0x1, - [0x2]: 0x0, - [0x3]: 0x0, - [0x4]: 0x1, - [0x5]: 0x1, - [0x6]: 0x1, - [0x7]: 0x1, - [0x8]: 0x0, - [0x9]: 0x0, - [0xa]: 0x0, - [0xb]: 0x0, - [0xc]: 0x0, - [0xd]: 0x0, - [0xe]: 0x0, - [0xf]: 0x0, - ], - }, - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x0, - [0x1]: 0x0, - [0x2]: 0x0, - [0x3]: 0x0, - [0x4]: 0x0, - [0x5]: 0x0, - [0x6]: 0x0, - [0x7]: 0x0, - [0x8]: 0x0, - [0x9]: 0x0, - [0xa]: 0x1, - [0xb]: 0x0, - [0xc]: 0x0, - [0xd]: 0x0, - [0xe]: 0x0, - [0xf]: 0x0, - ], - }, - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x1, - [0x1]: 0x0, - [0x2]: 0x1, - [0x3]: 0x0, - [0x4]: 0x1, - [0x5]: 0x1, - [0x6]: 0x0, - [0x7]: 0x0, - [0x8]: 0x0, - [0x9]: 0x0, - [0xa]: 0x1, - [0xb]: 0x1, - [0xc]: 0x0, - [0xd]: 0x0, - [0xe]: 0x0, - [0xf]: 0x0, - ], - }, - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x0, - [0x1]: 0x0, - [0x2]: 0x0, - [0x3]: 0x0, - [0x4]: 0x0, - [0x5]: 0x1, - [0x6]: 0x1, - [0x7]: 0x0, - [0x8]: 0x0, - [0x9]: 0x1, - [0xa]: 0x1, - [0xb]: 0x1, - [0xc]: 0x1, - [0xd]: 0x0, - [0xe]: 0x0, - [0xf]: 0x0, - ], - }, - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x1, - [0x1]: 0x1, - [0x2]: 0x1, - [0x3]: 0x0, - [0x4]: 0x0, - [0x5]: 0x1, - [0x6]: 0x0, - [0x7]: 0x1, - [0x8]: 0x1, - [0x9]: 0x0, - [0xa]: 0x0, - [0xb]: 0x0, - [0xc]: 0x0, - [0xd]: 0x0, - [0xe]: 0x1, - [0xf]: 0x0, - ], - }, - ], - .. - }, - }, - insns: [ - // at: module-XXXXXXXXXX.rs:8:1 - 0: Copy { - dest: StatePartIndex(153), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.addr", ty: UInt<4> }, - src: StatePartIndex(67), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[7].addr", ty: UInt<4> }, - }, - 1: Copy { - dest: StatePartIndex(154), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.en", ty: Bool }, - src: StatePartIndex(68), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[7].en", ty: Bool }, - }, - 2: Copy { - dest: StatePartIndex(155), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.clk", ty: Clock }, - src: StatePartIndex(69), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[7].clk", ty: Clock }, - }, - 3: Copy { - dest: StatePartIndex(156), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.data", ty: Bool }, - src: StatePartIndex(70), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[7].data", ty: Bool }, - }, - 4: Copy { - dest: StatePartIndex(157), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.mask", ty: Bool }, - src: StatePartIndex(71), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[7].mask", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 5: Copy { - dest: StatePartIndex(151), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::r0.clk", ty: Clock }, - src: StatePartIndex(30), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[7].clk", ty: Clock }, - }, - 6: Copy { - dest: StatePartIndex(150), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::r0.en", ty: Bool }, - src: StatePartIndex(29), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[7].en", ty: Bool }, - }, - 7: Copy { - dest: StatePartIndex(149), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::r0.addr", ty: UInt<4> }, - src: StatePartIndex(28), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[7].addr", ty: UInt<4> }, - }, - // at: module-XXXXXXXXXX.rs:8:1 - 8: Copy { - dest: StatePartIndex(142), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.addr", ty: UInt<4> }, - src: StatePartIndex(62), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[6].addr", ty: UInt<4> }, - }, - 9: Copy { - dest: StatePartIndex(143), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.en", ty: Bool }, - src: StatePartIndex(63), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[6].en", ty: Bool }, - }, - 10: Copy { - dest: StatePartIndex(144), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.clk", ty: Clock }, - src: StatePartIndex(64), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[6].clk", ty: Clock }, - }, - 11: Copy { - dest: StatePartIndex(145), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.data", ty: Bool }, - src: StatePartIndex(65), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[6].data", ty: Bool }, - }, - 12: Copy { - dest: StatePartIndex(146), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.mask", ty: Bool }, - src: StatePartIndex(66), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[6].mask", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 13: Copy { - dest: StatePartIndex(140), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::r0.clk", ty: Clock }, - src: StatePartIndex(26), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[6].clk", ty: Clock }, - }, - 14: Copy { - dest: StatePartIndex(139), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::r0.en", ty: Bool }, - src: StatePartIndex(25), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[6].en", ty: Bool }, - }, - 15: Copy { - dest: StatePartIndex(138), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::r0.addr", ty: UInt<4> }, - src: StatePartIndex(24), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[6].addr", ty: UInt<4> }, - }, - // at: module-XXXXXXXXXX.rs:8:1 - 16: Copy { - dest: StatePartIndex(131), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.addr", ty: UInt<4> }, - src: StatePartIndex(57), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[5].addr", ty: UInt<4> }, - }, - 17: Copy { - dest: StatePartIndex(132), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.en", ty: Bool }, - src: StatePartIndex(58), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[5].en", ty: Bool }, - }, - 18: Copy { - dest: StatePartIndex(133), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.clk", ty: Clock }, - src: StatePartIndex(59), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[5].clk", ty: Clock }, - }, - 19: Copy { - dest: StatePartIndex(134), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.data", ty: Bool }, - src: StatePartIndex(60), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[5].data", ty: Bool }, - }, - 20: Copy { - dest: StatePartIndex(135), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.mask", ty: Bool }, - src: StatePartIndex(61), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[5].mask", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 21: Copy { - dest: StatePartIndex(129), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::r0.clk", ty: Clock }, - src: StatePartIndex(22), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[5].clk", ty: Clock }, - }, - 22: Copy { - dest: StatePartIndex(128), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::r0.en", ty: Bool }, - src: StatePartIndex(21), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[5].en", ty: Bool }, - }, - 23: Copy { - dest: StatePartIndex(127), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::r0.addr", ty: UInt<4> }, - src: StatePartIndex(20), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[5].addr", ty: UInt<4> }, - }, - // at: module-XXXXXXXXXX.rs:8:1 - 24: Copy { - dest: StatePartIndex(120), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.addr", ty: UInt<4> }, - src: StatePartIndex(52), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[4].addr", ty: UInt<4> }, - }, - 25: Copy { - dest: StatePartIndex(121), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.en", ty: Bool }, - src: StatePartIndex(53), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[4].en", ty: Bool }, - }, - 26: Copy { - dest: StatePartIndex(122), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.clk", ty: Clock }, - src: StatePartIndex(54), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[4].clk", ty: Clock }, - }, - 27: Copy { - dest: StatePartIndex(123), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.data", ty: Bool }, - src: StatePartIndex(55), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[4].data", ty: Bool }, - }, - 28: Copy { - dest: StatePartIndex(124), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.mask", ty: Bool }, - src: StatePartIndex(56), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[4].mask", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 29: Copy { - dest: StatePartIndex(118), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::r0.clk", ty: Clock }, - src: StatePartIndex(18), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[4].clk", ty: Clock }, - }, - 30: Copy { - dest: StatePartIndex(117), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::r0.en", ty: Bool }, - src: StatePartIndex(17), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[4].en", ty: Bool }, - }, - 31: Copy { - dest: StatePartIndex(116), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::r0.addr", ty: UInt<4> }, - src: StatePartIndex(16), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[4].addr", ty: UInt<4> }, - }, - // at: module-XXXXXXXXXX.rs:8:1 - 32: Copy { - dest: StatePartIndex(109), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.addr", ty: UInt<4> }, - src: StatePartIndex(47), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[3].addr", ty: UInt<4> }, - }, - 33: Copy { - dest: StatePartIndex(110), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.en", ty: Bool }, - src: StatePartIndex(48), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[3].en", ty: Bool }, - }, - 34: Copy { - dest: StatePartIndex(111), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.clk", ty: Clock }, - src: StatePartIndex(49), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[3].clk", ty: Clock }, - }, - 35: Copy { - dest: StatePartIndex(112), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.data", ty: Bool }, - src: StatePartIndex(50), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[3].data", ty: Bool }, - }, - 36: Copy { - dest: StatePartIndex(113), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.mask", ty: Bool }, - src: StatePartIndex(51), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[3].mask", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 37: Copy { - dest: StatePartIndex(107), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::r0.clk", ty: Clock }, - src: StatePartIndex(14), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[3].clk", ty: Clock }, - }, - 38: Copy { - dest: StatePartIndex(106), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::r0.en", ty: Bool }, - src: StatePartIndex(13), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[3].en", ty: Bool }, - }, - 39: Copy { - dest: StatePartIndex(105), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::r0.addr", ty: UInt<4> }, - src: StatePartIndex(12), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[3].addr", ty: UInt<4> }, - }, - // at: module-XXXXXXXXXX.rs:8:1 - 40: Copy { - dest: StatePartIndex(98), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.addr", ty: UInt<4> }, - src: StatePartIndex(42), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[2].addr", ty: UInt<4> }, - }, - 41: Copy { - dest: StatePartIndex(99), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.en", ty: Bool }, - src: StatePartIndex(43), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[2].en", ty: Bool }, - }, - 42: Copy { - dest: StatePartIndex(100), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.clk", ty: Clock }, - src: StatePartIndex(44), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[2].clk", ty: Clock }, - }, - 43: Copy { - dest: StatePartIndex(101), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.data", ty: Bool }, - src: StatePartIndex(45), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[2].data", ty: Bool }, - }, - 44: Copy { - dest: StatePartIndex(102), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.mask", ty: Bool }, - src: StatePartIndex(46), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[2].mask", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 45: Copy { - dest: StatePartIndex(96), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::r0.clk", ty: Clock }, - src: StatePartIndex(10), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[2].clk", ty: Clock }, - }, - 46: Copy { - dest: StatePartIndex(95), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::r0.en", ty: Bool }, - src: StatePartIndex(9), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[2].en", ty: Bool }, - }, - 47: Copy { - dest: StatePartIndex(94), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::r0.addr", ty: UInt<4> }, - src: StatePartIndex(8), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[2].addr", ty: UInt<4> }, - }, - // at: module-XXXXXXXXXX.rs:8:1 - 48: Copy { - dest: StatePartIndex(87), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.addr", ty: UInt<4> }, - src: StatePartIndex(37), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[1].addr", ty: UInt<4> }, - }, - 49: Copy { - dest: StatePartIndex(88), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.en", ty: Bool }, - src: StatePartIndex(38), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[1].en", ty: Bool }, - }, - 50: Copy { - dest: StatePartIndex(89), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.clk", ty: Clock }, - src: StatePartIndex(39), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[1].clk", ty: Clock }, - }, - 51: Copy { - dest: StatePartIndex(90), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.data", ty: Bool }, - src: StatePartIndex(40), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[1].data", ty: Bool }, - }, - 52: Copy { - dest: StatePartIndex(91), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.mask", ty: Bool }, - src: StatePartIndex(41), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[1].mask", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 53: Copy { - dest: StatePartIndex(85), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::r0.clk", ty: Clock }, - src: StatePartIndex(6), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[1].clk", ty: Clock }, - }, - 54: Copy { - dest: StatePartIndex(84), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::r0.en", ty: Bool }, - src: StatePartIndex(5), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[1].en", ty: Bool }, - }, - 55: Copy { - dest: StatePartIndex(83), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::r0.addr", ty: UInt<4> }, - src: StatePartIndex(4), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[1].addr", ty: UInt<4> }, - }, - // at: module-XXXXXXXXXX.rs:8:1 - 56: Copy { - dest: StatePartIndex(76), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.addr", ty: UInt<4> }, - src: StatePartIndex(32), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[0].addr", ty: UInt<4> }, - }, - 57: Copy { - dest: StatePartIndex(77), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.en", ty: Bool }, - src: StatePartIndex(33), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[0].en", ty: Bool }, - }, - 58: Copy { - dest: StatePartIndex(78), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.clk", ty: Clock }, - src: StatePartIndex(34), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[0].clk", ty: Clock }, - }, - 59: Copy { - dest: StatePartIndex(79), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.data", ty: Bool }, - src: StatePartIndex(35), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[0].data", ty: Bool }, - }, - 60: Copy { - dest: StatePartIndex(80), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.mask", ty: Bool }, - src: StatePartIndex(36), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::w[0].mask", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 61: Copy { - dest: StatePartIndex(74), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::r0.clk", ty: Clock }, - src: StatePartIndex(2), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[0].clk", ty: Clock }, - }, - 62: Copy { - dest: StatePartIndex(73), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::r0.en", ty: Bool }, - src: StatePartIndex(1), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[0].en", ty: Bool }, - }, - 63: Copy { - dest: StatePartIndex(72), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::r0.addr", ty: UInt<4> }, - src: StatePartIndex(0), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[0].addr", ty: UInt<4> }, - }, - // at: module-XXXXXXXXXX.rs:4:1 - 64: CastBigToArrayIndex { - dest: StatePartIndex(93), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(153), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.addr", ty: UInt<4> }, - }, - 65: IsNonZeroDestIsSmall { - dest: StatePartIndex(92), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(154), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.en", ty: Bool }, - }, - 66: IsNonZeroDestIsSmall { - dest: StatePartIndex(91), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(155), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.clk", ty: Clock }, - }, - 67: AndSmall { - dest: StatePartIndex(90), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(91), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(89), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 68: CastBigToArrayIndex { - dest: StatePartIndex(88), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(149), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::r0.addr", ty: UInt<4> }, - }, - 69: IsNonZeroDestIsSmall { - dest: StatePartIndex(87), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(150), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::r0.en", ty: Bool }, - }, - 70: BranchIfSmallZero { - target: 73, - value: StatePartIndex(87), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 71: MemoryReadUInt { - dest: StatePartIndex(152), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::r0.data", ty: Bool }, - memory: StatePartIndex(7), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x1, - // [0x2]: 0x1, - // [0x3]: 0x0, - // [0x4]: 0x0, - // [0x5]: 0x1, - // [0x6]: 0x0, - // [0x7]: 0x1, - // [0x8]: 0x1, - // [0x9]: 0x0, - // [0xa]: 0x0, - // [0xb]: 0x0, - // [0xc]: 0x0, - // [0xd]: 0x0, - // [0xe]: 0x1, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(88), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 72: Branch { - target: 74, - }, - 73: Const { - dest: StatePartIndex(152), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::r0.data", ty: Bool }, - value: 0x0, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 74: Copy { - dest: StatePartIndex(31), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[7].data", ty: Bool }, - src: StatePartIndex(152), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::r0.data", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:4:1 - 75: IsNonZeroDestIsSmall { - dest: StatePartIndex(86), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(151), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::r0.clk", ty: Clock }, - }, - 76: AndSmall { - dest: StatePartIndex(85), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(86), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(84), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 77: CastBigToArrayIndex { - dest: StatePartIndex(81), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(142), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.addr", ty: UInt<4> }, - }, - 78: IsNonZeroDestIsSmall { - dest: StatePartIndex(80), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(143), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.en", ty: Bool }, - }, - 79: IsNonZeroDestIsSmall { - dest: StatePartIndex(79), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(144), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.clk", ty: Clock }, - }, - 80: AndSmall { - dest: StatePartIndex(78), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(79), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(77), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 81: CastBigToArrayIndex { - dest: StatePartIndex(76), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(138), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::r0.addr", ty: UInt<4> }, - }, - 82: IsNonZeroDestIsSmall { - dest: StatePartIndex(75), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(139), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::r0.en", ty: Bool }, - }, - 83: BranchIfSmallZero { - target: 86, - value: StatePartIndex(75), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 84: MemoryReadUInt { - dest: StatePartIndex(141), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::r0.data", ty: Bool }, - memory: StatePartIndex(6), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x0, - // [0x2]: 0x0, - // [0x3]: 0x0, - // [0x4]: 0x0, - // [0x5]: 0x1, - // [0x6]: 0x1, - // [0x7]: 0x0, - // [0x8]: 0x0, - // [0x9]: 0x1, - // [0xa]: 0x1, - // [0xb]: 0x1, - // [0xc]: 0x1, - // [0xd]: 0x0, - // [0xe]: 0x0, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(76), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 85: Branch { - target: 87, - }, - 86: Const { - dest: StatePartIndex(141), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::r0.data", ty: Bool }, - value: 0x0, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 87: Copy { - dest: StatePartIndex(27), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[6].data", ty: Bool }, - src: StatePartIndex(141), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::r0.data", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:4:1 - 88: IsNonZeroDestIsSmall { - dest: StatePartIndex(74), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(140), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::r0.clk", ty: Clock }, - }, - 89: AndSmall { - dest: StatePartIndex(73), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(74), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(72), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 90: CastBigToArrayIndex { - dest: StatePartIndex(69), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(131), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.addr", ty: UInt<4> }, - }, - 91: IsNonZeroDestIsSmall { - dest: StatePartIndex(68), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(132), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.en", ty: Bool }, - }, - 92: IsNonZeroDestIsSmall { - dest: StatePartIndex(67), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(133), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.clk", ty: Clock }, - }, - 93: AndSmall { - dest: StatePartIndex(66), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(67), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(65), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 94: CastBigToArrayIndex { - dest: StatePartIndex(64), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(127), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::r0.addr", ty: UInt<4> }, - }, - 95: IsNonZeroDestIsSmall { - dest: StatePartIndex(63), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(128), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::r0.en", ty: Bool }, - }, - 96: BranchIfSmallZero { - target: 99, - value: StatePartIndex(63), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 97: MemoryReadUInt { - dest: StatePartIndex(130), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::r0.data", ty: Bool }, - memory: StatePartIndex(5), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x0, - // [0x2]: 0x1, - // [0x3]: 0x0, - // [0x4]: 0x1, - // [0x5]: 0x1, - // [0x6]: 0x0, - // [0x7]: 0x0, - // [0x8]: 0x0, - // [0x9]: 0x0, - // [0xa]: 0x1, - // [0xb]: 0x1, - // [0xc]: 0x0, - // [0xd]: 0x0, - // [0xe]: 0x0, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(64), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 98: Branch { - target: 100, - }, - 99: Const { - dest: StatePartIndex(130), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::r0.data", ty: Bool }, - value: 0x0, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 100: Copy { - dest: StatePartIndex(23), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[5].data", ty: Bool }, - src: StatePartIndex(130), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::r0.data", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:4:1 - 101: IsNonZeroDestIsSmall { - dest: StatePartIndex(62), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(129), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::r0.clk", ty: Clock }, - }, - 102: AndSmall { - dest: StatePartIndex(61), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(62), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(60), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 103: CastBigToArrayIndex { - dest: StatePartIndex(57), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(120), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.addr", ty: UInt<4> }, - }, - 104: IsNonZeroDestIsSmall { - dest: StatePartIndex(56), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(121), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.en", ty: Bool }, - }, - 105: IsNonZeroDestIsSmall { - dest: StatePartIndex(55), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(122), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.clk", ty: Clock }, - }, - 106: AndSmall { - dest: StatePartIndex(54), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(55), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(53), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 107: CastBigToArrayIndex { - dest: StatePartIndex(52), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(116), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::r0.addr", ty: UInt<4> }, - }, - 108: IsNonZeroDestIsSmall { - dest: StatePartIndex(51), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(117), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::r0.en", ty: Bool }, - }, - 109: BranchIfSmallZero { - target: 112, - value: StatePartIndex(51), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 110: MemoryReadUInt { - dest: StatePartIndex(119), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::r0.data", ty: Bool }, - memory: StatePartIndex(4), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x0, - // [0x2]: 0x0, - // [0x3]: 0x0, - // [0x4]: 0x0, - // [0x5]: 0x0, - // [0x6]: 0x0, - // [0x7]: 0x0, - // [0x8]: 0x0, - // [0x9]: 0x0, - // [0xa]: 0x1, - // [0xb]: 0x0, - // [0xc]: 0x0, - // [0xd]: 0x0, - // [0xe]: 0x0, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(52), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 111: Branch { - target: 113, - }, - 112: Const { - dest: StatePartIndex(119), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::r0.data", ty: Bool }, - value: 0x0, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 113: Copy { - dest: StatePartIndex(19), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[4].data", ty: Bool }, - src: StatePartIndex(119), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::r0.data", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:4:1 - 114: IsNonZeroDestIsSmall { - dest: StatePartIndex(50), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(118), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::r0.clk", ty: Clock }, - }, - 115: AndSmall { - dest: StatePartIndex(49), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(50), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(48), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 116: CastBigToArrayIndex { - dest: StatePartIndex(45), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(109), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.addr", ty: UInt<4> }, - }, - 117: IsNonZeroDestIsSmall { - dest: StatePartIndex(44), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(110), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.en", ty: Bool }, - }, - 118: IsNonZeroDestIsSmall { - dest: StatePartIndex(43), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(111), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.clk", ty: Clock }, - }, - 119: AndSmall { - dest: StatePartIndex(42), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(43), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(41), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 120: CastBigToArrayIndex { - dest: StatePartIndex(40), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(105), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::r0.addr", ty: UInt<4> }, - }, - 121: IsNonZeroDestIsSmall { - dest: StatePartIndex(39), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(106), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::r0.en", ty: Bool }, - }, - 122: BranchIfSmallZero { - target: 125, - value: StatePartIndex(39), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 123: MemoryReadUInt { - dest: StatePartIndex(108), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::r0.data", ty: Bool }, - memory: StatePartIndex(3), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x1, - // [0x2]: 0x0, - // [0x3]: 0x0, - // [0x4]: 0x1, - // [0x5]: 0x1, - // [0x6]: 0x1, - // [0x7]: 0x1, - // [0x8]: 0x0, - // [0x9]: 0x0, - // [0xa]: 0x0, - // [0xb]: 0x0, - // [0xc]: 0x0, - // [0xd]: 0x0, - // [0xe]: 0x0, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(40), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 124: Branch { - target: 126, - }, - 125: Const { - dest: StatePartIndex(108), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::r0.data", ty: Bool }, - value: 0x0, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 126: Copy { - dest: StatePartIndex(15), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[3].data", ty: Bool }, - src: StatePartIndex(108), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::r0.data", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:4:1 - 127: IsNonZeroDestIsSmall { - dest: StatePartIndex(38), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(107), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::r0.clk", ty: Clock }, - }, - 128: AndSmall { - dest: StatePartIndex(37), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(38), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(36), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 129: CastBigToArrayIndex { - dest: StatePartIndex(33), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(98), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.addr", ty: UInt<4> }, - }, - 130: IsNonZeroDestIsSmall { - dest: StatePartIndex(32), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(99), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.en", ty: Bool }, - }, - 131: IsNonZeroDestIsSmall { - dest: StatePartIndex(31), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(100), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.clk", ty: Clock }, - }, - 132: AndSmall { - dest: StatePartIndex(30), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(31), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(29), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 133: CastBigToArrayIndex { - dest: StatePartIndex(28), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(94), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::r0.addr", ty: UInt<4> }, - }, - 134: IsNonZeroDestIsSmall { - dest: StatePartIndex(27), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(95), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::r0.en", ty: Bool }, - }, - 135: BranchIfSmallZero { - target: 138, - value: StatePartIndex(27), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 136: MemoryReadUInt { - dest: StatePartIndex(97), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::r0.data", ty: Bool }, - memory: StatePartIndex(2), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x0, - // [0x2]: 0x0, - // [0x3]: 0x0, - // [0x4]: 0x0, - // [0x5]: 0x1, - // [0x6]: 0x0, - // [0x7]: 0x0, - // [0x8]: 0x0, - // [0x9]: 0x0, - // [0xa]: 0x0, - // [0xb]: 0x0, - // [0xc]: 0x0, - // [0xd]: 0x0, - // [0xe]: 0x0, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(28), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 137: Branch { - target: 139, - }, - 138: Const { - dest: StatePartIndex(97), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::r0.data", ty: Bool }, - value: 0x0, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 139: Copy { - dest: StatePartIndex(11), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[2].data", ty: Bool }, - src: StatePartIndex(97), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::r0.data", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:4:1 - 140: IsNonZeroDestIsSmall { - dest: StatePartIndex(26), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(96), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::r0.clk", ty: Clock }, - }, - 141: AndSmall { - dest: StatePartIndex(25), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(26), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(24), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 142: CastBigToArrayIndex { - dest: StatePartIndex(21), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(87), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.addr", ty: UInt<4> }, - }, - 143: IsNonZeroDestIsSmall { - dest: StatePartIndex(20), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(88), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.en", ty: Bool }, - }, - 144: IsNonZeroDestIsSmall { - dest: StatePartIndex(19), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(89), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.clk", ty: Clock }, - }, - 145: AndSmall { - dest: StatePartIndex(18), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(19), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(17), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 146: CastBigToArrayIndex { - dest: StatePartIndex(16), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(83), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::r0.addr", ty: UInt<4> }, - }, - 147: IsNonZeroDestIsSmall { - dest: StatePartIndex(15), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(84), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::r0.en", ty: Bool }, - }, - 148: BranchIfSmallZero { - target: 151, - value: StatePartIndex(15), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 149: MemoryReadUInt { - dest: StatePartIndex(86), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::r0.data", ty: Bool }, - memory: StatePartIndex(1), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x0, - // [0x2]: 0x0, - // [0x3]: 0x0, - // [0x4]: 0x0, - // [0x5]: 0x0, - // [0x6]: 0x0, - // [0x7]: 0x0, - // [0x8]: 0x0, - // [0x9]: 0x0, - // [0xa]: 0x0, - // [0xb]: 0x0, - // [0xc]: 0x0, - // [0xd]: 0x0, - // [0xe]: 0x0, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(16), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 150: Branch { - target: 152, - }, - 151: Const { - dest: StatePartIndex(86), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::r0.data", ty: Bool }, - value: 0x0, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 152: Copy { - dest: StatePartIndex(7), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[1].data", ty: Bool }, - src: StatePartIndex(86), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::r0.data", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:4:1 - 153: IsNonZeroDestIsSmall { - dest: StatePartIndex(14), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(85), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::r0.clk", ty: Clock }, - }, - 154: AndSmall { - dest: StatePartIndex(13), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(14), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(12), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 155: CastBigToArrayIndex { - dest: StatePartIndex(9), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(76), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.addr", ty: UInt<4> }, - }, - 156: IsNonZeroDestIsSmall { - dest: StatePartIndex(8), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(77), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.en", ty: Bool }, - }, - 157: IsNonZeroDestIsSmall { - dest: StatePartIndex(7), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(78), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.clk", ty: Clock }, - }, - 158: AndSmall { - dest: StatePartIndex(6), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(7), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(5), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 159: CastBigToArrayIndex { - dest: StatePartIndex(4), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(72), // (0xf) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::r0.addr", ty: UInt<4> }, - }, - 160: IsNonZeroDestIsSmall { - dest: StatePartIndex(3), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(73), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::r0.en", ty: Bool }, - }, - 161: BranchIfSmallZero { - target: 164, - value: StatePartIndex(3), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 162: MemoryReadUInt { - dest: StatePartIndex(75), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::r0.data", ty: Bool }, - memory: StatePartIndex(0), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x0, - // [0x2]: 0x0, - // [0x3]: 0x0, - // [0x4]: 0x0, - // [0x5]: 0x0, - // [0x6]: 0x0, - // [0x7]: 0x0, - // [0x8]: 0x0, - // [0x9]: 0x0, - // [0xa]: 0x0, - // [0xb]: 0x0, - // [0xc]: 0x0, - // [0xd]: 0x0, - // [0xe]: 0x0, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(4), // (0xf 15) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 163: Branch { - target: 165, - }, - 164: Const { - dest: StatePartIndex(75), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::r0.data", ty: Bool }, - value: 0x0, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 165: Copy { - dest: StatePartIndex(3), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::r[0].data", ty: Bool }, - src: StatePartIndex(75), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::r0.data", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:4:1 - 166: IsNonZeroDestIsSmall { - dest: StatePartIndex(2), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(74), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::r0.clk", ty: Clock }, - }, - 167: AndSmall { - dest: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(2), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(0), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - 168: BranchIfSmallZero { - target: 169, - value: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 169: BranchIfSmallZero { - target: 177, - value: StatePartIndex(6), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 170: CopySmall { - dest: StatePartIndex(10), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(9), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - }, - 171: CopySmall { - dest: StatePartIndex(11), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(8), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 172: Copy { - dest: StatePartIndex(81), // (0x0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(79), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.data", ty: Bool }, - }, - 173: Copy { - dest: StatePartIndex(82), // (0x1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(80), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_0::w1.mask", ty: Bool }, - }, - 174: BranchIfSmallZero { - target: 177, - value: StatePartIndex(11), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 175: BranchIfZero { - target: 177, - value: StatePartIndex(82), // (0x1) SlotDebugData { name: "", ty: Bool }, - }, - 176: MemoryWriteUInt { - value: StatePartIndex(81), // (0x0) SlotDebugData { name: "", ty: Bool }, - memory: StatePartIndex(0), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x0, - // [0x2]: 0x0, - // [0x3]: 0x0, - // [0x4]: 0x0, - // [0x5]: 0x0, - // [0x6]: 0x0, - // [0x7]: 0x0, - // [0x8]: 0x0, - // [0x9]: 0x0, - // [0xa]: 0x0, - // [0xb]: 0x0, - // [0xc]: 0x0, - // [0xd]: 0x0, - // [0xe]: 0x0, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(10), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 177: BranchIfSmallZero { - target: 178, - value: StatePartIndex(13), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 178: BranchIfSmallZero { - target: 186, - value: StatePartIndex(18), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 179: CopySmall { - dest: StatePartIndex(22), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(21), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - }, - 180: CopySmall { - dest: StatePartIndex(23), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(20), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 181: Copy { - dest: StatePartIndex(92), // (0x0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(90), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.data", ty: Bool }, - }, - 182: Copy { - dest: StatePartIndex(93), // (0x1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(91), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_1::w1.mask", ty: Bool }, - }, - 183: BranchIfSmallZero { - target: 186, - value: StatePartIndex(23), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 184: BranchIfZero { - target: 186, - value: StatePartIndex(93), // (0x1) SlotDebugData { name: "", ty: Bool }, - }, - 185: MemoryWriteUInt { - value: StatePartIndex(92), // (0x0) SlotDebugData { name: "", ty: Bool }, - memory: StatePartIndex(1), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x0, - // [0x2]: 0x0, - // [0x3]: 0x0, - // [0x4]: 0x0, - // [0x5]: 0x0, - // [0x6]: 0x0, - // [0x7]: 0x0, - // [0x8]: 0x0, - // [0x9]: 0x0, - // [0xa]: 0x0, - // [0xb]: 0x0, - // [0xc]: 0x0, - // [0xd]: 0x0, - // [0xe]: 0x0, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(22), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 186: BranchIfSmallZero { - target: 187, - value: StatePartIndex(25), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 187: BranchIfSmallZero { - target: 195, - value: StatePartIndex(30), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 188: CopySmall { - dest: StatePartIndex(34), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(33), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - }, - 189: CopySmall { - dest: StatePartIndex(35), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(32), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 190: Copy { - dest: StatePartIndex(103), // (0x0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(101), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.data", ty: Bool }, - }, - 191: Copy { - dest: StatePartIndex(104), // (0x1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(102), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_2::w1.mask", ty: Bool }, - }, - 192: BranchIfSmallZero { - target: 195, - value: StatePartIndex(35), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 193: BranchIfZero { - target: 195, - value: StatePartIndex(104), // (0x1) SlotDebugData { name: "", ty: Bool }, - }, - 194: MemoryWriteUInt { - value: StatePartIndex(103), // (0x0) SlotDebugData { name: "", ty: Bool }, - memory: StatePartIndex(2), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x0, - // [0x2]: 0x0, - // [0x3]: 0x0, - // [0x4]: 0x0, - // [0x5]: 0x1, - // [0x6]: 0x0, - // [0x7]: 0x0, - // [0x8]: 0x0, - // [0x9]: 0x0, - // [0xa]: 0x0, - // [0xb]: 0x0, - // [0xc]: 0x0, - // [0xd]: 0x0, - // [0xe]: 0x0, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(34), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 195: BranchIfSmallZero { - target: 196, - value: StatePartIndex(37), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 196: BranchIfSmallZero { - target: 204, - value: StatePartIndex(42), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 197: CopySmall { - dest: StatePartIndex(46), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(45), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - }, - 198: CopySmall { - dest: StatePartIndex(47), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(44), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 199: Copy { - dest: StatePartIndex(114), // (0x0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(112), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.data", ty: Bool }, - }, - 200: Copy { - dest: StatePartIndex(115), // (0x1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(113), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_3::w1.mask", ty: Bool }, - }, - 201: BranchIfSmallZero { - target: 204, - value: StatePartIndex(47), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 202: BranchIfZero { - target: 204, - value: StatePartIndex(115), // (0x1) SlotDebugData { name: "", ty: Bool }, - }, - 203: MemoryWriteUInt { - value: StatePartIndex(114), // (0x0) SlotDebugData { name: "", ty: Bool }, - memory: StatePartIndex(3), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x1, - // [0x2]: 0x0, - // [0x3]: 0x0, - // [0x4]: 0x1, - // [0x5]: 0x1, - // [0x6]: 0x1, - // [0x7]: 0x1, - // [0x8]: 0x0, - // [0x9]: 0x0, - // [0xa]: 0x0, - // [0xb]: 0x0, - // [0xc]: 0x0, - // [0xd]: 0x0, - // [0xe]: 0x0, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(46), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 204: BranchIfSmallZero { - target: 205, - value: StatePartIndex(49), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 205: BranchIfSmallZero { - target: 213, - value: StatePartIndex(54), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 206: CopySmall { - dest: StatePartIndex(58), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(57), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - }, - 207: CopySmall { - dest: StatePartIndex(59), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(56), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 208: Copy { - dest: StatePartIndex(125), // (0x0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(123), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.data", ty: Bool }, - }, - 209: Copy { - dest: StatePartIndex(126), // (0x1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(124), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_4::w1.mask", ty: Bool }, - }, - 210: BranchIfSmallZero { - target: 213, - value: StatePartIndex(59), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 211: BranchIfZero { - target: 213, - value: StatePartIndex(126), // (0x1) SlotDebugData { name: "", ty: Bool }, - }, - 212: MemoryWriteUInt { - value: StatePartIndex(125), // (0x0) SlotDebugData { name: "", ty: Bool }, - memory: StatePartIndex(4), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x0, - // [0x2]: 0x0, - // [0x3]: 0x0, - // [0x4]: 0x0, - // [0x5]: 0x0, - // [0x6]: 0x0, - // [0x7]: 0x0, - // [0x8]: 0x0, - // [0x9]: 0x0, - // [0xa]: 0x1, - // [0xb]: 0x0, - // [0xc]: 0x0, - // [0xd]: 0x0, - // [0xe]: 0x0, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(58), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 213: BranchIfSmallZero { - target: 214, - value: StatePartIndex(61), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 214: BranchIfSmallZero { - target: 222, - value: StatePartIndex(66), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 215: CopySmall { - dest: StatePartIndex(70), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(69), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - }, - 216: CopySmall { - dest: StatePartIndex(71), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(68), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 217: Copy { - dest: StatePartIndex(136), // (0x0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(134), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.data", ty: Bool }, - }, - 218: Copy { - dest: StatePartIndex(137), // (0x1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(135), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_5::w1.mask", ty: Bool }, - }, - 219: BranchIfSmallZero { - target: 222, - value: StatePartIndex(71), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 220: BranchIfZero { - target: 222, - value: StatePartIndex(137), // (0x1) SlotDebugData { name: "", ty: Bool }, - }, - 221: MemoryWriteUInt { - value: StatePartIndex(136), // (0x0) SlotDebugData { name: "", ty: Bool }, - memory: StatePartIndex(5), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x0, - // [0x2]: 0x1, - // [0x3]: 0x0, - // [0x4]: 0x1, - // [0x5]: 0x1, - // [0x6]: 0x0, - // [0x7]: 0x0, - // [0x8]: 0x0, - // [0x9]: 0x0, - // [0xa]: 0x1, - // [0xb]: 0x1, - // [0xc]: 0x0, - // [0xd]: 0x0, - // [0xe]: 0x0, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(70), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 222: BranchIfSmallZero { - target: 223, - value: StatePartIndex(73), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 223: BranchIfSmallZero { - target: 231, - value: StatePartIndex(78), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 224: CopySmall { - dest: StatePartIndex(82), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(81), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - }, - 225: CopySmall { - dest: StatePartIndex(83), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(80), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 226: Copy { - dest: StatePartIndex(147), // (0x0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(145), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.data", ty: Bool }, - }, - 227: Copy { - dest: StatePartIndex(148), // (0x1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(146), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_6::w1.mask", ty: Bool }, - }, - 228: BranchIfSmallZero { - target: 231, - value: StatePartIndex(83), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 229: BranchIfZero { - target: 231, - value: StatePartIndex(148), // (0x1) SlotDebugData { name: "", ty: Bool }, - }, - 230: MemoryWriteUInt { - value: StatePartIndex(147), // (0x0) SlotDebugData { name: "", ty: Bool }, - memory: StatePartIndex(6), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x0, - // [0x2]: 0x0, - // [0x3]: 0x0, - // [0x4]: 0x0, - // [0x5]: 0x1, - // [0x6]: 0x1, - // [0x7]: 0x0, - // [0x8]: 0x0, - // [0x9]: 0x1, - // [0xa]: 0x1, - // [0xb]: 0x1, - // [0xc]: 0x1, - // [0xd]: 0x0, - // [0xe]: 0x0, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(82), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 231: BranchIfSmallZero { - target: 232, - value: StatePartIndex(85), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 232: BranchIfSmallZero { - target: 240, - value: StatePartIndex(90), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 233: CopySmall { - dest: StatePartIndex(94), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - src: StatePartIndex(93), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - }, - 234: CopySmall { - dest: StatePartIndex(95), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(92), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 235: Copy { - dest: StatePartIndex(158), // (0x0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(156), // (0x0) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.data", ty: Bool }, - }, - 236: Copy { - dest: StatePartIndex(159), // (0x1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(157), // (0x1) SlotDebugData { name: "InstantiatedModule(many_memories: many_memories).many_memories::mem_7::w1.mask", ty: Bool }, - }, - 237: BranchIfSmallZero { - target: 240, - value: StatePartIndex(95), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 238: BranchIfZero { - target: 240, - value: StatePartIndex(159), // (0x1) SlotDebugData { name: "", ty: Bool }, - }, - 239: MemoryWriteUInt { - value: StatePartIndex(158), // (0x0) SlotDebugData { name: "", ty: Bool }, - memory: StatePartIndex(7), // (MemoryData { - // array_type: Array, - // data: [ - // // len = 0x10 - // [0x0]: 0x0, - // [0x1]: 0x1, - // [0x2]: 0x1, - // [0x3]: 0x0, - // [0x4]: 0x0, - // [0x5]: 0x1, - // [0x6]: 0x0, - // [0x7]: 0x1, - // [0x8]: 0x1, - // [0x9]: 0x0, - // [0xa]: 0x0, - // [0xb]: 0x0, - // [0xc]: 0x0, - // [0xd]: 0x0, - // [0xe]: 0x1, - // [0xf]: 0x0, - // ], - // }) (), - addr: StatePartIndex(94), // (0x0 0) SlotDebugData { name: "", ty: UInt<4> }, - stride: 1, - start: 0, - width: 1, - }, - 240: XorSmallImmediate { - dest: StatePartIndex(0), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(2), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 241: XorSmallImmediate { - dest: StatePartIndex(5), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(7), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 242: XorSmallImmediate { - dest: StatePartIndex(12), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(14), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 243: XorSmallImmediate { - dest: StatePartIndex(17), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(19), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 244: XorSmallImmediate { - dest: StatePartIndex(24), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(26), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 245: XorSmallImmediate { - dest: StatePartIndex(29), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(31), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 246: XorSmallImmediate { - dest: StatePartIndex(36), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(38), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 247: XorSmallImmediate { - dest: StatePartIndex(41), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(43), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 248: XorSmallImmediate { - dest: StatePartIndex(48), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(50), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 249: XorSmallImmediate { - dest: StatePartIndex(53), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(55), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 250: XorSmallImmediate { - dest: StatePartIndex(60), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(62), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 251: XorSmallImmediate { - dest: StatePartIndex(65), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(67), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 252: XorSmallImmediate { - dest: StatePartIndex(72), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(74), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 253: XorSmallImmediate { - dest: StatePartIndex(77), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(79), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 254: XorSmallImmediate { - dest: StatePartIndex(84), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(86), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 255: XorSmallImmediate { - dest: StatePartIndex(89), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(91), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 256: Return, - ], - .. - }, - pc: 256, - memory_write_log: [], - memories: StatePart { - value: [ - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x0, - [0x1]: 0x0, - [0x2]: 0x0, - [0x3]: 0x0, - [0x4]: 0x0, - [0x5]: 0x0, - [0x6]: 0x0, - [0x7]: 0x0, - [0x8]: 0x0, - [0x9]: 0x0, - [0xa]: 0x0, - [0xb]: 0x0, - [0xc]: 0x0, - [0xd]: 0x0, - [0xe]: 0x0, - [0xf]: 0x0, - ], - }, - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x0, - [0x1]: 0x0, - [0x2]: 0x0, - [0x3]: 0x0, - [0x4]: 0x0, - [0x5]: 0x0, - [0x6]: 0x0, - [0x7]: 0x0, - [0x8]: 0x0, - [0x9]: 0x0, - [0xa]: 0x0, - [0xb]: 0x0, - [0xc]: 0x0, - [0xd]: 0x0, - [0xe]: 0x0, - [0xf]: 0x0, - ], - }, - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x0, - [0x1]: 0x0, - [0x2]: 0x0, - [0x3]: 0x0, - [0x4]: 0x0, - [0x5]: 0x1, - [0x6]: 0x0, - [0x7]: 0x0, - [0x8]: 0x0, - [0x9]: 0x0, - [0xa]: 0x0, - [0xb]: 0x0, - [0xc]: 0x0, - [0xd]: 0x0, - [0xe]: 0x0, - [0xf]: 0x0, - ], - }, - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x0, - [0x1]: 0x1, - [0x2]: 0x0, - [0x3]: 0x0, - [0x4]: 0x1, - [0x5]: 0x1, - [0x6]: 0x1, - [0x7]: 0x1, - [0x8]: 0x0, - [0x9]: 0x0, - [0xa]: 0x0, - [0xb]: 0x0, - [0xc]: 0x0, - [0xd]: 0x0, - [0xe]: 0x0, - [0xf]: 0x0, - ], - }, - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x0, - [0x1]: 0x0, - [0x2]: 0x0, - [0x3]: 0x0, - [0x4]: 0x0, - [0x5]: 0x0, - [0x6]: 0x0, - [0x7]: 0x0, - [0x8]: 0x0, - [0x9]: 0x0, - [0xa]: 0x1, - [0xb]: 0x0, - [0xc]: 0x0, - [0xd]: 0x0, - [0xe]: 0x0, - [0xf]: 0x0, - ], - }, - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x0, - [0x1]: 0x0, - [0x2]: 0x1, - [0x3]: 0x0, - [0x4]: 0x1, - [0x5]: 0x1, - [0x6]: 0x0, - [0x7]: 0x0, - [0x8]: 0x0, - [0x9]: 0x0, - [0xa]: 0x1, - [0xb]: 0x1, - [0xc]: 0x0, - [0xd]: 0x0, - [0xe]: 0x0, - [0xf]: 0x0, - ], - }, - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x0, - [0x1]: 0x0, - [0x2]: 0x0, - [0x3]: 0x0, - [0x4]: 0x0, - [0x5]: 0x1, - [0x6]: 0x1, - [0x7]: 0x0, - [0x8]: 0x0, - [0x9]: 0x1, - [0xa]: 0x1, - [0xb]: 0x1, - [0xc]: 0x1, - [0xd]: 0x0, - [0xe]: 0x0, - [0xf]: 0x0, - ], - }, - MemoryData { - array_type: Array, - data: [ - // len = 0x10 - [0x0]: 0x0, - [0x1]: 0x1, - [0x2]: 0x1, - [0x3]: 0x0, - [0x4]: 0x0, - [0x5]: 0x1, - [0x6]: 0x0, - [0x7]: 0x1, - [0x8]: 0x1, - [0x9]: 0x0, - [0xa]: 0x0, - [0xb]: 0x0, - [0xc]: 0x0, - [0xd]: 0x0, - [0xe]: 0x1, - [0xf]: 0x0, - ], - }, - ], - }, - small_slots: StatePart { - value: [ - 1, - 0, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - ], - }, - big_slots: StatePart { - value: [ - 15, - 1, - 0, - 0, - 15, - 1, - 0, - 0, - 15, - 1, - 0, - 0, - 15, - 1, - 0, - 0, - 15, - 1, - 0, - 0, - 15, - 1, - 0, - 0, - 15, - 1, - 0, - 0, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 1, - 15, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 1, - ], - }, - sim_only_slots: StatePart { - value: [], - }, - }, - io: Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[0], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[0].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[0].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[0].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[0].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[1], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[1].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[1].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[1].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[1].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[2], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[2].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[2].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[2].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[2].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[3], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[3].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[3].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[3].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[3].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[4], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[4].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[4].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[4].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[4].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[5], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[5].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[5].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[5].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[5].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[6], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[6].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[6].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[6].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[6].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[7], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[7].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[7].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[7].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.r[7].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[0], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[0].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[0].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[0].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[0].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[0].mask, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[1], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[1].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[1].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[1].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[1].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[1].mask, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[2], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[2].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[2].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[2].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[2].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[2].mask, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[3], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[3].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[3].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[3].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[3].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[3].mask, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[4], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[4].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[4].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[4].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[4].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[4].mask, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[5], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[5].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[5].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[5].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[5].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[5].mask, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[6], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[6].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[6].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[6].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[6].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[6].mask, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[7], - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[7].addr, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[7].clk, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[7].data, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[7].en, - Instance { - name: ::many_memories, - instantiated: Module { - name: many_memories, - .. - }, - }.w[7].mask, - }, - did_initial_settle: true, - }, - extern_modules: [], - state_ready_to_run: false, - trace_decls: TraceModule { - name: "many_memories", - children: [ - TraceModuleIO { - name: "r", - child: TraceArray { - name: "r", - elements: [ - TraceBundle { - name: "[0]", - fields: [ - TraceUInt { - location: TraceScalarId(0), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(1), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(2), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(3), - name: "data", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Source, - }, - TraceBundle { - name: "[1]", - fields: [ - TraceUInt { - location: TraceScalarId(4), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(5), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(6), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(7), - name: "data", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Source, - }, - TraceBundle { - name: "[2]", - fields: [ - TraceUInt { - location: TraceScalarId(8), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(9), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(10), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(11), - name: "data", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Source, - }, - TraceBundle { - name: "[3]", - fields: [ - TraceUInt { - location: TraceScalarId(12), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(13), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(14), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(15), - name: "data", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Source, - }, - TraceBundle { - name: "[4]", - fields: [ - TraceUInt { - location: TraceScalarId(16), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(17), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(18), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(19), - name: "data", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Source, - }, - TraceBundle { - name: "[5]", - fields: [ - TraceUInt { - location: TraceScalarId(20), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(21), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(22), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(23), - name: "data", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Source, - }, - TraceBundle { - name: "[6]", - fields: [ - TraceUInt { - location: TraceScalarId(24), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(25), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(26), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(27), - name: "data", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Source, - }, - TraceBundle { - name: "[7]", - fields: [ - TraceUInt { - location: TraceScalarId(28), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(29), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(30), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(31), - name: "data", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Source, - }, - ], - ty: Array, en: Bool, clk: Clock, #[hdl(flip)] data: Bool}, 8>, - flow: Source, - }, - ty: Array, en: Bool, clk: Clock, #[hdl(flip)] data: Bool}, 8>, - flow: Source, - }, - TraceModuleIO { - name: "w", - child: TraceArray { - name: "w", - elements: [ - TraceBundle { - name: "[0]", - fields: [ - TraceUInt { - location: TraceScalarId(32), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(33), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(34), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(35), - name: "data", - flow: Source, - }, - TraceBool { - location: TraceScalarId(36), - name: "mask", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Source, - }, - TraceBundle { - name: "[1]", - fields: [ - TraceUInt { - location: TraceScalarId(37), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(38), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(39), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(40), - name: "data", - flow: Source, - }, - TraceBool { - location: TraceScalarId(41), - name: "mask", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Source, - }, - TraceBundle { - name: "[2]", - fields: [ - TraceUInt { - location: TraceScalarId(42), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(43), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(44), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(45), - name: "data", - flow: Source, - }, - TraceBool { - location: TraceScalarId(46), - name: "mask", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Source, - }, - TraceBundle { - name: "[3]", - fields: [ - TraceUInt { - location: TraceScalarId(47), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(48), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(49), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(50), - name: "data", - flow: Source, - }, - TraceBool { - location: TraceScalarId(51), - name: "mask", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Source, - }, - TraceBundle { - name: "[4]", - fields: [ - TraceUInt { - location: TraceScalarId(52), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(53), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(54), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(55), - name: "data", - flow: Source, - }, - TraceBool { - location: TraceScalarId(56), - name: "mask", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Source, - }, - TraceBundle { - name: "[5]", - fields: [ - TraceUInt { - location: TraceScalarId(57), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(58), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(59), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(60), - name: "data", - flow: Source, - }, - TraceBool { - location: TraceScalarId(61), - name: "mask", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Source, - }, - TraceBundle { - name: "[6]", - fields: [ - TraceUInt { - location: TraceScalarId(62), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(63), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(64), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(65), - name: "data", - flow: Source, - }, - TraceBool { - location: TraceScalarId(66), - name: "mask", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Source, - }, - TraceBundle { - name: "[7]", - fields: [ - TraceUInt { - location: TraceScalarId(67), - name: "addr", - ty: UInt<4>, - flow: Source, - }, - TraceBool { - location: TraceScalarId(68), - name: "en", - flow: Source, - }, - TraceClock { - location: TraceScalarId(69), - name: "clk", - flow: Source, - }, - TraceBool { - location: TraceScalarId(70), - name: "data", - flow: Source, - }, - TraceBool { - location: TraceScalarId(71), - name: "mask", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Source, - }, - ], - ty: Array, en: Bool, clk: Clock, data: Bool, mask: Bool}, 8>, - flow: Source, - }, - ty: Array, en: Bool, clk: Clock, data: Bool, mask: Bool}, 8>, - flow: Source, - }, - TraceMem { - id: TraceMemoryId(0), - name: "mem_0", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(0), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_0", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(72), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(73), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(74), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(75), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(76), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(77), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(78), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(79), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(80), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - TraceMem { - id: TraceMemoryId(1), - name: "mem_1", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(1), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_1", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(81), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(82), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(83), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(84), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(85), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(86), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(87), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(88), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(89), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - TraceMem { - id: TraceMemoryId(2), - name: "mem_2", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(2), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_2", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(90), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(91), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(92), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(93), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(94), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(95), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(96), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(97), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(98), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - TraceMem { - id: TraceMemoryId(3), - name: "mem_3", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(3), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_3", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(99), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(100), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(101), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(102), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(103), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(104), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(105), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(106), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(107), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - TraceMem { - id: TraceMemoryId(4), - name: "mem_4", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(4), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_4", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(108), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(109), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(110), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(111), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(112), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(113), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(114), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(115), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(116), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - TraceMem { - id: TraceMemoryId(5), - name: "mem_5", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(5), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_5", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(117), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(118), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(119), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(120), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(121), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(122), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(123), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(124), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(125), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - TraceMem { - id: TraceMemoryId(6), - name: "mem_6", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(6), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_6", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(126), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(127), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(128), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(129), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(130), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(131), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(132), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(133), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(134), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - TraceMem { - id: TraceMemoryId(7), - name: "mem_7", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(7), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_7", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(135), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(136), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(137), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(138), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(139), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(140), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(141), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(142), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(143), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - ], - }, - traces: [ - SimTrace { - id: TraceScalarId(0), - kind: BigUInt { - index: StatePartIndex(0), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(1), - kind: BigBool { - index: StatePartIndex(1), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(2), - kind: BigClock { - index: StatePartIndex(2), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(3), - kind: BigBool { - index: StatePartIndex(3), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(4), - kind: BigUInt { - index: StatePartIndex(4), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(5), - kind: BigBool { - index: StatePartIndex(5), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(6), - kind: BigClock { - index: StatePartIndex(6), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(7), - kind: BigBool { - index: StatePartIndex(7), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(8), - kind: BigUInt { - index: StatePartIndex(8), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(9), - kind: BigBool { - index: StatePartIndex(9), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(10), - kind: BigClock { - index: StatePartIndex(10), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(11), - kind: BigBool { - index: StatePartIndex(11), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(12), - kind: BigUInt { - index: StatePartIndex(12), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(13), - kind: BigBool { - index: StatePartIndex(13), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(14), - kind: BigClock { - index: StatePartIndex(14), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(15), - kind: BigBool { - index: StatePartIndex(15), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(16), - kind: BigUInt { - index: StatePartIndex(16), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(17), - kind: BigBool { - index: StatePartIndex(17), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(18), - kind: BigClock { - index: StatePartIndex(18), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(19), - kind: BigBool { - index: StatePartIndex(19), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(20), - kind: BigUInt { - index: StatePartIndex(20), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(21), - kind: BigBool { - index: StatePartIndex(21), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(22), - kind: BigClock { - index: StatePartIndex(22), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(23), - kind: BigBool { - index: StatePartIndex(23), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(24), - kind: BigUInt { - index: StatePartIndex(24), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(25), - kind: BigBool { - index: StatePartIndex(25), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(26), - kind: BigClock { - index: StatePartIndex(26), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(27), - kind: BigBool { - index: StatePartIndex(27), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(28), - kind: BigUInt { - index: StatePartIndex(28), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(29), - kind: BigBool { - index: StatePartIndex(29), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(30), - kind: BigClock { - index: StatePartIndex(30), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(31), - kind: BigBool { - index: StatePartIndex(31), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(32), - kind: BigUInt { - index: StatePartIndex(32), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(33), - kind: BigBool { - index: StatePartIndex(33), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(34), - kind: BigClock { - index: StatePartIndex(34), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(35), - kind: BigBool { - index: StatePartIndex(35), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(36), - kind: BigBool { - index: StatePartIndex(36), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(37), - kind: BigUInt { - index: StatePartIndex(37), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(38), - kind: BigBool { - index: StatePartIndex(38), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(39), - kind: BigClock { - index: StatePartIndex(39), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(40), - kind: BigBool { - index: StatePartIndex(40), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(41), - kind: BigBool { - index: StatePartIndex(41), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(42), - kind: BigUInt { - index: StatePartIndex(42), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(43), - kind: BigBool { - index: StatePartIndex(43), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(44), - kind: BigClock { - index: StatePartIndex(44), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(45), - kind: BigBool { - index: StatePartIndex(45), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(46), - kind: BigBool { - index: StatePartIndex(46), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(47), - kind: BigUInt { - index: StatePartIndex(47), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(48), - kind: BigBool { - index: StatePartIndex(48), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(49), - kind: BigClock { - index: StatePartIndex(49), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(50), - kind: BigBool { - index: StatePartIndex(50), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(51), - kind: BigBool { - index: StatePartIndex(51), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(52), - kind: BigUInt { - index: StatePartIndex(52), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(53), - kind: BigBool { - index: StatePartIndex(53), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(54), - kind: BigClock { - index: StatePartIndex(54), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(55), - kind: BigBool { - index: StatePartIndex(55), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(56), - kind: BigBool { - index: StatePartIndex(56), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(57), - kind: BigUInt { - index: StatePartIndex(57), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(58), - kind: BigBool { - index: StatePartIndex(58), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(59), - kind: BigClock { - index: StatePartIndex(59), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(60), - kind: BigBool { - index: StatePartIndex(60), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(61), - kind: BigBool { - index: StatePartIndex(61), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(62), - kind: BigUInt { - index: StatePartIndex(62), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(63), - kind: BigBool { - index: StatePartIndex(63), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(64), - kind: BigClock { - index: StatePartIndex(64), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(65), - kind: BigBool { - index: StatePartIndex(65), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(66), - kind: BigBool { - index: StatePartIndex(66), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(67), - kind: BigUInt { - index: StatePartIndex(67), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(68), - kind: BigBool { - index: StatePartIndex(68), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(69), - kind: BigClock { - index: StatePartIndex(69), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(70), - kind: BigBool { - index: StatePartIndex(70), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(71), - kind: BigBool { - index: StatePartIndex(71), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(72), - kind: BigUInt { - index: StatePartIndex(72), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(73), - kind: BigBool { - index: StatePartIndex(73), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(74), - kind: BigClock { - index: StatePartIndex(74), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(75), - kind: BigBool { - index: StatePartIndex(75), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(76), - kind: BigUInt { - index: StatePartIndex(76), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(77), - kind: BigBool { - index: StatePartIndex(77), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(78), - kind: BigClock { - index: StatePartIndex(78), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(79), - kind: BigBool { - index: StatePartIndex(79), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(80), - kind: BigBool { - index: StatePartIndex(80), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(81), - kind: BigUInt { - index: StatePartIndex(83), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(82), - kind: BigBool { - index: StatePartIndex(84), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(83), - kind: BigClock { - index: StatePartIndex(85), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(84), - kind: BigBool { - index: StatePartIndex(86), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(85), - kind: BigUInt { - index: StatePartIndex(87), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(86), - kind: BigBool { - index: StatePartIndex(88), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(87), - kind: BigClock { - index: StatePartIndex(89), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(88), - kind: BigBool { - index: StatePartIndex(90), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(89), - kind: BigBool { - index: StatePartIndex(91), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(90), - kind: BigUInt { - index: StatePartIndex(94), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(91), - kind: BigBool { - index: StatePartIndex(95), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(92), - kind: BigClock { - index: StatePartIndex(96), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(93), - kind: BigBool { - index: StatePartIndex(97), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(94), - kind: BigUInt { - index: StatePartIndex(98), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(95), - kind: BigBool { - index: StatePartIndex(99), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(96), - kind: BigClock { - index: StatePartIndex(100), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(97), - kind: BigBool { - index: StatePartIndex(101), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(98), - kind: BigBool { - index: StatePartIndex(102), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(99), - kind: BigUInt { - index: StatePartIndex(105), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(100), - kind: BigBool { - index: StatePartIndex(106), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(101), - kind: BigClock { - index: StatePartIndex(107), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(102), - kind: BigBool { - index: StatePartIndex(108), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(103), - kind: BigUInt { - index: StatePartIndex(109), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(104), - kind: BigBool { - index: StatePartIndex(110), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(105), - kind: BigClock { - index: StatePartIndex(111), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(106), - kind: BigBool { - index: StatePartIndex(112), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(107), - kind: BigBool { - index: StatePartIndex(113), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(108), - kind: BigUInt { - index: StatePartIndex(116), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(109), - kind: BigBool { - index: StatePartIndex(117), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(110), - kind: BigClock { - index: StatePartIndex(118), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(111), - kind: BigBool { - index: StatePartIndex(119), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(112), - kind: BigUInt { - index: StatePartIndex(120), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(113), - kind: BigBool { - index: StatePartIndex(121), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(114), - kind: BigClock { - index: StatePartIndex(122), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(115), - kind: BigBool { - index: StatePartIndex(123), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(116), - kind: BigBool { - index: StatePartIndex(124), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(117), - kind: BigUInt { - index: StatePartIndex(127), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(118), - kind: BigBool { - index: StatePartIndex(128), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(119), - kind: BigClock { - index: StatePartIndex(129), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(120), - kind: BigBool { - index: StatePartIndex(130), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(121), - kind: BigUInt { - index: StatePartIndex(131), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(122), - kind: BigBool { - index: StatePartIndex(132), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(123), - kind: BigClock { - index: StatePartIndex(133), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(124), - kind: BigBool { - index: StatePartIndex(134), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(125), - kind: BigBool { - index: StatePartIndex(135), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(126), - kind: BigUInt { - index: StatePartIndex(138), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(127), - kind: BigBool { - index: StatePartIndex(139), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(128), - kind: BigClock { - index: StatePartIndex(140), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(129), - kind: BigBool { - index: StatePartIndex(141), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(130), - kind: BigUInt { - index: StatePartIndex(142), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(131), - kind: BigBool { - index: StatePartIndex(143), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(132), - kind: BigClock { - index: StatePartIndex(144), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(133), - kind: BigBool { - index: StatePartIndex(145), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(134), - kind: BigBool { - index: StatePartIndex(146), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(135), - kind: BigUInt { - index: StatePartIndex(149), - ty: UInt<4>, - }, - state: 0xf, - last_state: 0xf, - }, - SimTrace { - id: TraceScalarId(136), - kind: BigBool { - index: StatePartIndex(150), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(137), - kind: BigClock { - index: StatePartIndex(151), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(138), - kind: BigBool { - index: StatePartIndex(152), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(139), - kind: BigUInt { - index: StatePartIndex(153), - ty: UInt<4>, - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(140), - kind: BigBool { - index: StatePartIndex(154), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(141), - kind: BigClock { - index: StatePartIndex(155), - }, - state: 0x0, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(142), - kind: BigBool { - index: StatePartIndex(156), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(143), - kind: BigBool { - index: StatePartIndex(157), - }, - state: 0x1, - last_state: 0x1, - }, - ], - trace_memories: { - StatePartIndex(0): TraceMem { - id: TraceMemoryId(0), - name: "mem_0", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(0), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_0", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(72), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(73), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(74), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(75), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(76), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(77), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(78), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(79), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(80), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - StatePartIndex(1): TraceMem { - id: TraceMemoryId(1), - name: "mem_1", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(1), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_1", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(81), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(82), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(83), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(84), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(85), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(86), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(87), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(88), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(89), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - StatePartIndex(2): TraceMem { - id: TraceMemoryId(2), - name: "mem_2", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(2), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_2", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(90), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(91), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(92), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(93), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(94), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(95), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(96), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(97), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(98), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - StatePartIndex(3): TraceMem { - id: TraceMemoryId(3), - name: "mem_3", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(3), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_3", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(99), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(100), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(101), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(102), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(103), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(104), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(105), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(106), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(107), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - StatePartIndex(4): TraceMem { - id: TraceMemoryId(4), - name: "mem_4", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(4), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_4", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(108), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(109), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(110), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(111), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(112), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(113), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(114), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(115), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(116), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - StatePartIndex(5): TraceMem { - id: TraceMemoryId(5), - name: "mem_5", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(5), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_5", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(117), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(118), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(119), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(120), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(121), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(122), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(123), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(124), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(125), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - StatePartIndex(6): TraceMem { - id: TraceMemoryId(6), - name: "mem_6", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(6), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_6", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(126), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(127), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(128), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(129), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(130), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(131), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(132), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(133), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(134), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - StatePartIndex(7): TraceMem { - id: TraceMemoryId(7), - name: "mem_7", - stride: 1, - element_type: TraceBool { - location: TraceMemoryLocation { - id: TraceMemoryId(7), - depth: 16, - stride: 1, - start: 0, - len: 1, - }, - name: "mem_7", - flow: Duplex, - }, - ports: [ - TraceMemPort { - name: "r0", - bundle: TraceBundle { - name: "r0", - fields: [ - TraceUInt { - location: TraceScalarId(135), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(136), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(137), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(138), - name: "data", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - #[hdl(flip)] /* offset = 6 */ - data: Bool, - }, - }, - TraceMemPort { - name: "w1", - bundle: TraceBundle { - name: "w1", - fields: [ - TraceUInt { - location: TraceScalarId(139), - name: "addr", - ty: UInt<4>, - flow: Sink, - }, - TraceBool { - location: TraceScalarId(140), - name: "en", - flow: Sink, - }, - TraceClock { - location: TraceScalarId(141), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(142), - name: "data", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(143), - name: "mask", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - flow: Sink, - }, - ty: Bundle { - /* offset = 0 */ - addr: UInt<4>, - /* offset = 4 */ - en: Bool, - /* offset = 5 */ - clk: Clock, - /* offset = 6 */ - data: Bool, - /* offset = 7 */ - mask: Bool, - }, - }, - ], - array_type: Array, - }, - }, - trace_writers: [ - Running( - VcdWriter { - finished_init: true, - timescale: 1 ps, - .. - }, - ), - ], - instant: 38 μs, - clocks_triggered: [ - StatePartIndex(1), - StatePartIndex(6), - StatePartIndex(13), - StatePartIndex(18), - StatePartIndex(25), - StatePartIndex(30), - StatePartIndex(37), - StatePartIndex(42), - StatePartIndex(49), - StatePartIndex(54), - StatePartIndex(61), - StatePartIndex(66), - StatePartIndex(73), - StatePartIndex(78), - StatePartIndex(85), - StatePartIndex(90), - ], - .. -} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/many_memories.vcd b/crates/fayalite/tests/sim/expected/many_memories.vcd deleted file mode 100644 index cbaeb7b..0000000 --- a/crates/fayalite/tests/sim/expected/many_memories.vcd +++ /dev/null @@ -1,2596 +0,0 @@ -$timescale 1 ps $end -$scope module many_memories $end -$scope struct r $end -$scope struct \[0] $end -$var wire 4 ! addr $end -$var wire 1 " en $end -$var wire 1 # clk $end -$var wire 1 $ data $end -$upscope $end -$scope struct \[1] $end -$var wire 4 % addr $end -$var wire 1 & en $end -$var wire 1 ' clk $end -$var wire 1 ( data $end -$upscope $end -$scope struct \[2] $end -$var wire 4 ) addr $end -$var wire 1 * en $end -$var wire 1 + clk $end -$var wire 1 , data $end -$upscope $end -$scope struct \[3] $end -$var wire 4 - addr $end -$var wire 1 . en $end -$var wire 1 / clk $end -$var wire 1 0 data $end -$upscope $end -$scope struct \[4] $end -$var wire 4 1 addr $end -$var wire 1 2 en $end -$var wire 1 3 clk $end -$var wire 1 4 data $end -$upscope $end -$scope struct \[5] $end -$var wire 4 5 addr $end -$var wire 1 6 en $end -$var wire 1 7 clk $end -$var wire 1 8 data $end -$upscope $end -$scope struct \[6] $end -$var wire 4 9 addr $end -$var wire 1 : en $end -$var wire 1 ; clk $end -$var wire 1 < data $end -$upscope $end -$scope struct \[7] $end -$var wire 4 = addr $end -$var wire 1 > en $end -$var wire 1 ? clk $end -$var wire 1 @ data $end -$upscope $end -$upscope $end -$scope struct w $end -$scope struct \[0] $end -$var wire 4 A addr $end -$var wire 1 B en $end -$var wire 1 C clk $end -$var wire 1 D data $end -$var wire 1 E mask $end -$upscope $end -$scope struct \[1] $end -$var wire 4 F addr $end -$var wire 1 G en $end -$var wire 1 H clk $end -$var wire 1 I data $end -$var wire 1 J mask $end -$upscope $end -$scope struct \[2] $end -$var wire 4 K addr $end -$var wire 1 L en $end -$var wire 1 M clk $end -$var wire 1 N data $end -$var wire 1 O mask $end -$upscope $end -$scope struct \[3] $end -$var wire 4 P addr $end -$var wire 1 Q en $end -$var wire 1 R clk $end -$var wire 1 S data $end -$var wire 1 T mask $end -$upscope $end -$scope struct \[4] $end -$var wire 4 U addr $end -$var wire 1 V en $end -$var wire 1 W clk $end -$var wire 1 X data $end -$var wire 1 Y mask $end -$upscope $end -$scope struct \[5] $end -$var wire 4 Z addr $end -$var wire 1 [ en $end -$var wire 1 \ clk $end -$var wire 1 ] data $end -$var wire 1 ^ mask $end -$upscope $end -$scope struct \[6] $end -$var wire 4 _ addr $end -$var wire 1 ` en $end -$var wire 1 a clk $end -$var wire 1 b data $end -$var wire 1 c mask $end -$upscope $end -$scope struct \[7] $end -$var wire 4 d addr $end -$var wire 1 e en $end -$var wire 1 f clk $end -$var wire 1 g data $end -$var wire 1 h mask $end -$upscope $end -$upscope $end -$scope struct mem_0 $end -$scope struct contents $end -$scope struct \[0] $end -$var reg 1 S" mem_0 $end -$upscope $end -$scope struct \[1] $end -$var reg 1 T" mem_0 $end -$upscope $end -$scope struct \[2] $end -$var reg 1 U" mem_0 $end -$upscope $end -$scope struct \[3] $end -$var reg 1 V" mem_0 $end -$upscope $end -$scope struct \[4] $end -$var reg 1 W" mem_0 $end -$upscope $end -$scope struct \[5] $end -$var reg 1 X" mem_0 $end -$upscope $end -$scope struct \[6] $end -$var reg 1 Y" mem_0 $end -$upscope $end -$scope struct \[7] $end -$var reg 1 Z" mem_0 $end -$upscope $end -$scope struct \[8] $end -$var reg 1 [" mem_0 $end -$upscope $end -$scope struct \[9] $end -$var reg 1 \" mem_0 $end -$upscope $end -$scope struct \[10] $end -$var reg 1 ]" mem_0 $end -$upscope $end -$scope struct \[11] $end -$var reg 1 ^" mem_0 $end -$upscope $end -$scope struct \[12] $end -$var reg 1 _" mem_0 $end -$upscope $end -$scope struct \[13] $end -$var reg 1 `" mem_0 $end -$upscope $end -$scope struct \[14] $end -$var reg 1 a" mem_0 $end -$upscope $end -$scope struct \[15] $end -$var reg 1 b" mem_0 $end -$upscope $end -$upscope $end -$scope struct r0 $end -$var wire 4 i addr $end -$var wire 1 j en $end -$var wire 1 k clk $end -$var wire 1 l data $end -$upscope $end -$scope struct w1 $end -$var wire 4 m addr $end -$var wire 1 n en $end -$var wire 1 o clk $end -$var wire 1 p data $end -$var wire 1 q mask $end -$upscope $end -$upscope $end -$scope struct mem_1 $end -$scope struct contents $end -$scope struct \[0] $end -$var reg 1 c" mem_1 $end -$upscope $end -$scope struct \[1] $end -$var reg 1 d" mem_1 $end -$upscope $end -$scope struct \[2] $end -$var reg 1 e" mem_1 $end -$upscope $end -$scope struct \[3] $end -$var reg 1 f" mem_1 $end -$upscope $end -$scope struct \[4] $end -$var reg 1 g" mem_1 $end -$upscope $end -$scope struct \[5] $end -$var reg 1 h" mem_1 $end -$upscope $end -$scope struct \[6] $end -$var reg 1 i" mem_1 $end -$upscope $end -$scope struct \[7] $end -$var reg 1 j" mem_1 $end -$upscope $end -$scope struct \[8] $end -$var reg 1 k" mem_1 $end -$upscope $end -$scope struct \[9] $end -$var reg 1 l" mem_1 $end -$upscope $end -$scope struct \[10] $end -$var reg 1 m" mem_1 $end -$upscope $end -$scope struct \[11] $end -$var reg 1 n" mem_1 $end -$upscope $end -$scope struct \[12] $end -$var reg 1 o" mem_1 $end -$upscope $end -$scope struct \[13] $end -$var reg 1 p" mem_1 $end -$upscope $end -$scope struct \[14] $end -$var reg 1 q" mem_1 $end -$upscope $end -$scope struct \[15] $end -$var reg 1 r" mem_1 $end -$upscope $end -$upscope $end -$scope struct r0 $end -$var wire 4 r addr $end -$var wire 1 s en $end -$var wire 1 t clk $end -$var wire 1 u data $end -$upscope $end -$scope struct w1 $end -$var wire 4 v addr $end -$var wire 1 w en $end -$var wire 1 x clk $end -$var wire 1 y data $end -$var wire 1 z mask $end -$upscope $end -$upscope $end -$scope struct mem_2 $end -$scope struct contents $end -$scope struct \[0] $end -$var reg 1 s" mem_2 $end -$upscope $end -$scope struct \[1] $end -$var reg 1 t" mem_2 $end -$upscope $end -$scope struct \[2] $end -$var reg 1 u" mem_2 $end -$upscope $end -$scope struct \[3] $end -$var reg 1 v" mem_2 $end -$upscope $end -$scope struct \[4] $end -$var reg 1 w" mem_2 $end -$upscope $end -$scope struct \[5] $end -$var reg 1 x" mem_2 $end -$upscope $end -$scope struct \[6] $end -$var reg 1 y" mem_2 $end -$upscope $end -$scope struct \[7] $end -$var reg 1 z" mem_2 $end -$upscope $end -$scope struct \[8] $end -$var reg 1 {" mem_2 $end -$upscope $end -$scope struct \[9] $end -$var reg 1 |" mem_2 $end -$upscope $end -$scope struct \[10] $end -$var reg 1 }" mem_2 $end -$upscope $end -$scope struct \[11] $end -$var reg 1 ~" mem_2 $end -$upscope $end -$scope struct \[12] $end -$var reg 1 !# mem_2 $end -$upscope $end -$scope struct \[13] $end -$var reg 1 "# mem_2 $end -$upscope $end -$scope struct \[14] $end -$var reg 1 ## mem_2 $end -$upscope $end -$scope struct \[15] $end -$var reg 1 $# mem_2 $end -$upscope $end -$upscope $end -$scope struct r0 $end -$var wire 4 { addr $end -$var wire 1 | en $end -$var wire 1 } clk $end -$var wire 1 ~ data $end -$upscope $end -$scope struct w1 $end -$var wire 4 !" addr $end -$var wire 1 "" en $end -$var wire 1 #" clk $end -$var wire 1 $" data $end -$var wire 1 %" mask $end -$upscope $end -$upscope $end -$scope struct mem_3 $end -$scope struct contents $end -$scope struct \[0] $end -$var reg 1 %# mem_3 $end -$upscope $end -$scope struct \[1] $end -$var reg 1 &# mem_3 $end -$upscope $end -$scope struct \[2] $end -$var reg 1 '# mem_3 $end -$upscope $end -$scope struct \[3] $end -$var reg 1 (# mem_3 $end -$upscope $end -$scope struct \[4] $end -$var reg 1 )# mem_3 $end -$upscope $end -$scope struct \[5] $end -$var reg 1 *# mem_3 $end -$upscope $end -$scope struct \[6] $end -$var reg 1 +# mem_3 $end -$upscope $end -$scope struct \[7] $end -$var reg 1 ,# mem_3 $end -$upscope $end -$scope struct \[8] $end -$var reg 1 -# mem_3 $end -$upscope $end -$scope struct \[9] $end -$var reg 1 .# mem_3 $end -$upscope $end -$scope struct \[10] $end -$var reg 1 /# mem_3 $end -$upscope $end -$scope struct \[11] $end -$var reg 1 0# mem_3 $end -$upscope $end -$scope struct \[12] $end -$var reg 1 1# mem_3 $end -$upscope $end -$scope struct \[13] $end -$var reg 1 2# mem_3 $end -$upscope $end -$scope struct \[14] $end -$var reg 1 3# mem_3 $end -$upscope $end -$scope struct \[15] $end -$var reg 1 4# mem_3 $end -$upscope $end -$upscope $end -$scope struct r0 $end -$var wire 4 &" addr $end -$var wire 1 '" en $end -$var wire 1 (" clk $end -$var wire 1 )" data $end -$upscope $end -$scope struct w1 $end -$var wire 4 *" addr $end -$var wire 1 +" en $end -$var wire 1 ," clk $end -$var wire 1 -" data $end -$var wire 1 ." mask $end -$upscope $end -$upscope $end -$scope struct mem_4 $end -$scope struct contents $end -$scope struct \[0] $end -$var reg 1 5# mem_4 $end -$upscope $end -$scope struct \[1] $end -$var reg 1 6# mem_4 $end -$upscope $end -$scope struct \[2] $end -$var reg 1 7# mem_4 $end -$upscope $end -$scope struct \[3] $end -$var reg 1 8# mem_4 $end -$upscope $end -$scope struct \[4] $end -$var reg 1 9# mem_4 $end -$upscope $end -$scope struct \[5] $end -$var reg 1 :# mem_4 $end -$upscope $end -$scope struct \[6] $end -$var reg 1 ;# mem_4 $end -$upscope $end -$scope struct \[7] $end -$var reg 1 <# mem_4 $end -$upscope $end -$scope struct \[8] $end -$var reg 1 =# mem_4 $end -$upscope $end -$scope struct \[9] $end -$var reg 1 ># mem_4 $end -$upscope $end -$scope struct \[10] $end -$var reg 1 ?# mem_4 $end -$upscope $end -$scope struct \[11] $end -$var reg 1 @# mem_4 $end -$upscope $end -$scope struct \[12] $end -$var reg 1 A# mem_4 $end -$upscope $end -$scope struct \[13] $end -$var reg 1 B# mem_4 $end -$upscope $end -$scope struct \[14] $end -$var reg 1 C# mem_4 $end -$upscope $end -$scope struct \[15] $end -$var reg 1 D# mem_4 $end -$upscope $end -$upscope $end -$scope struct r0 $end -$var wire 4 /" addr $end -$var wire 1 0" en $end -$var wire 1 1" clk $end -$var wire 1 2" data $end -$upscope $end -$scope struct w1 $end -$var wire 4 3" addr $end -$var wire 1 4" en $end -$var wire 1 5" clk $end -$var wire 1 6" data $end -$var wire 1 7" mask $end -$upscope $end -$upscope $end -$scope struct mem_5 $end -$scope struct contents $end -$scope struct \[0] $end -$var reg 1 E# mem_5 $end -$upscope $end -$scope struct \[1] $end -$var reg 1 F# mem_5 $end -$upscope $end -$scope struct \[2] $end -$var reg 1 G# mem_5 $end -$upscope $end -$scope struct \[3] $end -$var reg 1 H# mem_5 $end -$upscope $end -$scope struct \[4] $end -$var reg 1 I# mem_5 $end -$upscope $end -$scope struct \[5] $end -$var reg 1 J# mem_5 $end -$upscope $end -$scope struct \[6] $end -$var reg 1 K# mem_5 $end -$upscope $end -$scope struct \[7] $end -$var reg 1 L# mem_5 $end -$upscope $end -$scope struct \[8] $end -$var reg 1 M# mem_5 $end -$upscope $end -$scope struct \[9] $end -$var reg 1 N# mem_5 $end -$upscope $end -$scope struct \[10] $end -$var reg 1 O# mem_5 $end -$upscope $end -$scope struct \[11] $end -$var reg 1 P# mem_5 $end -$upscope $end -$scope struct \[12] $end -$var reg 1 Q# mem_5 $end -$upscope $end -$scope struct \[13] $end -$var reg 1 R# mem_5 $end -$upscope $end -$scope struct \[14] $end -$var reg 1 S# mem_5 $end -$upscope $end -$scope struct \[15] $end -$var reg 1 T# mem_5 $end -$upscope $end -$upscope $end -$scope struct r0 $end -$var wire 4 8" addr $end -$var wire 1 9" en $end -$var wire 1 :" clk $end -$var wire 1 ;" data $end -$upscope $end -$scope struct w1 $end -$var wire 4 <" addr $end -$var wire 1 =" en $end -$var wire 1 >" clk $end -$var wire 1 ?" data $end -$var wire 1 @" mask $end -$upscope $end -$upscope $end -$scope struct mem_6 $end -$scope struct contents $end -$scope struct \[0] $end -$var reg 1 U# mem_6 $end -$upscope $end -$scope struct \[1] $end -$var reg 1 V# mem_6 $end -$upscope $end -$scope struct \[2] $end -$var reg 1 W# mem_6 $end -$upscope $end -$scope struct \[3] $end -$var reg 1 X# mem_6 $end -$upscope $end -$scope struct \[4] $end -$var reg 1 Y# mem_6 $end -$upscope $end -$scope struct \[5] $end -$var reg 1 Z# mem_6 $end -$upscope $end -$scope struct \[6] $end -$var reg 1 [# mem_6 $end -$upscope $end -$scope struct \[7] $end -$var reg 1 \# mem_6 $end -$upscope $end -$scope struct \[8] $end -$var reg 1 ]# mem_6 $end -$upscope $end -$scope struct \[9] $end -$var reg 1 ^# mem_6 $end -$upscope $end -$scope struct \[10] $end -$var reg 1 _# mem_6 $end -$upscope $end -$scope struct \[11] $end -$var reg 1 `# mem_6 $end -$upscope $end -$scope struct \[12] $end -$var reg 1 a# mem_6 $end -$upscope $end -$scope struct \[13] $end -$var reg 1 b# mem_6 $end -$upscope $end -$scope struct \[14] $end -$var reg 1 c# mem_6 $end -$upscope $end -$scope struct \[15] $end -$var reg 1 d# mem_6 $end -$upscope $end -$upscope $end -$scope struct r0 $end -$var wire 4 A" addr $end -$var wire 1 B" en $end -$var wire 1 C" clk $end -$var wire 1 D" data $end -$upscope $end -$scope struct w1 $end -$var wire 4 E" addr $end -$var wire 1 F" en $end -$var wire 1 G" clk $end -$var wire 1 H" data $end -$var wire 1 I" mask $end -$upscope $end -$upscope $end -$scope struct mem_7 $end -$scope struct contents $end -$scope struct \[0] $end -$var reg 1 e# mem_7 $end -$upscope $end -$scope struct \[1] $end -$var reg 1 f# mem_7 $end -$upscope $end -$scope struct \[2] $end -$var reg 1 g# mem_7 $end -$upscope $end -$scope struct \[3] $end -$var reg 1 h# mem_7 $end -$upscope $end -$scope struct \[4] $end -$var reg 1 i# mem_7 $end -$upscope $end -$scope struct \[5] $end -$var reg 1 j# mem_7 $end -$upscope $end -$scope struct \[6] $end -$var reg 1 k# mem_7 $end -$upscope $end -$scope struct \[7] $end -$var reg 1 l# mem_7 $end -$upscope $end -$scope struct \[8] $end -$var reg 1 m# mem_7 $end -$upscope $end -$scope struct \[9] $end -$var reg 1 n# mem_7 $end -$upscope $end -$scope struct \[10] $end -$var reg 1 o# mem_7 $end -$upscope $end -$scope struct \[11] $end -$var reg 1 p# mem_7 $end -$upscope $end -$scope struct \[12] $end -$var reg 1 q# mem_7 $end -$upscope $end -$scope struct \[13] $end -$var reg 1 r# mem_7 $end -$upscope $end -$scope struct \[14] $end -$var reg 1 s# mem_7 $end -$upscope $end -$scope struct \[15] $end -$var reg 1 t# mem_7 $end -$upscope $end -$upscope $end -$scope struct r0 $end -$var wire 4 J" addr $end -$var wire 1 K" en $end -$var wire 1 L" clk $end -$var wire 1 M" data $end -$upscope $end -$scope struct w1 $end -$var wire 4 N" addr $end -$var wire 1 O" en $end -$var wire 1 P" clk $end -$var wire 1 Q" data $end -$var wire 1 R" mask $end -$upscope $end -$upscope $end -$upscope $end -$enddefinitions $end -$dumpvars -0S" -0T" -0U" -0V" -0W" -0X" -0Y" -0Z" -0[" -0\" -0]" -0^" -0_" -0`" -0a" -0b" -1c" -0d" -0e" -0f" -0g" -0h" -0i" -0j" -0k" -0l" -0m" -0n" -0o" -0p" -0q" -0r" -0s" -0t" -0u" -0v" -0w" -1x" -0y" -0z" -0{" -0|" -0}" -0~" -0!# -0"# -0## -0$# -1%# -1&# -0'# -0(# -1)# -1*# -1+# -1,# -0-# -0.# -0/# -00# -01# -02# -03# -04# -05# -06# -07# -08# -09# -0:# -0;# -0<# -0=# -0># -1?# -0@# -0A# -0B# -0C# -0D# -1E# -0F# -1G# -0H# -1I# -1J# -0K# -0L# -0M# -0N# -1O# -1P# -0Q# -0R# -0S# -0T# -0U# -0V# -0W# -0X# -0Y# -1Z# -1[# -0\# -0]# -1^# -1_# -1`# -1a# -0b# -0c# -0d# -1e# -1f# -1g# -0h# -0i# -1j# -0k# -1l# -1m# -0n# -0o# -0p# -0q# -0r# -1s# -0t# -b0 ! -0" -0# -0$ -b0 % -0& -0' -0( -b0 ) -0* -0+ -0, -b0 - -0. -0/ -00 -b0 1 -02 -03 -04 -b0 5 -06 -07 -08 -b0 9 -0: -0; -0< -b0 = -0> -0? -0@ -b0 A -0B -0C -0D -0E -b0 F -0G -0H -0I -0J -b0 K -0L -0M -0N -0O -b0 P -0Q -0R -0S -0T -b0 U -0V -0W -0X -0Y -b0 Z -0[ -0\ -0] -0^ -b0 _ -0` -0a -0b -0c -b0 d -0e -0f -0g -0h -b0 i -0j -0k -0l -b0 m -0n -0o -0p -0q -b0 r -0s -0t -0u -b0 v -0w -0x -0y -0z -b0 { -0| -0} -0~ -b0 !" -0"" -0#" -0$" -0%" -b0 &" -0'" -0(" -0)" -b0 *" -0+" -0," -0-" -0." -b0 /" -00" -01" -02" -b0 3" -04" -05" -06" -07" -b0 8" -09" -0:" -0;" -b0 <" -0=" -0>" -0?" -0@" -b0 A" -0B" -0C" -0D" -b0 E" -0F" -0G" -0H" -0I" -b0 J" -0K" -0L" -0M" -b0 N" -0O" -0P" -0Q" -0R" -$end -#1000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#2000000 -1" -0# -1& -0' -1( -1* -0+ -1. -0/ -10 -12 -03 -16 -07 -18 -1: -0; -1> -0? -1@ -1B -0C -1D -1E -1G -0H -1I -1J -1L -0M -1N -1O -1Q -0R -1S -1T -1V -0W -1X -1Y -1[ -0\ -1] -1^ -1` -0a -1b -1c -1e -0f -1g -1h -1j -0k -1n -0o -1p -1q -1s -0t -1u -1w -0x -1y -1z -1| -0} -1"" -0#" -1$" -1%" -1'" -0(" -1)" -1+" -0," -1-" -1." -10" -01" -14" -05" -16" -17" -19" -0:" -1;" -1=" -0>" -1?" -1@" -1B" -0C" -1F" -0G" -1H" -1I" -1K" -0L" -1M" -1O" -0P" -1Q" -1R" -#3000000 -1S" -1c" -1s" -1%# -15# -1E# -1U# -1e# -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -1$ -1, -14 -1< -1l -1~ -12" -1D" -#4000000 -0# -0' -0+ -0/ -03 -07 -0; -0? -0C -0D -0H -0I -0M -0N -0R -0S -0W -0X -0\ -0] -0a -0b -0f -0g -0k -0o -0p -0t -0x -0y -0} -0#" -0$" -0(" -0," -0-" -01" -05" -06" -0:" -0>" -0?" -0C" -0G" -0H" -0L" -0P" -0Q" -#5000000 -0S" -0c" -0s" -0%# -05# -0E# -0U# -0e# -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -0$ -0( -0, -00 -04 -08 -0< -0@ -0l -0u -0~ -0)" -02" -0;" -0D" -0M" -#6000000 -0# -0' -0+ -0/ -03 -07 -0; -0? -0B -0C -0G -0H -0L -0M -0Q -0R -0V -0W -0[ -0\ -0` -0a -0e -0f -0k -0n -0o -0t -0w -0x -0} -0"" -0#" -0(" -0+" -0," -01" -04" -05" -0:" -0=" -0>" -0C" -0F" -0G" -0L" -0O" -0P" -#7000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#8000000 -b1 ! -0# -b1 % -0' -b1 ) -0+ -b1 - -0/ -10 -b1 1 -03 -b1 5 -07 -b1 9 -0; -b1 = -0? -1@ -0C -0H -0M -0R -0W -0\ -0a -0f -b1 i -0k -0o -b1 r -0t -0x -b1 { -0} -0#" -b1 &" -0(" -1)" -0," -b1 /" -01" -05" -b1 8" -0:" -0>" -b1 A" -0C" -0G" -b1 J" -0L" -1M" -0P" -#9000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#10000000 -b10 ! -0# -b10 % -0' -b10 ) -0+ -b10 - -0/ -00 -b10 1 -03 -b10 5 -07 -18 -b10 9 -0; -b10 = -0? -0C -0H -0M -0R -0W -0\ -0a -0f -b10 i -0k -0o -b10 r -0t -0x -b10 { -0} -0#" -b10 &" -0(" -0)" -0," -b10 /" -01" -05" -b10 8" -0:" -1;" -0>" -b10 A" -0C" -0G" -b10 J" -0L" -0P" -#11000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#12000000 -b11 ! -0# -b11 % -0' -b11 ) -0+ -b11 - -0/ -b11 1 -03 -b11 5 -07 -08 -b11 9 -0; -b11 = -0? -0@ -0C -0H -0M -0R -0W -0\ -0a -0f -b11 i -0k -0o -b11 r -0t -0x -b11 { -0} -0#" -b11 &" -0(" -0," -b11 /" -01" -05" -b11 8" -0:" -0;" -0>" -b11 A" -0C" -0G" -b11 J" -0L" -0M" -0P" -#13000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#14000000 -b100 ! -0# -b100 % -0' -b100 ) -0+ -b100 - -0/ -10 -b100 1 -03 -b100 5 -07 -18 -b100 9 -0; -b100 = -0? -0C -0H -0M -0R -0W -0\ -0a -0f -b100 i -0k -0o -b100 r -0t -0x -b100 { -0} -0#" -b100 &" -0(" -1)" -0," -b100 /" -01" -05" -b100 8" -0:" -1;" -0>" -b100 A" -0C" -0G" -b100 J" -0L" -0P" -#15000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#16000000 -b101 ! -0# -b101 % -0' -b101 ) -0+ -1, -b101 - -0/ -b101 1 -03 -b101 5 -07 -b101 9 -0; -1< -b101 = -0? -1@ -0C -0H -0M -0R -0W -0\ -0a -0f -b101 i -0k -0o -b101 r -0t -0x -b101 { -0} -1~ -0#" -b101 &" -0(" -0," -b101 /" -01" -05" -b101 8" -0:" -0>" -b101 A" -0C" -1D" -0G" -b101 J" -0L" -1M" -0P" -#17000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#18000000 -b110 ! -0# -b110 % -0' -b110 ) -0+ -0, -b110 - -0/ -b110 1 -03 -b110 5 -07 -08 -b110 9 -0; -b110 = -0? -0@ -0C -0H -0M -0R -0W -0\ -0a -0f -b110 i -0k -0o -b110 r -0t -0x -b110 { -0} -0~ -0#" -b110 &" -0(" -0," -b110 /" -01" -05" -b110 8" -0:" -0;" -0>" -b110 A" -0C" -0G" -b110 J" -0L" -0M" -0P" -#19000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#20000000 -b111 ! -0# -b111 % -0' -b111 ) -0+ -b111 - -0/ -b111 1 -03 -b111 5 -07 -b111 9 -0; -0< -b111 = -0? -1@ -0C -0H -0M -0R -0W -0\ -0a -0f -b111 i -0k -0o -b111 r -0t -0x -b111 { -0} -0#" -b111 &" -0(" -0," -b111 /" -01" -05" -b111 8" -0:" -0>" -b111 A" -0C" -0D" -0G" -b111 J" -0L" -1M" -0P" -#21000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#22000000 -b1000 ! -0# -b1000 % -0' -b1000 ) -0+ -b1000 - -0/ -00 -b1000 1 -03 -b1000 5 -07 -b1000 9 -0; -b1000 = -0? -0C -0H -0M -0R -0W -0\ -0a -0f -b1000 i -0k -0o -b1000 r -0t -0x -b1000 { -0} -0#" -b1000 &" -0(" -0)" -0," -b1000 /" -01" -05" -b1000 8" -0:" -0>" -b1000 A" -0C" -0G" -b1000 J" -0L" -0P" -#23000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#24000000 -b1001 ! -0# -b1001 % -0' -b1001 ) -0+ -b1001 - -0/ -b1001 1 -03 -b1001 5 -07 -b1001 9 -0; -1< -b1001 = -0? -0@ -0C -0H -0M -0R -0W -0\ -0a -0f -b1001 i -0k -0o -b1001 r -0t -0x -b1001 { -0} -0#" -b1001 &" -0(" -0," -b1001 /" -01" -05" -b1001 8" -0:" -0>" -b1001 A" -0C" -1D" -0G" -b1001 J" -0L" -0M" -0P" -#25000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#26000000 -b1010 ! -0# -b1010 % -0' -b1010 ) -0+ -b1010 - -0/ -b1010 1 -03 -14 -b1010 5 -07 -18 -b1010 9 -0; -b1010 = -0? -0C -0H -0M -0R -0W -0\ -0a -0f -b1010 i -0k -0o -b1010 r -0t -0x -b1010 { -0} -0#" -b1010 &" -0(" -0," -b1010 /" -01" -12" -05" -b1010 8" -0:" -1;" -0>" -b1010 A" -0C" -0G" -b1010 J" -0L" -0P" -#27000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#28000000 -b1011 ! -0# -b1011 % -0' -b1011 ) -0+ -b1011 - -0/ -b1011 1 -03 -04 -b1011 5 -07 -b1011 9 -0; -b1011 = -0? -0C -0H -0M -0R -0W -0\ -0a -0f -b1011 i -0k -0o -b1011 r -0t -0x -b1011 { -0} -0#" -b1011 &" -0(" -0," -b1011 /" -01" -02" -05" -b1011 8" -0:" -0>" -b1011 A" -0C" -0G" -b1011 J" -0L" -0P" -#29000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#30000000 -b1100 ! -0# -b1100 % -0' -b1100 ) -0+ -b1100 - -0/ -b1100 1 -03 -b1100 5 -07 -08 -b1100 9 -0; -b1100 = -0? -0C -0H -0M -0R -0W -0\ -0a -0f -b1100 i -0k -0o -b1100 r -0t -0x -b1100 { -0} -0#" -b1100 &" -0(" -0," -b1100 /" -01" -05" -b1100 8" -0:" -0;" -0>" -b1100 A" -0C" -0G" -b1100 J" -0L" -0P" -#31000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#32000000 -b1101 ! -0# -b1101 % -0' -b1101 ) -0+ -b1101 - -0/ -b1101 1 -03 -b1101 5 -07 -b1101 9 -0; -0< -b1101 = -0? -0C -0H -0M -0R -0W -0\ -0a -0f -b1101 i -0k -0o -b1101 r -0t -0x -b1101 { -0} -0#" -b1101 &" -0(" -0," -b1101 /" -01" -05" -b1101 8" -0:" -0>" -b1101 A" -0C" -0D" -0G" -b1101 J" -0L" -0P" -#33000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#34000000 -b1110 ! -0# -b1110 % -0' -b1110 ) -0+ -b1110 - -0/ -b1110 1 -03 -b1110 5 -07 -b1110 9 -0; -b1110 = -0? -1@ -0C -0H -0M -0R -0W -0\ -0a -0f -b1110 i -0k -0o -b1110 r -0t -0x -b1110 { -0} -0#" -b1110 &" -0(" -0," -b1110 /" -01" -05" -b1110 8" -0:" -0>" -b1110 A" -0C" -0G" -b1110 J" -0L" -1M" -0P" -#35000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#36000000 -b1111 ! -0# -b1111 % -0' -b1111 ) -0+ -b1111 - -0/ -b1111 1 -03 -b1111 5 -07 -b1111 9 -0; -b1111 = -0? -0@ -0C -0H -0M -0R -0W -0\ -0a -0f -b1111 i -0k -0o -b1111 r -0t -0x -b1111 { -0} -0#" -b1111 &" -0(" -0," -b1111 /" -01" -05" -b1111 8" -0:" -0>" -b1111 A" -0C" -0G" -b1111 J" -0L" -0M" -0P" -#37000000 -1# -1' -1+ -1/ -13 -17 -1; -1? -1C -1H -1M -1R -1W -1\ -1a -1f -1k -1o -1t -1x -1} -1#" -1(" -1," -11" -15" -1:" -1>" -1C" -1G" -1L" -1P" -#38000000 -0# -0' -0+ -0/ -03 -07 -0; -0? -0C -0H -0M -0R -0W -0\ -0a -0f -0k -0o -0t -0x -0} -0#" -0(" -0," -01" -05" -0:" -0>" -0C" -0G" -0L" -0P" diff --git a/crates/fayalite/tests/sim/expected/memories.txt b/crates/fayalite/tests/sim/expected/memories.txt index f7f88e3..afccd8a 100644 --- a/crates/fayalite/tests/sim/expected/memories.txt +++ b/crates/fayalite/tests/sim/expected/memories.txt @@ -175,12 +175,6 @@ Simulation { ], .. }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, }, memories: StatePartLayout { len: 1, @@ -568,9 +562,6 @@ Simulation { 1, ], }, - sim_only_slots: StatePart { - value: [], - }, }, io: Instance { name: ::memories, @@ -579,149 +570,1309 @@ Simulation { .. }, }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.r: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + addr: UInt<4>, + /* offset = 4 */ + en: Bool, + /* offset = 5 */ + clk: Clock, + #[hdl(flip)] /* offset = 6 */ + data: Bundle { + /* offset = 0 */ + 0: UInt<8>, + /* offset = 8 */ + 1: SInt<8>, + }, }, - }.r, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 5, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(memories: memories).memories::r.addr", + ty: UInt<4>, + }, + SlotDebugData { + name: "InstantiatedModule(memories: memories).memories::r.en", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(memories: memories).memories::r.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(memories: memories).memories::r.data.0", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories: memories).memories::r.data.1", + ty: SInt<8>, + }, + ], + .. + }, }, - }.w, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: UInt<4>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<4>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(2), + }, + ty: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(3), + }, + ty: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + 0: UInt<8>, + /* offset = 8 */ + 1: SInt<8>, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: ".0", + ty: UInt<8>, + }, + SlotDebugData { + name: ".1", + ty: SInt<8>, + }, + ], + .. + }, + }, + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: SInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], + }, + }, + }, + ], }, - }.r, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.r.addr, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.r.clk, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.r.data, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.r.data.0, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.r.data.1, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.r.en, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.addr, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.clk, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.data, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.data.0, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.data.1, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.en, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.mask, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.mask.0, - Instance { - name: ::memories, - instantiated: Module { - name: memories, - .. - }, - }.w.mask.1, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 5 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.r.addr: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<4>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<4>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.r.clk: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 2, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.r.data: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + 0: UInt<8>, + /* offset = 8 */ + 1: SInt<8>, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: ".0", + ty: UInt<8>, + }, + SlotDebugData { + name: ".1", + ty: SInt<8>, + }, + ], + .. + }, + }, + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: SInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 3, len: 2 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.r.data.0: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 3, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.r.data.1: CompiledValue { + layout: CompiledTypeLayout { + ty: SInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 4, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.r.en: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 1, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + addr: UInt<4>, + /* offset = 4 */ + en: Bool, + /* offset = 5 */ + clk: Clock, + /* offset = 6 */ + data: Bundle { + /* offset = 0 */ + 0: UInt<8>, + /* offset = 8 */ + 1: SInt<8>, + }, + /* offset = 22 */ + mask: Bundle { + /* offset = 0 */ + 0: Bool, + /* offset = 1 */ + 1: Bool, + }, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 7, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(memories: memories).memories::w.addr", + ty: UInt<4>, + }, + SlotDebugData { + name: "InstantiatedModule(memories: memories).memories::w.en", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(memories: memories).memories::w.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(memories: memories).memories::w.data.0", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories: memories).memories::w.data.1", + ty: SInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories: memories).memories::w.mask.0", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(memories: memories).memories::w.mask.1", + ty: Bool, + }, + ], + .. + }, + }, + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: UInt<4>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<4>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(2), + }, + ty: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(3), + }, + ty: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + 0: UInt<8>, + /* offset = 8 */ + 1: SInt<8>, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: ".0", + ty: UInt<8>, + }, + SlotDebugData { + name: ".1", + ty: SInt<8>, + }, + ], + .. + }, + }, + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: SInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], + }, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(5), + }, + ty: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + 0: Bool, + /* offset = 1 */ + 1: Bool, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: ".0", + ty: Bool, + }, + SlotDebugData { + name: ".1", + ty: Bool, + }, + ], + .. + }, + }, + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], + }, + }, + }, + ], + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 5, len: 7 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.addr: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<4>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<4>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 5, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.clk: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 7, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.data: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + 0: UInt<8>, + /* offset = 8 */ + 1: SInt<8>, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: ".0", + ty: UInt<8>, + }, + SlotDebugData { + name: ".1", + ty: SInt<8>, + }, + ], + .. + }, + }, + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: SInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 8, len: 2 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.data.0: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 8, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.data.1: CompiledValue { + layout: CompiledTypeLayout { + ty: SInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 9, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.en: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 6, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.mask: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + 0: Bool, + /* offset = 1 */ + 1: Bool, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: ".0", + ty: Bool, + }, + SlotDebugData { + name: ".1", + ty: Bool, + }, + ], + .. + }, + }, + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 10, len: 2 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.mask.0: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 10, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories, + instantiated: Module { + name: memories, + .. + }, + }.w.mask.1: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 11, len: 1 }, + }, + write: None, }, - did_initial_settle: true, }, - extern_modules: [], - state_ready_to_run: false, + made_initial_step: true, + needs_settle: false, trace_decls: TraceModule { name: "memories", children: [ diff --git a/crates/fayalite/tests/sim/expected/memories.vcd b/crates/fayalite/tests/sim/expected/memories.vcd index bedc354..72af410 100644 --- a/crates/fayalite/tests/sim/expected/memories.vcd +++ b/crates/fayalite/tests/sim/expected/memories.vcd @@ -24,97 +24,97 @@ $upscope $end $upscope $end $scope struct mem $end $scope struct contents $end -$scope struct \[0] $end +$scope struct [0] $end $scope struct mem $end $var reg 8 9 \0 $end $var reg 8 I \1 $end $upscope $end $upscope $end -$scope struct \[1] $end +$scope struct [1] $end $scope struct mem $end $var reg 8 : \0 $end $var reg 8 J \1 $end $upscope $end $upscope $end -$scope struct \[2] $end +$scope struct [2] $end $scope struct mem $end $var reg 8 ; \0 $end $var reg 8 K \1 $end $upscope $end $upscope $end -$scope struct \[3] $end +$scope struct [3] $end $scope struct mem $end $var reg 8 < \0 $end $var reg 8 L \1 $end $upscope $end $upscope $end -$scope struct \[4] $end +$scope struct [4] $end $scope struct mem $end $var reg 8 = \0 $end $var reg 8 M \1 $end $upscope $end $upscope $end -$scope struct \[5] $end +$scope struct [5] $end $scope struct mem $end $var reg 8 > \0 $end $var reg 8 N \1 $end $upscope $end $upscope $end -$scope struct \[6] $end +$scope struct [6] $end $scope struct mem $end $var reg 8 ? \0 $end $var reg 8 O \1 $end $upscope $end $upscope $end -$scope struct \[7] $end +$scope struct [7] $end $scope struct mem $end $var reg 8 @ \0 $end $var reg 8 P \1 $end $upscope $end $upscope $end -$scope struct \[8] $end +$scope struct [8] $end $scope struct mem $end $var reg 8 A \0 $end $var reg 8 Q \1 $end $upscope $end $upscope $end -$scope struct \[9] $end +$scope struct [9] $end $scope struct mem $end $var reg 8 B \0 $end $var reg 8 R \1 $end $upscope $end $upscope $end -$scope struct \[10] $end +$scope struct [10] $end $scope struct mem $end $var reg 8 C \0 $end $var reg 8 S \1 $end $upscope $end $upscope $end -$scope struct \[11] $end +$scope struct [11] $end $scope struct mem $end $var reg 8 D \0 $end $var reg 8 T \1 $end $upscope $end $upscope $end -$scope struct \[12] $end +$scope struct [12] $end $scope struct mem $end $var reg 8 E \0 $end $var reg 8 U \1 $end $upscope $end $upscope $end -$scope struct \[13] $end +$scope struct [13] $end $scope struct mem $end $var reg 8 F \0 $end $var reg 8 V \1 $end $upscope $end $upscope $end -$scope struct \[14] $end +$scope struct [14] $end $scope struct mem $end $var reg 8 G \0 $end $var reg 8 W \1 $end $upscope $end $upscope $end -$scope struct \[15] $end +$scope struct [15] $end $scope struct mem $end $var reg 8 H \0 $end $var reg 8 X \1 $end diff --git a/crates/fayalite/tests/sim/expected/memories2.txt b/crates/fayalite/tests/sim/expected/memories2.txt index c216104..5d90815 100644 --- a/crates/fayalite/tests/sim/expected/memories2.txt +++ b/crates/fayalite/tests/sim/expected/memories2.txt @@ -224,12 +224,6 @@ Simulation { ], .. }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, }, memories: StatePartLayout { len: 1, @@ -596,9 +590,6 @@ Simulation { 1, ], }, - sim_only_slots: StatePart { - value: [], - }, }, io: Instance { name: ::memories2, @@ -607,79 +598,514 @@ Simulation { .. }, }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. + }, + }.rw: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + addr: UInt<3>, + /* offset = 3 */ + en: Bool, + /* offset = 4 */ + clk: Clock, + #[hdl(flip)] /* offset = 5 */ + rdata: UInt<2>, + /* offset = 7 */ + wmode: Bool, + /* offset = 8 */ + wdata: UInt<2>, + /* offset = 10 */ + wmask: Bool, }, - }.rw, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 7, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(memories2: memories2).memories2::rw.addr", + ty: UInt<3>, + }, + SlotDebugData { + name: "InstantiatedModule(memories2: memories2).memories2::rw.en", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(memories2: memories2).memories2::rw.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(memories2: memories2).memories2::rw.rdata", + ty: UInt<2>, + }, + SlotDebugData { + name: "InstantiatedModule(memories2: memories2).memories2::rw.wmode", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(memories2: memories2).memories2::rw.wdata", + ty: UInt<2>, + }, + SlotDebugData { + name: "InstantiatedModule(memories2: memories2).memories2::rw.wmask", + ty: Bool, + }, + ], + .. + }, }, - }.rw, - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: UInt<3>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<3>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(2), + }, + ty: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(3), + }, + ty: CompiledTypeLayout { + ty: UInt<2>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<2>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(4), + }, + ty: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(5), + }, + ty: CompiledTypeLayout { + ty: UInt<2>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<2>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(6), + }, + ty: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], }, - }.rw.addr, - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. - }, - }.rw.clk, - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. - }, - }.rw.en, - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. - }, - }.rw.rdata, - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. - }, - }.rw.wdata, - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. - }, - }.rw.wmask, - Instance { - name: ::memories2, - instantiated: Module { - name: memories2, - .. - }, - }.rw.wmode, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 7 }, + }, + write: None, + }, + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. + }, + }.rw.addr: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<3>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<3>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. + }, + }.rw.clk: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 2, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. + }, + }.rw.en: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 1, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. + }, + }.rw.rdata: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<2>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<2>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 3, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. + }, + }.rw.wdata: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<2>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<2>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 5, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. + }, + }.rw.wmask: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 6, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories2, + instantiated: Module { + name: memories2, + .. + }, + }.rw.wmode: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 4, len: 1 }, + }, + write: None, }, - did_initial_settle: true, }, - extern_modules: [], - state_ready_to_run: false, + made_initial_step: true, + needs_settle: false, trace_decls: TraceModule { name: "memories2", children: [ diff --git a/crates/fayalite/tests/sim/expected/memories2.vcd b/crates/fayalite/tests/sim/expected/memories2.vcd index 4039754..bd48f24 100644 --- a/crates/fayalite/tests/sim/expected/memories2.vcd +++ b/crates/fayalite/tests/sim/expected/memories2.vcd @@ -11,31 +11,31 @@ $var wire 1 ' wmask $end $upscope $end $scope struct mem $end $scope struct contents $end -$scope struct \[0] $end +$scope struct [0] $end $scope struct mem $end $var string 1 1 \$tag $end $var reg 1 6 HdlSome $end $upscope $end $upscope $end -$scope struct \[1] $end +$scope struct [1] $end $scope struct mem $end $var string 1 2 \$tag $end $var reg 1 7 HdlSome $end $upscope $end $upscope $end -$scope struct \[2] $end +$scope struct [2] $end $scope struct mem $end $var string 1 3 \$tag $end $var reg 1 8 HdlSome $end $upscope $end $upscope $end -$scope struct \[3] $end +$scope struct [3] $end $scope struct mem $end $var string 1 4 \$tag $end $var reg 1 9 HdlSome $end $upscope $end $upscope $end -$scope struct \[4] $end +$scope struct [4] $end $scope struct mem $end $var string 1 5 \$tag $end $var reg 1 : HdlSome $end diff --git a/crates/fayalite/tests/sim/expected/memories3.txt b/crates/fayalite/tests/sim/expected/memories3.txt index 8114c7e..7860bc5 100644 --- a/crates/fayalite/tests/sim/expected/memories3.txt +++ b/crates/fayalite/tests/sim/expected/memories3.txt @@ -503,12 +503,6 @@ Simulation { ], .. }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, }, memories: StatePartLayout { len: 1, @@ -1484,9 +1478,6 @@ Simulation { 0, ], }, - sim_only_slots: StatePart { - value: [], - }, }, io: Instance { name: ::memories3, @@ -1495,275 +1486,1882 @@ Simulation { .. }, }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + addr: UInt<3>, + /* offset = 3 */ + en: Bool, + /* offset = 4 */ + clk: Clock, + #[hdl(flip)] /* offset = 5 */ + data: Array, 8>, }, - }.r, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 11, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::r.addr", + ty: UInt<3>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::r.en", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::r.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::r.data[0]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::r.data[1]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::r.data[2]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::r.data[3]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::r.data[4]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::r.data[5]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::r.data[6]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::r.data[7]", + ty: UInt<8>, + }, + ], + .. + }, }, - }.w, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: UInt<3>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<3>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(2), + }, + ty: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(3), + }, + ty: CompiledTypeLayout { + ty: Array, 8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 8, + debug_data: [ + SlotDebugData { + name: "[0]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[1]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[2]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[3]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[4]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[5]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[6]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[7]", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Array { + element: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + }, + }, + ], }, - }.r, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.addr, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.clk, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[0], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[1], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[2], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[3], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[4], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[5], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[6], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.data[7], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.r.en, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.addr, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.clk, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[0], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[1], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[2], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[3], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[4], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[5], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[6], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.data[7], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.en, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask, - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[0], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[1], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[2], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[3], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[4], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[5], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[6], - Instance { - name: ::memories3, - instantiated: Module { - name: memories3, - .. - }, - }.w.mask[7], + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 11 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.addr: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<3>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<3>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.clk: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 2, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data: CompiledValue { + layout: CompiledTypeLayout { + ty: Array, 8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 8, + debug_data: [ + SlotDebugData { + name: "[0]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[1]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[2]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[3]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[4]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[5]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[6]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[7]", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Array { + element: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 3, len: 8 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[0]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 3, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[1]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 4, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[2]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 5, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[3]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 6, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[4]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 7, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[5]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 8, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[6]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 9, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.data[7]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 10, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.r.en: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 1, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + addr: UInt<3>, + /* offset = 3 */ + en: Bool, + /* offset = 4 */ + clk: Clock, + /* offset = 5 */ + data: Array, 8>, + /* offset = 69 */ + mask: Array, + }, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 19, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.addr", + ty: UInt<3>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.en", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.data[0]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.data[1]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.data[2]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.data[3]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.data[4]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.data[5]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.data[6]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.data[7]", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.mask[0]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.mask[1]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.mask[2]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.mask[3]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.mask[4]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.mask[5]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.mask[6]", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(memories3: memories3).memories3::w.mask[7]", + ty: Bool, + }, + ], + .. + }, + }, + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: UInt<3>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<3>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(2), + }, + ty: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(3), + }, + ty: CompiledTypeLayout { + ty: Array, 8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 8, + debug_data: [ + SlotDebugData { + name: "[0]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[1]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[2]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[3]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[4]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[5]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[6]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[7]", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Array { + element: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(11), + }, + ty: CompiledTypeLayout { + ty: Array, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 8, + debug_data: [ + SlotDebugData { + name: "[0]", + ty: Bool, + }, + SlotDebugData { + name: "[1]", + ty: Bool, + }, + SlotDebugData { + name: "[2]", + ty: Bool, + }, + SlotDebugData { + name: "[3]", + ty: Bool, + }, + SlotDebugData { + name: "[4]", + ty: Bool, + }, + SlotDebugData { + name: "[5]", + ty: Bool, + }, + SlotDebugData { + name: "[6]", + ty: Bool, + }, + SlotDebugData { + name: "[7]", + ty: Bool, + }, + ], + .. + }, + }, + body: Array { + element: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + }, + }, + ], + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 11, len: 19 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.addr: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<3>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<3>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 11, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.clk: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 13, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data: CompiledValue { + layout: CompiledTypeLayout { + ty: Array, 8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 8, + debug_data: [ + SlotDebugData { + name: "[0]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[1]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[2]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[3]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[4]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[5]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[6]", + ty: UInt<8>, + }, + SlotDebugData { + name: "[7]", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Array { + element: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 14, len: 8 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[0]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 14, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[1]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 15, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[2]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 16, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[3]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 17, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[4]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 18, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[5]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 19, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[6]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 20, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.data[7]: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<8>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 21, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.en: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 12, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask: CompiledValue { + layout: CompiledTypeLayout { + ty: Array, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 8, + debug_data: [ + SlotDebugData { + name: "[0]", + ty: Bool, + }, + SlotDebugData { + name: "[1]", + ty: Bool, + }, + SlotDebugData { + name: "[2]", + ty: Bool, + }, + SlotDebugData { + name: "[3]", + ty: Bool, + }, + SlotDebugData { + name: "[4]", + ty: Bool, + }, + SlotDebugData { + name: "[5]", + ty: Bool, + }, + SlotDebugData { + name: "[6]", + ty: Bool, + }, + SlotDebugData { + name: "[7]", + ty: Bool, + }, + ], + .. + }, + }, + body: Array { + element: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 22, len: 8 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[0]: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 22, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[1]: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 23, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[2]: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 24, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[3]: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 25, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[4]: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 26, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[5]: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 27, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[6]: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 28, len: 1 }, + }, + write: None, + }, + Instance { + name: ::memories3, + instantiated: Module { + name: memories3, + .. + }, + }.w.mask[7]: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 29, len: 1 }, + }, + write: None, }, - did_initial_settle: true, }, - extern_modules: [], - state_ready_to_run: false, + made_initial_step: true, + needs_settle: false, trace_decls: TraceModule { name: "memories3", children: [ diff --git a/crates/fayalite/tests/sim/expected/memories3.vcd b/crates/fayalite/tests/sim/expected/memories3.vcd index 5768560..328fcaa 100644 --- a/crates/fayalite/tests/sim/expected/memories3.vcd +++ b/crates/fayalite/tests/sim/expected/memories3.vcd @@ -42,7 +42,7 @@ $upscope $end $upscope $end $scope struct mem $end $scope struct contents $end -$scope struct \[0] $end +$scope struct [0] $end $scope struct mem $end $var reg 8 ] \[0] $end $var reg 8 e \[1] $end @@ -54,7 +54,7 @@ $var reg 8 /" \[6] $end $var reg 8 7" \[7] $end $upscope $end $upscope $end -$scope struct \[1] $end +$scope struct [1] $end $scope struct mem $end $var reg 8 ^ \[0] $end $var reg 8 f \[1] $end @@ -66,7 +66,7 @@ $var reg 8 0" \[6] $end $var reg 8 8" \[7] $end $upscope $end $upscope $end -$scope struct \[2] $end +$scope struct [2] $end $scope struct mem $end $var reg 8 _ \[0] $end $var reg 8 g \[1] $end @@ -78,7 +78,7 @@ $var reg 8 1" \[6] $end $var reg 8 9" \[7] $end $upscope $end $upscope $end -$scope struct \[3] $end +$scope struct [3] $end $scope struct mem $end $var reg 8 ` \[0] $end $var reg 8 h \[1] $end @@ -90,7 +90,7 @@ $var reg 8 2" \[6] $end $var reg 8 :" \[7] $end $upscope $end $upscope $end -$scope struct \[4] $end +$scope struct [4] $end $scope struct mem $end $var reg 8 a \[0] $end $var reg 8 i \[1] $end @@ -102,7 +102,7 @@ $var reg 8 3" \[6] $end $var reg 8 ;" \[7] $end $upscope $end $upscope $end -$scope struct \[5] $end +$scope struct [5] $end $scope struct mem $end $var reg 8 b \[0] $end $var reg 8 j \[1] $end @@ -114,7 +114,7 @@ $var reg 8 4" \[6] $end $var reg 8 <" \[7] $end $upscope $end $upscope $end -$scope struct \[6] $end +$scope struct [6] $end $scope struct mem $end $var reg 8 c \[0] $end $var reg 8 k \[1] $end @@ -126,7 +126,7 @@ $var reg 8 5" \[6] $end $var reg 8 =" \[7] $end $upscope $end $upscope $end -$scope struct \[7] $end +$scope struct [7] $end $scope struct mem $end $var reg 8 d \[0] $end $var reg 8 l \[1] $end diff --git a/crates/fayalite/tests/sim/expected/mod1.txt b/crates/fayalite/tests/sim/expected/mod1.txt index 4ef02b2..5c2b7eb 100644 --- a/crates/fayalite/tests/sim/expected/mod1.txt +++ b/crates/fayalite/tests/sim/expected/mod1.txt @@ -82,12 +82,6 @@ Simulation { ], .. }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, }, memories: StatePartLayout { len: 0, @@ -214,9 +208,6 @@ Simulation { 15, ], }, - sim_only_slots: StatePart { - value: [], - }, }, io: Instance { name: ::mod1, @@ -225,58 +216,313 @@ Simulation { .. }, }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::mod1, - instantiated: Module { - name: mod1, - .. + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::mod1, + instantiated: Module { + name: mod1, + .. + }, + }.o: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + #[hdl(flip)] /* offset = 0 */ + i: UInt<4>, + /* offset = 4 */ + o: SInt<2>, + #[hdl(flip)] /* offset = 6 */ + i2: SInt<2>, + /* offset = 8 */ + o2: UInt<4>, }, - }.o, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::mod1, - instantiated: Module { - name: mod1, - .. + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 4, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(mod1: mod1).mod1::o.i", + ty: UInt<4>, + }, + SlotDebugData { + name: "InstantiatedModule(mod1: mod1).mod1::o.o", + ty: SInt<2>, + }, + SlotDebugData { + name: "InstantiatedModule(mod1: mod1).mod1::o.i2", + ty: SInt<2>, + }, + SlotDebugData { + name: "InstantiatedModule(mod1: mod1).mod1::o.o2", + ty: UInt<4>, + }, + ], + .. + }, }, - }.o, - Instance { - name: ::mod1, - instantiated: Module { - name: mod1, - .. + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: UInt<4>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<4>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: SInt<2>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SInt<2>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(2), + }, + ty: CompiledTypeLayout { + ty: SInt<2>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SInt<2>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(3), + }, + ty: CompiledTypeLayout { + ty: UInt<4>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<4>, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], }, - }.o.i, - Instance { - name: ::mod1, - instantiated: Module { - name: mod1, - .. - }, - }.o.i2, - Instance { - name: ::mod1, - instantiated: Module { - name: mod1, - .. - }, - }.o.o, - Instance { - name: ::mod1, - instantiated: Module { - name: mod1, - .. - }, - }.o.o2, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 4 }, + }, + write: None, + }, + Instance { + name: ::mod1, + instantiated: Module { + name: mod1, + .. + }, + }.o.i: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<4>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<4>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, + }, + Instance { + name: ::mod1, + instantiated: Module { + name: mod1, + .. + }, + }.o.i2: CompiledValue { + layout: CompiledTypeLayout { + ty: SInt<2>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SInt<2>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 2, len: 1 }, + }, + write: None, + }, + Instance { + name: ::mod1, + instantiated: Module { + name: mod1, + .. + }, + }.o.o: CompiledValue { + layout: CompiledTypeLayout { + ty: SInt<2>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SInt<2>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 1, len: 1 }, + }, + write: None, + }, + Instance { + name: ::mod1, + instantiated: Module { + name: mod1, + .. + }, + }.o.o2: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<4>, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: UInt<4>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 3, len: 1 }, + }, + write: None, }, - did_initial_settle: true, }, - extern_modules: [], - state_ready_to_run: false, + made_initial_step: true, + needs_settle: false, trace_decls: TraceModule { name: "mod1", children: [ diff --git a/crates/fayalite/tests/sim/expected/ripple_counter.txt b/crates/fayalite/tests/sim/expected/ripple_counter.txt deleted file mode 100644 index 9e4e0d1..0000000 --- a/crates/fayalite/tests/sim/expected/ripple_counter.txt +++ /dev/null @@ -1,1603 +0,0 @@ -Simulation { - state: State { - insns: Insns { - state_layout: StateLayout { - ty: TypeLayout { - small_slots: StatePartLayout { - len: 9, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - big_slots: StatePartLayout { - len: 58, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::o", - ty: UInt<6>, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[0]", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[1]", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[2]", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[3]", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[4]", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[5]", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: UInt<1>, - }, - SlotDebugData { - name: "", - ty: UInt<1>, - }, - SlotDebugData { - name: "", - ty: UInt<2>, - }, - SlotDebugData { - name: "", - ty: UInt<2>, - }, - SlotDebugData { - name: "", - ty: UInt<1>, - }, - SlotDebugData { - name: "", - ty: UInt<3>, - }, - SlotDebugData { - name: "", - ty: UInt<3>, - }, - SlotDebugData { - name: "", - ty: UInt<1>, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: UInt<4>, - }, - SlotDebugData { - name: "", - ty: UInt<1>, - }, - SlotDebugData { - name: "", - ty: UInt<5>, - }, - SlotDebugData { - name: "", - ty: UInt<5>, - }, - SlotDebugData { - name: "", - ty: UInt<1>, - }, - SlotDebugData { - name: "", - ty: UInt<6>, - }, - SlotDebugData { - name: "", - ty: UInt<6>, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_0", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_0$next", - ty: Bool, - }, - SlotDebugData { - name: ".clk", - ty: Clock, - }, - SlotDebugData { - name: ".rst", - ty: SyncReset, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: SyncReset, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_1.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_1.o", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter.bit_reg_1: sw_reg).sw_reg::clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter.bit_reg_1: sw_reg).sw_reg::o", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_2", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_2$next", - ty: Bool, - }, - SlotDebugData { - name: ".clk", - ty: Clock, - }, - SlotDebugData { - name: ".rst", - ty: SyncReset, - }, - SlotDebugData { - name: "", - ty: Clock, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_3.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_3.o", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter.bit_reg_3: sw_reg).sw_reg::clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter.bit_reg_3: sw_reg).sw_reg::o", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_4", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_4$next", - ty: Bool, - }, - SlotDebugData { - name: ".clk", - ty: Clock, - }, - SlotDebugData { - name: ".rst", - ty: SyncReset, - }, - SlotDebugData { - name: "", - ty: Clock, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_5.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_5.o", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter.bit_reg_5: sw_reg).sw_reg::clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(ripple_counter.bit_reg_5: sw_reg).sw_reg::o", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - memories: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - insns: [ - // at: module-XXXXXXXXXX.rs:9:1 - 0: Copy { - dest: StatePartIndex(54), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_5.o", ty: Bool }, - src: StatePartIndex(56), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter.bit_reg_5: sw_reg).sw_reg::o", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:11:1 - 1: Copy { - dest: StatePartIndex(7), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[5]", ty: Bool }, - src: StatePartIndex(54), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_5.o", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 2: NotU { - dest: StatePartIndex(52), // (0x1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(47), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_4", ty: Bool }, - width: 1, - }, - // at: module-XXXXXXXXXX.rs:8:1 - 3: Copy { - dest: StatePartIndex(48), // (0x1) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_4$next", ty: Bool }, - src: StatePartIndex(52), // (0x1) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:7:1 - 4: Copy { - dest: StatePartIndex(6), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[4]", ty: Bool }, - src: StatePartIndex(47), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_4", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 5: Copy { - dest: StatePartIndex(57), // (0x0) SlotDebugData { name: "", ty: Clock }, - src: StatePartIndex(6), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[4]", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:10:1 - 6: Copy { - dest: StatePartIndex(53), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_5.clk", ty: Clock }, - src: StatePartIndex(57), // (0x0) SlotDebugData { name: "", ty: Clock }, - }, - // at: module-XXXXXXXXXX.rs:9:1 - 7: Copy { - dest: StatePartIndex(55), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter.bit_reg_5: sw_reg).sw_reg::clk", ty: Clock }, - src: StatePartIndex(53), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_5.clk", ty: Clock }, - }, - 8: Copy { - dest: StatePartIndex(43), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_3.o", ty: Bool }, - src: StatePartIndex(45), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter.bit_reg_3: sw_reg).sw_reg::o", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:11:1 - 9: Copy { - dest: StatePartIndex(5), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[3]", ty: Bool }, - src: StatePartIndex(43), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_3.o", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 10: Copy { - dest: StatePartIndex(51), // (0x0) SlotDebugData { name: "", ty: Clock }, - src: StatePartIndex(5), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[3]", ty: Bool }, - }, - 11: NotU { - dest: StatePartIndex(41), // (0x1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(36), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_2", ty: Bool }, - width: 1, - }, - // at: module-XXXXXXXXXX.rs:8:1 - 12: Copy { - dest: StatePartIndex(37), // (0x1) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_2$next", ty: Bool }, - src: StatePartIndex(41), // (0x1) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:7:1 - 13: Copy { - dest: StatePartIndex(4), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[2]", ty: Bool }, - src: StatePartIndex(36), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_2", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 14: Copy { - dest: StatePartIndex(46), // (0x0) SlotDebugData { name: "", ty: Clock }, - src: StatePartIndex(4), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[2]", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:10:1 - 15: Copy { - dest: StatePartIndex(42), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_3.clk", ty: Clock }, - src: StatePartIndex(46), // (0x0) SlotDebugData { name: "", ty: Clock }, - }, - // at: module-XXXXXXXXXX.rs:9:1 - 16: Copy { - dest: StatePartIndex(44), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter.bit_reg_3: sw_reg).sw_reg::clk", ty: Clock }, - src: StatePartIndex(42), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_3.clk", ty: Clock }, - }, - 17: Copy { - dest: StatePartIndex(32), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_1.o", ty: Bool }, - src: StatePartIndex(34), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter.bit_reg_1: sw_reg).sw_reg::o", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:11:1 - 18: Copy { - dest: StatePartIndex(3), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[1]", ty: Bool }, - src: StatePartIndex(32), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_1.o", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 19: Copy { - dest: StatePartIndex(40), // (0x0) SlotDebugData { name: "", ty: Clock }, - src: StatePartIndex(3), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[1]", ty: Bool }, - }, - 20: NotU { - dest: StatePartIndex(30), // (0x1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(24), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_0", ty: Bool }, - width: 1, - }, - // at: module-XXXXXXXXXX.rs:8:1 - 21: Copy { - dest: StatePartIndex(25), // (0x1) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_0$next", ty: Bool }, - src: StatePartIndex(30), // (0x1) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:7:1 - 22: Copy { - dest: StatePartIndex(2), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[0]", ty: Bool }, - src: StatePartIndex(24), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_0", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 23: Copy { - dest: StatePartIndex(35), // (0x0) SlotDebugData { name: "", ty: Clock }, - src: StatePartIndex(2), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[0]", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:10:1 - 24: Copy { - dest: StatePartIndex(31), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_1.clk", ty: Clock }, - src: StatePartIndex(35), // (0x0) SlotDebugData { name: "", ty: Clock }, - }, - // at: module-XXXXXXXXXX.rs:9:1 - 25: Copy { - dest: StatePartIndex(33), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter.bit_reg_1: sw_reg).sw_reg::clk", ty: Clock }, - src: StatePartIndex(31), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_1.clk", ty: Clock }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 26: Const { - dest: StatePartIndex(28), // (0x0) SlotDebugData { name: "", ty: Bool }, - value: 0x0, - }, - 27: Copy { - dest: StatePartIndex(29), // (0x0) SlotDebugData { name: "", ty: SyncReset }, - src: StatePartIndex(28), // (0x0) SlotDebugData { name: "", ty: Bool }, - }, - 28: Copy { - dest: StatePartIndex(26), // (0x1) SlotDebugData { name: ".clk", ty: Clock }, - src: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::clk", ty: Clock }, - }, - 29: Copy { - dest: StatePartIndex(27), // (0x0) SlotDebugData { name: ".rst", ty: SyncReset }, - src: StatePartIndex(29), // (0x0) SlotDebugData { name: "", ty: SyncReset }, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 30: IsNonZeroDestIsSmall { - dest: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(26), // (0x1) SlotDebugData { name: ".clk", ty: Clock }, - }, - 31: AndSmall { - dest: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(0), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 32: Copy { - dest: StatePartIndex(38), // (0x0) SlotDebugData { name: ".clk", ty: Clock }, - src: StatePartIndex(40), // (0x0) SlotDebugData { name: "", ty: Clock }, - }, - 33: Copy { - dest: StatePartIndex(39), // (0x0) SlotDebugData { name: ".rst", ty: SyncReset }, - src: StatePartIndex(29), // (0x0) SlotDebugData { name: "", ty: SyncReset }, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 34: IsNonZeroDestIsSmall { - dest: StatePartIndex(5), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(38), // (0x0) SlotDebugData { name: ".clk", ty: Clock }, - }, - 35: AndSmall { - dest: StatePartIndex(4), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(5), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(3), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 36: Copy { - dest: StatePartIndex(49), // (0x0) SlotDebugData { name: ".clk", ty: Clock }, - src: StatePartIndex(51), // (0x0) SlotDebugData { name: "", ty: Clock }, - }, - 37: Copy { - dest: StatePartIndex(50), // (0x0) SlotDebugData { name: ".rst", ty: SyncReset }, - src: StatePartIndex(29), // (0x0) SlotDebugData { name: "", ty: SyncReset }, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 38: IsNonZeroDestIsSmall { - dest: StatePartIndex(8), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(49), // (0x0) SlotDebugData { name: ".clk", ty: Clock }, - }, - 39: AndSmall { - dest: StatePartIndex(7), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(8), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(6), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 40: Copy { - dest: StatePartIndex(21), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(7), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[5]", ty: Bool }, - }, - 41: Shl { - dest: StatePartIndex(22), // (0x0) SlotDebugData { name: "", ty: UInt<6> }, - lhs: StatePartIndex(21), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - rhs: 5, - }, - 42: Copy { - dest: StatePartIndex(18), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(6), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[4]", ty: Bool }, - }, - 43: Shl { - dest: StatePartIndex(19), // (0x0) SlotDebugData { name: "", ty: UInt<5> }, - lhs: StatePartIndex(18), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - rhs: 4, - }, - 44: Copy { - dest: StatePartIndex(15), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(5), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[3]", ty: Bool }, - }, - 45: Shl { - dest: StatePartIndex(16), // (0x0) SlotDebugData { name: "", ty: UInt<4> }, - lhs: StatePartIndex(15), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - rhs: 3, - }, - 46: Copy { - dest: StatePartIndex(12), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(4), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[2]", ty: Bool }, - }, - 47: Shl { - dest: StatePartIndex(13), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, - lhs: StatePartIndex(12), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - rhs: 2, - }, - 48: Copy { - dest: StatePartIndex(9), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(3), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[1]", ty: Bool }, - }, - 49: Shl { - dest: StatePartIndex(10), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, - lhs: StatePartIndex(9), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - rhs: 1, - }, - 50: Copy { - dest: StatePartIndex(8), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - src: StatePartIndex(2), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bits[0]", ty: Bool }, - }, - 51: Or { - dest: StatePartIndex(11), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, - lhs: StatePartIndex(8), // (0x0) SlotDebugData { name: "", ty: UInt<1> }, - rhs: StatePartIndex(10), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, - }, - 52: Or { - dest: StatePartIndex(14), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, - lhs: StatePartIndex(11), // (0x0) SlotDebugData { name: "", ty: UInt<2> }, - rhs: StatePartIndex(13), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, - }, - 53: Or { - dest: StatePartIndex(17), // (0x0) SlotDebugData { name: "", ty: UInt<4> }, - lhs: StatePartIndex(14), // (0x0) SlotDebugData { name: "", ty: UInt<3> }, - rhs: StatePartIndex(16), // (0x0) SlotDebugData { name: "", ty: UInt<4> }, - }, - 54: Or { - dest: StatePartIndex(20), // (0x0) SlotDebugData { name: "", ty: UInt<5> }, - lhs: StatePartIndex(17), // (0x0) SlotDebugData { name: "", ty: UInt<4> }, - rhs: StatePartIndex(19), // (0x0) SlotDebugData { name: "", ty: UInt<5> }, - }, - 55: Or { - dest: StatePartIndex(23), // (0x0) SlotDebugData { name: "", ty: UInt<6> }, - lhs: StatePartIndex(20), // (0x0) SlotDebugData { name: "", ty: UInt<5> }, - rhs: StatePartIndex(22), // (0x0) SlotDebugData { name: "", ty: UInt<6> }, - }, - // at: module-XXXXXXXXXX.rs:5:1 - 56: Copy { - dest: StatePartIndex(1), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::o", ty: UInt<6> }, - src: StatePartIndex(23), // (0x0) SlotDebugData { name: "", ty: UInt<6> }, - }, - // at: module-XXXXXXXXXX.rs:6:1 - 57: BranchIfSmallZero { - target: 59, - value: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 58: Copy { - dest: StatePartIndex(24), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_0", ty: Bool }, - src: StatePartIndex(25), // (0x1) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_0$next", ty: Bool }, - }, - 59: BranchIfSmallZero { - target: 61, - value: StatePartIndex(4), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 60: Copy { - dest: StatePartIndex(36), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_2", ty: Bool }, - src: StatePartIndex(37), // (0x1) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_2$next", ty: Bool }, - }, - 61: BranchIfSmallZero { - target: 63, - value: StatePartIndex(7), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 62: Copy { - dest: StatePartIndex(47), // (0x0) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_4", ty: Bool }, - src: StatePartIndex(48), // (0x1) SlotDebugData { name: "InstantiatedModule(ripple_counter: ripple_counter).ripple_counter::bit_reg_4$next", ty: Bool }, - }, - 63: XorSmallImmediate { - dest: StatePartIndex(0), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 64: XorSmallImmediate { - dest: StatePartIndex(3), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(5), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - 65: XorSmallImmediate { - dest: StatePartIndex(6), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(8), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 66: Return, - ], - .. - }, - pc: 66, - memory_write_log: [], - memories: StatePart { - value: [], - }, - small_slots: StatePart { - value: [ - 0, - 0, - 1, - 1, - 0, - 0, - 1, - 0, - 0, - ], - }, - big_slots: StatePart { - value: [ - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - ], - }, - sim_only_slots: StatePart { - value: [], - }, - }, - io: Instance { - name: ::ripple_counter, - instantiated: Module { - name: ripple_counter, - .. - }, - }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::ripple_counter, - instantiated: Module { - name: ripple_counter, - .. - }, - }.clk, - Instance { - name: ::ripple_counter, - instantiated: Module { - name: ripple_counter, - .. - }, - }.o, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::ripple_counter, - instantiated: Module { - name: ripple_counter, - .. - }, - }.clk, - Instance { - name: ::ripple_counter, - instantiated: Module { - name: ripple_counter, - .. - }, - }.o, - }, - did_initial_settle: true, - }, - extern_modules: [ - SimulationExternModuleState { - module_state: SimulationModuleState { - base_targets: [ - ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }, - ], - uninitialized_ios: {}, - io_targets: { - ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }, - }, - did_initial_settle: true, - }, - sim: ExternModuleSimulation { - generator: SimGeneratorFn { - args: ( - ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }, - ), - f: ..., - }, - sim_io_to_generator_map: { - ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }: ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }: ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }, - }, - source_location: SourceLocation( - module-XXXXXXXXXX-2.rs:4:1, - ), - }, - running_generator: Some( - ..., - ), - wait_targets: { - Change { - key: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(ripple_counter.bit_reg_1: sw_reg).sw_reg::clk", - ty: Clock, - }, - ], - .. - }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 3, len: 0 }, - big_slots: StatePartIndexRange { start: 33, len: 1 }, - sim_only_slots: StatePartIndexRange { start: 0, len: 0 }, - }, - write: None, - }, - value: SimValue { - ty: Clock, - value: OpaqueSimValue { - bits: 0x0_u1, - sim_only_values: [], - }, - }, - }, - }, - }, - SimulationExternModuleState { - module_state: SimulationModuleState { - base_targets: [ - ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }, - ], - uninitialized_ios: {}, - io_targets: { - ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }, - }, - did_initial_settle: true, - }, - sim: ExternModuleSimulation { - generator: SimGeneratorFn { - args: ( - ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }, - ), - f: ..., - }, - sim_io_to_generator_map: { - ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }: ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }: ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }, - }, - source_location: SourceLocation( - module-XXXXXXXXXX-2.rs:4:1, - ), - }, - running_generator: Some( - ..., - ), - wait_targets: { - Change { - key: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(ripple_counter.bit_reg_3: sw_reg).sw_reg::clk", - ty: Clock, - }, - ], - .. - }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 6, len: 0 }, - big_slots: StatePartIndexRange { start: 44, len: 1 }, - sim_only_slots: StatePartIndexRange { start: 0, len: 0 }, - }, - write: None, - }, - value: SimValue { - ty: Clock, - value: OpaqueSimValue { - bits: 0x0_u1, - sim_only_values: [], - }, - }, - }, - }, - }, - SimulationExternModuleState { - module_state: SimulationModuleState { - base_targets: [ - ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }, - ], - uninitialized_ios: {}, - io_targets: { - ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }, - }, - did_initial_settle: true, - }, - sim: ExternModuleSimulation { - generator: SimGeneratorFn { - args: ( - ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }, - ), - f: ..., - }, - sim_io_to_generator_map: { - ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }: ModuleIO { - name: sw_reg::clk, - is_input: true, - ty: Clock, - .. - }, - ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }: ModuleIO { - name: sw_reg::o, - is_input: false, - ty: Bool, - .. - }, - }, - source_location: SourceLocation( - module-XXXXXXXXXX-2.rs:4:1, - ), - }, - running_generator: Some( - ..., - ), - wait_targets: { - Change { - key: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(ripple_counter.bit_reg_5: sw_reg).sw_reg::clk", - ty: Clock, - }, - ], - .. - }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 9, len: 0 }, - big_slots: StatePartIndexRange { start: 55, len: 1 }, - sim_only_slots: StatePartIndexRange { start: 0, len: 0 }, - }, - write: None, - }, - value: SimValue { - ty: Clock, - value: OpaqueSimValue { - bits: 0x0_u1, - sim_only_values: [], - }, - }, - }, - }, - }, - ], - state_ready_to_run: false, - trace_decls: TraceModule { - name: "ripple_counter", - children: [ - TraceModuleIO { - name: "clk", - child: TraceClock { - location: TraceScalarId(0), - name: "clk", - flow: Source, - }, - ty: Clock, - flow: Source, - }, - TraceModuleIO { - name: "o", - child: TraceUInt { - location: TraceScalarId(1), - name: "o", - ty: UInt<6>, - flow: Sink, - }, - ty: UInt<6>, - flow: Sink, - }, - TraceWire { - name: "bits", - child: TraceArray { - name: "bits", - elements: [ - TraceBool { - location: TraceScalarId(2), - name: "[0]", - flow: Duplex, - }, - TraceBool { - location: TraceScalarId(3), - name: "[1]", - flow: Duplex, - }, - TraceBool { - location: TraceScalarId(4), - name: "[2]", - flow: Duplex, - }, - TraceBool { - location: TraceScalarId(5), - name: "[3]", - flow: Duplex, - }, - TraceBool { - location: TraceScalarId(6), - name: "[4]", - flow: Duplex, - }, - TraceBool { - location: TraceScalarId(7), - name: "[5]", - flow: Duplex, - }, - ], - ty: Array, - flow: Duplex, - }, - ty: Array, - }, - TraceReg { - name: "bit_reg_0", - child: TraceBool { - location: TraceScalarId(8), - name: "bit_reg_0", - flow: Duplex, - }, - ty: Bool, - }, - TraceInstance { - name: "bit_reg_1", - instance_io: TraceBundle { - name: "bit_reg_1", - fields: [ - TraceClock { - location: TraceScalarId(11), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(12), - name: "o", - flow: Source, - }, - ], - ty: Bundle { - #[hdl(flip)] /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - o: Bool, - }, - flow: Source, - }, - module: TraceModule { - name: "sw_reg", - children: [ - TraceModuleIO { - name: "clk", - child: TraceClock { - location: TraceScalarId(9), - name: "clk", - flow: Source, - }, - ty: Clock, - flow: Source, - }, - TraceModuleIO { - name: "o", - child: TraceBool { - location: TraceScalarId(10), - name: "o", - flow: Sink, - }, - ty: Bool, - flow: Sink, - }, - ], - }, - ty: Bundle { - #[hdl(flip)] /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - o: Bool, - }, - }, - TraceReg { - name: "bit_reg_2", - child: TraceBool { - location: TraceScalarId(13), - name: "bit_reg_2", - flow: Duplex, - }, - ty: Bool, - }, - TraceInstance { - name: "bit_reg_3", - instance_io: TraceBundle { - name: "bit_reg_3", - fields: [ - TraceClock { - location: TraceScalarId(16), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(17), - name: "o", - flow: Source, - }, - ], - ty: Bundle { - #[hdl(flip)] /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - o: Bool, - }, - flow: Source, - }, - module: TraceModule { - name: "sw_reg", - children: [ - TraceModuleIO { - name: "clk", - child: TraceClock { - location: TraceScalarId(14), - name: "clk", - flow: Source, - }, - ty: Clock, - flow: Source, - }, - TraceModuleIO { - name: "o", - child: TraceBool { - location: TraceScalarId(15), - name: "o", - flow: Sink, - }, - ty: Bool, - flow: Sink, - }, - ], - }, - ty: Bundle { - #[hdl(flip)] /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - o: Bool, - }, - }, - TraceReg { - name: "bit_reg_4", - child: TraceBool { - location: TraceScalarId(18), - name: "bit_reg_4", - flow: Duplex, - }, - ty: Bool, - }, - TraceInstance { - name: "bit_reg_5", - instance_io: TraceBundle { - name: "bit_reg_5", - fields: [ - TraceClock { - location: TraceScalarId(21), - name: "clk", - flow: Sink, - }, - TraceBool { - location: TraceScalarId(22), - name: "o", - flow: Source, - }, - ], - ty: Bundle { - #[hdl(flip)] /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - o: Bool, - }, - flow: Source, - }, - module: TraceModule { - name: "sw_reg", - children: [ - TraceModuleIO { - name: "clk", - child: TraceClock { - location: TraceScalarId(19), - name: "clk", - flow: Source, - }, - ty: Clock, - flow: Source, - }, - TraceModuleIO { - name: "o", - child: TraceBool { - location: TraceScalarId(20), - name: "o", - flow: Sink, - }, - ty: Bool, - flow: Sink, - }, - ], - }, - ty: Bundle { - #[hdl(flip)] /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - o: Bool, - }, - }, - ], - }, - traces: [ - SimTrace { - id: TraceScalarId(0), - kind: BigClock { - index: StatePartIndex(0), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(1), - kind: BigUInt { - index: StatePartIndex(1), - ty: UInt<6>, - }, - state: 0x00, - last_state: 0x00, - }, - SimTrace { - id: TraceScalarId(2), - kind: BigBool { - index: StatePartIndex(2), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(3), - kind: BigBool { - index: StatePartIndex(3), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(4), - kind: BigBool { - index: StatePartIndex(4), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(5), - kind: BigBool { - index: StatePartIndex(5), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(6), - kind: BigBool { - index: StatePartIndex(6), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(7), - kind: BigBool { - index: StatePartIndex(7), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(8), - kind: BigBool { - index: StatePartIndex(24), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(9), - kind: BigClock { - index: StatePartIndex(33), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(10), - kind: BigBool { - index: StatePartIndex(34), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(11), - kind: BigClock { - index: StatePartIndex(31), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(12), - kind: BigBool { - index: StatePartIndex(32), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(13), - kind: BigBool { - index: StatePartIndex(36), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(14), - kind: BigClock { - index: StatePartIndex(44), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(15), - kind: BigBool { - index: StatePartIndex(45), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(16), - kind: BigClock { - index: StatePartIndex(42), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(17), - kind: BigBool { - index: StatePartIndex(43), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(18), - kind: BigBool { - index: StatePartIndex(47), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(19), - kind: BigClock { - index: StatePartIndex(55), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(20), - kind: BigBool { - index: StatePartIndex(56), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(21), - kind: BigClock { - index: StatePartIndex(53), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(22), - kind: BigBool { - index: StatePartIndex(54), - }, - state: 0x0, - last_state: 0x0, - }, - ], - trace_memories: {}, - trace_writers: [ - Running( - VcdWriter { - finished_init: true, - timescale: 1 ps, - .. - }, - ), - ], - instant: 256 μs, - clocks_triggered: [ - StatePartIndex(1), - StatePartIndex(4), - StatePartIndex(7), - ], - .. -} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/ripple_counter.vcd b/crates/fayalite/tests/sim/expected/ripple_counter.vcd deleted file mode 100644 index 6f14a8e..0000000 --- a/crates/fayalite/tests/sim/expected/ripple_counter.vcd +++ /dev/null @@ -1,1753 +0,0 @@ -$timescale 1 ps $end -$scope module ripple_counter $end -$var wire 1 ! clk $end -$var wire 6 " o $end -$scope struct bits $end -$var wire 1 # \[0] $end -$var wire 1 $ \[1] $end -$var wire 1 % \[2] $end -$var wire 1 & \[3] $end -$var wire 1 ' \[4] $end -$var wire 1 ( \[5] $end -$upscope $end -$var reg 1 ) bit_reg_0 $end -$scope struct bit_reg_1 $end -$var wire 1 , clk $end -$var wire 1 - o $end -$upscope $end -$scope module sw_reg $end -$var wire 1 * clk $end -$var wire 1 + o $end -$upscope $end -$var reg 1 . bit_reg_2 $end -$scope struct bit_reg_3 $end -$var wire 1 1 clk $end -$var wire 1 2 o $end -$upscope $end -$scope module sw_reg_2 $end -$var wire 1 / clk $end -$var wire 1 0 o $end -$upscope $end -$var reg 1 3 bit_reg_4 $end -$scope struct bit_reg_5 $end -$var wire 1 6 clk $end -$var wire 1 7 o $end -$upscope $end -$scope module sw_reg_3 $end -$var wire 1 4 clk $end -$var wire 1 5 o $end -$upscope $end -$upscope $end -$enddefinitions $end -$dumpvars -0! -b0 " -0# -0$ -0% -0& -0' -0( -0) -0* -0+ -0, -0- -0. -0/ -00 -01 -02 -03 -04 -05 -06 -07 -$end -#1000000 -1! -1) -b1 " -1# -1* -1, -1+ -b11 " -1$ -1- -1. -b111 " -1% -1/ -11 -10 -b1111 " -1& -12 -13 -b11111 " -1' -14 -16 -15 -b111111 " -1( -17 -#2000000 -0! -#3000000 -1! -0) -b111110 " -0# -0* -0, -#4000000 -0! -#5000000 -1! -1) -b111111 " -1# -1* -1, -0+ -b111101 " -0$ -0- -#6000000 -0! -#7000000 -1! -0) -b111100 " -0# -0* -0, -#8000000 -0! -#9000000 -1! -1) -b111101 " -1# -1* -1, -1+ -b111111 " -1$ -1- -0. -b111011 " -0% -0/ -01 -#10000000 -0! -#11000000 -1! -0) -b111010 " -0# -0* -0, -#12000000 -0! -#13000000 -1! -1) -b111011 " -1# -1* -1, -0+ -b111001 " -0$ -0- -#14000000 -0! -#15000000 -1! -0) -b111000 " -0# -0* -0, -#16000000 -0! -#17000000 -1! -1) -b111001 " -1# -1* -1, -1+ -b111011 " -1$ -1- -1. -b111111 " -1% -1/ -11 -00 -b110111 " -0& -02 -#18000000 -0! -#19000000 -1! -0) -b110110 " -0# -0* -0, -#20000000 -0! -#21000000 -1! -1) -b110111 " -1# -1* -1, -0+ -b110101 " -0$ -0- -#22000000 -0! -#23000000 -1! -0) -b110100 " -0# -0* -0, -#24000000 -0! -#25000000 -1! -1) -b110101 " -1# -1* -1, -1+ -b110111 " -1$ -1- -0. -b110011 " -0% -0/ -01 -#26000000 -0! -#27000000 -1! -0) -b110010 " -0# -0* -0, -#28000000 -0! -#29000000 -1! -1) -b110011 " -1# -1* -1, -0+ -b110001 " -0$ -0- -#30000000 -0! -#31000000 -1! -0) -b110000 " -0# -0* -0, -#32000000 -0! -#33000000 -1! -1) -b110001 " -1# -1* -1, -1+ -b110011 " -1$ -1- -1. -b110111 " -1% -1/ -11 -10 -b111111 " -1& -12 -03 -b101111 " -0' -04 -06 -#34000000 -0! -#35000000 -1! -0) -b101110 " -0# -0* -0, -#36000000 -0! -#37000000 -1! -1) -b101111 " -1# -1* -1, -0+ -b101101 " -0$ -0- -#38000000 -0! -#39000000 -1! -0) -b101100 " -0# -0* -0, -#40000000 -0! -#41000000 -1! -1) -b101101 " -1# -1* -1, -1+ -b101111 " -1$ -1- -0. -b101011 " -0% -0/ -01 -#42000000 -0! -#43000000 -1! -0) -b101010 " -0# -0* -0, -#44000000 -0! -#45000000 -1! -1) -b101011 " -1# -1* -1, -0+ -b101001 " -0$ -0- -#46000000 -0! -#47000000 -1! -0) -b101000 " -0# -0* -0, -#48000000 -0! -#49000000 -1! -1) -b101001 " -1# -1* -1, -1+ -b101011 " -1$ -1- -1. -b101111 " -1% -1/ -11 -00 -b100111 " -0& -02 -#50000000 -0! -#51000000 -1! -0) -b100110 " -0# -0* -0, -#52000000 -0! -#53000000 -1! -1) -b100111 " -1# -1* -1, -0+ -b100101 " -0$ -0- -#54000000 -0! -#55000000 -1! -0) -b100100 " -0# -0* -0, -#56000000 -0! -#57000000 -1! -1) -b100101 " -1# -1* -1, -1+ -b100111 " -1$ -1- -0. -b100011 " -0% -0/ -01 -#58000000 -0! -#59000000 -1! -0) -b100010 " -0# -0* -0, -#60000000 -0! -#61000000 -1! -1) -b100011 " -1# -1* -1, -0+ -b100001 " -0$ -0- -#62000000 -0! -#63000000 -1! -0) -b100000 " -0# -0* -0, -#64000000 -0! -#65000000 -1! -1) -b100001 " -1# -1* -1, -1+ -b100011 " -1$ -1- -1. -b100111 " -1% -1/ -11 -10 -b101111 " -1& -12 -13 -b111111 " -1' -14 -16 -05 -b11111 " -0( -07 -#66000000 -0! -#67000000 -1! -0) -b11110 " -0# -0* -0, -#68000000 -0! -#69000000 -1! -1) -b11111 " -1# -1* -1, -0+ -b11101 " -0$ -0- -#70000000 -0! -#71000000 -1! -0) -b11100 " -0# -0* -0, -#72000000 -0! -#73000000 -1! -1) -b11101 " -1# -1* -1, -1+ -b11111 " -1$ -1- -0. -b11011 " -0% -0/ -01 -#74000000 -0! -#75000000 -1! -0) -b11010 " -0# -0* -0, -#76000000 -0! -#77000000 -1! -1) -b11011 " -1# -1* -1, -0+ -b11001 " -0$ -0- -#78000000 -0! -#79000000 -1! -0) -b11000 " -0# -0* -0, -#80000000 -0! -#81000000 -1! -1) -b11001 " -1# -1* -1, -1+ -b11011 " -1$ -1- -1. -b11111 " -1% -1/ -11 -00 -b10111 " -0& -02 -#82000000 -0! -#83000000 -1! -0) -b10110 " -0# -0* -0, -#84000000 -0! -#85000000 -1! -1) -b10111 " -1# -1* -1, -0+ -b10101 " -0$ -0- -#86000000 -0! -#87000000 -1! -0) -b10100 " -0# -0* -0, -#88000000 -0! -#89000000 -1! -1) -b10101 " -1# -1* -1, -1+ -b10111 " -1$ -1- -0. -b10011 " -0% -0/ -01 -#90000000 -0! -#91000000 -1! -0) -b10010 " -0# -0* -0, -#92000000 -0! -#93000000 -1! -1) -b10011 " -1# -1* -1, -0+ -b10001 " -0$ -0- -#94000000 -0! -#95000000 -1! -0) -b10000 " -0# -0* -0, -#96000000 -0! -#97000000 -1! -1) -b10001 " -1# -1* -1, -1+ -b10011 " -1$ -1- -1. -b10111 " -1% -1/ -11 -10 -b11111 " -1& -12 -03 -b1111 " -0' -04 -06 -#98000000 -0! -#99000000 -1! -0) -b1110 " -0# -0* -0, -#100000000 -0! -#101000000 -1! -1) -b1111 " -1# -1* -1, -0+ -b1101 " -0$ -0- -#102000000 -0! -#103000000 -1! -0) -b1100 " -0# -0* -0, -#104000000 -0! -#105000000 -1! -1) -b1101 " -1# -1* -1, -1+ -b1111 " -1$ -1- -0. -b1011 " -0% -0/ -01 -#106000000 -0! -#107000000 -1! -0) -b1010 " -0# -0* -0, -#108000000 -0! -#109000000 -1! -1) -b1011 " -1# -1* -1, -0+ -b1001 " -0$ -0- -#110000000 -0! -#111000000 -1! -0) -b1000 " -0# -0* -0, -#112000000 -0! -#113000000 -1! -1) -b1001 " -1# -1* -1, -1+ -b1011 " -1$ -1- -1. -b1111 " -1% -1/ -11 -00 -b111 " -0& -02 -#114000000 -0! -#115000000 -1! -0) -b110 " -0# -0* -0, -#116000000 -0! -#117000000 -1! -1) -b111 " -1# -1* -1, -0+ -b101 " -0$ -0- -#118000000 -0! -#119000000 -1! -0) -b100 " -0# -0* -0, -#120000000 -0! -#121000000 -1! -1) -b101 " -1# -1* -1, -1+ -b111 " -1$ -1- -0. -b11 " -0% -0/ -01 -#122000000 -0! -#123000000 -1! -0) -b10 " -0# -0* -0, -#124000000 -0! -#125000000 -1! -1) -b11 " -1# -1* -1, -0+ -b1 " -0$ -0- -#126000000 -0! -#127000000 -1! -0) -b0 " -0# -0* -0, -#128000000 -0! -#129000000 -1! -1) -b1 " -1# -1* -1, -1+ -b11 " -1$ -1- -1. -b111 " -1% -1/ -11 -10 -b1111 " -1& -12 -13 -b11111 " -1' -14 -16 -15 -b111111 " -1( -17 -#130000000 -0! -#131000000 -1! -0) -b111110 " -0# -0* -0, -#132000000 -0! -#133000000 -1! -1) -b111111 " -1# -1* -1, -0+ -b111101 " -0$ -0- -#134000000 -0! -#135000000 -1! -0) -b111100 " -0# -0* -0, -#136000000 -0! -#137000000 -1! -1) -b111101 " -1# -1* -1, -1+ -b111111 " -1$ -1- -0. -b111011 " -0% -0/ -01 -#138000000 -0! -#139000000 -1! -0) -b111010 " -0# -0* -0, -#140000000 -0! -#141000000 -1! -1) -b111011 " -1# -1* -1, -0+ -b111001 " -0$ -0- -#142000000 -0! -#143000000 -1! -0) -b111000 " -0# -0* -0, -#144000000 -0! -#145000000 -1! -1) -b111001 " -1# -1* -1, -1+ -b111011 " -1$ -1- -1. -b111111 " -1% -1/ -11 -00 -b110111 " -0& -02 -#146000000 -0! -#147000000 -1! -0) -b110110 " -0# -0* -0, -#148000000 -0! -#149000000 -1! -1) -b110111 " -1# -1* -1, -0+ -b110101 " -0$ -0- -#150000000 -0! -#151000000 -1! -0) -b110100 " -0# -0* -0, -#152000000 -0! -#153000000 -1! -1) -b110101 " -1# -1* -1, -1+ -b110111 " -1$ -1- -0. -b110011 " -0% -0/ -01 -#154000000 -0! -#155000000 -1! -0) -b110010 " -0# -0* -0, -#156000000 -0! -#157000000 -1! -1) -b110011 " -1# -1* -1, -0+ -b110001 " -0$ -0- -#158000000 -0! -#159000000 -1! -0) -b110000 " -0# -0* -0, -#160000000 -0! -#161000000 -1! -1) -b110001 " -1# -1* -1, -1+ -b110011 " -1$ -1- -1. -b110111 " -1% -1/ -11 -10 -b111111 " -1& -12 -03 -b101111 " -0' -04 -06 -#162000000 -0! -#163000000 -1! -0) -b101110 " -0# -0* -0, -#164000000 -0! -#165000000 -1! -1) -b101111 " -1# -1* -1, -0+ -b101101 " -0$ -0- -#166000000 -0! -#167000000 -1! -0) -b101100 " -0# -0* -0, -#168000000 -0! -#169000000 -1! -1) -b101101 " -1# -1* -1, -1+ -b101111 " -1$ -1- -0. -b101011 " -0% -0/ -01 -#170000000 -0! -#171000000 -1! -0) -b101010 " -0# -0* -0, -#172000000 -0! -#173000000 -1! -1) -b101011 " -1# -1* -1, -0+ -b101001 " -0$ -0- -#174000000 -0! -#175000000 -1! -0) -b101000 " -0# -0* -0, -#176000000 -0! -#177000000 -1! -1) -b101001 " -1# -1* -1, -1+ -b101011 " -1$ -1- -1. -b101111 " -1% -1/ -11 -00 -b100111 " -0& -02 -#178000000 -0! -#179000000 -1! -0) -b100110 " -0# -0* -0, -#180000000 -0! -#181000000 -1! -1) -b100111 " -1# -1* -1, -0+ -b100101 " -0$ -0- -#182000000 -0! -#183000000 -1! -0) -b100100 " -0# -0* -0, -#184000000 -0! -#185000000 -1! -1) -b100101 " -1# -1* -1, -1+ -b100111 " -1$ -1- -0. -b100011 " -0% -0/ -01 -#186000000 -0! -#187000000 -1! -0) -b100010 " -0# -0* -0, -#188000000 -0! -#189000000 -1! -1) -b100011 " -1# -1* -1, -0+ -b100001 " -0$ -0- -#190000000 -0! -#191000000 -1! -0) -b100000 " -0# -0* -0, -#192000000 -0! -#193000000 -1! -1) -b100001 " -1# -1* -1, -1+ -b100011 " -1$ -1- -1. -b100111 " -1% -1/ -11 -10 -b101111 " -1& -12 -13 -b111111 " -1' -14 -16 -05 -b11111 " -0( -07 -#194000000 -0! -#195000000 -1! -0) -b11110 " -0# -0* -0, -#196000000 -0! -#197000000 -1! -1) -b11111 " -1# -1* -1, -0+ -b11101 " -0$ -0- -#198000000 -0! -#199000000 -1! -0) -b11100 " -0# -0* -0, -#200000000 -0! -#201000000 -1! -1) -b11101 " -1# -1* -1, -1+ -b11111 " -1$ -1- -0. -b11011 " -0% -0/ -01 -#202000000 -0! -#203000000 -1! -0) -b11010 " -0# -0* -0, -#204000000 -0! -#205000000 -1! -1) -b11011 " -1# -1* -1, -0+ -b11001 " -0$ -0- -#206000000 -0! -#207000000 -1! -0) -b11000 " -0# -0* -0, -#208000000 -0! -#209000000 -1! -1) -b11001 " -1# -1* -1, -1+ -b11011 " -1$ -1- -1. -b11111 " -1% -1/ -11 -00 -b10111 " -0& -02 -#210000000 -0! -#211000000 -1! -0) -b10110 " -0# -0* -0, -#212000000 -0! -#213000000 -1! -1) -b10111 " -1# -1* -1, -0+ -b10101 " -0$ -0- -#214000000 -0! -#215000000 -1! -0) -b10100 " -0# -0* -0, -#216000000 -0! -#217000000 -1! -1) -b10101 " -1# -1* -1, -1+ -b10111 " -1$ -1- -0. -b10011 " -0% -0/ -01 -#218000000 -0! -#219000000 -1! -0) -b10010 " -0# -0* -0, -#220000000 -0! -#221000000 -1! -1) -b10011 " -1# -1* -1, -0+ -b10001 " -0$ -0- -#222000000 -0! -#223000000 -1! -0) -b10000 " -0# -0* -0, -#224000000 -0! -#225000000 -1! -1) -b10001 " -1# -1* -1, -1+ -b10011 " -1$ -1- -1. -b10111 " -1% -1/ -11 -10 -b11111 " -1& -12 -03 -b1111 " -0' -04 -06 -#226000000 -0! -#227000000 -1! -0) -b1110 " -0# -0* -0, -#228000000 -0! -#229000000 -1! -1) -b1111 " -1# -1* -1, -0+ -b1101 " -0$ -0- -#230000000 -0! -#231000000 -1! -0) -b1100 " -0# -0* -0, -#232000000 -0! -#233000000 -1! -1) -b1101 " -1# -1* -1, -1+ -b1111 " -1$ -1- -0. -b1011 " -0% -0/ -01 -#234000000 -0! -#235000000 -1! -0) -b1010 " -0# -0* -0, -#236000000 -0! -#237000000 -1! -1) -b1011 " -1# -1* -1, -0+ -b1001 " -0$ -0- -#238000000 -0! -#239000000 -1! -0) -b1000 " -0# -0* -0, -#240000000 -0! -#241000000 -1! -1) -b1001 " -1# -1* -1, -1+ -b1011 " -1$ -1- -1. -b1111 " -1% -1/ -11 -00 -b111 " -0& -02 -#242000000 -0! -#243000000 -1! -0) -b110 " -0# -0* -0, -#244000000 -0! -#245000000 -1! -1) -b111 " -1# -1* -1, -0+ -b101 " -0$ -0- -#246000000 -0! -#247000000 -1! -0) -b100 " -0# -0* -0, -#248000000 -0! -#249000000 -1! -1) -b101 " -1# -1* -1, -1+ -b111 " -1$ -1- -0. -b11 " -0% -0/ -01 -#250000000 -0! -#251000000 -1! -0) -b10 " -0# -0* -0, -#252000000 -0! -#253000000 -1! -1) -b11 " -1# -1* -1, -0+ -b1 " -0$ -0- -#254000000 -0! -#255000000 -1! -0) -b0 " -0# -0* -0, -#256000000 diff --git a/crates/fayalite/tests/sim/expected/shift_register.txt b/crates/fayalite/tests/sim/expected/shift_register.txt index 9bab424..73f6263 100644 --- a/crates/fayalite/tests/sim/expected/shift_register.txt +++ b/crates/fayalite/tests/sim/expected/shift_register.txt @@ -83,12 +83,6 @@ Simulation { ], .. }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, }, memories: StatePartLayout { len: 0, @@ -263,9 +257,6 @@ Simulation { 0, ], }, - sim_only_slots: StatePart { - value: [], - }, }, io: Instance { name: ::shift_register, @@ -274,72 +265,247 @@ Simulation { .. }, }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::shift_register, - instantiated: Module { - name: shift_register, - .. + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.cd: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + rst: SyncReset, }, - }.cd, - Instance { - name: ::shift_register, - instantiated: Module { - name: shift_register, - .. + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.rst", + ty: SyncReset, + }, + ], + .. + }, }, - }.d, - Instance { - name: ::shift_register, - instantiated: Module { - name: shift_register, - .. + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: SyncReset, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], }, - }.q, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::shift_register, - instantiated: Module { - name: shift_register, - .. - }, - }.cd, - Instance { - name: ::shift_register, - instantiated: Module { - name: shift_register, - .. - }, - }.cd.clk, - Instance { - name: ::shift_register, - instantiated: Module { - name: shift_register, - .. - }, - }.cd.rst, - Instance { - name: ::shift_register, - instantiated: Module { - name: shift_register, - .. - }, - }.d, - Instance { - name: ::shift_register, - instantiated: Module { - name: shift_register, - .. - }, - }.q, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 2 }, + }, + write: None, + }, + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.cd.clk: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, + }, + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.cd.rst: CompiledValue { + layout: CompiledTypeLayout { + ty: SyncReset, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 1, len: 1 }, + }, + write: None, + }, + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.d: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::d", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 2, len: 1 }, + }, + write: None, + }, + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.q: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::q", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 3, len: 1 }, + }, + write: None, }, - did_initial_settle: true, }, - extern_modules: [], - state_ready_to_run: false, + made_initial_step: true, + needs_settle: false, trace_decls: TraceModule { name: "shift_register", children: [ diff --git a/crates/fayalite/tests/sim/expected/sim_only_connects.txt b/crates/fayalite/tests/sim/expected/sim_only_connects.txt deleted file mode 100644 index 114b313..0000000 --- a/crates/fayalite/tests/sim/expected/sim_only_connects.txt +++ /dev/null @@ -1,1636 +0,0 @@ -Simulation { - state: State { - insns: Insns { - state_layout: StateLayout { - ty: TypeLayout { - small_slots: StatePartLayout { - len: 4, - debug_data: [ - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - ], - .. - }, - big_slots: StatePartLayout { - len: 14, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::cd.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::cd.rst", - ty: SyncReset, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper1.cd.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper1.cd.rst", - ty: SyncReset, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects.helper1: sim_only_connects_helper).sim_only_connects_helper::cd.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects.helper1: sim_only_connects_helper).sim_only_connects_helper::cd.rst", - ty: SyncReset, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1_empty", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1_empty$next", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "", - ty: Bool, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper2.cd.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper2.cd.rst", - ty: SyncReset, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects.helper2: sim_only_connects_helper).sim_only_connects_helper::cd.clk", - ty: Clock, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects.helper2: sim_only_connects_helper).sim_only_connects_helper::cd.rst", - ty: SyncReset, - }, - ], - .. - }, - sim_only_slots: StatePartLayout { - len: 15, - debug_data: [ - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::inp", - ty: SimOnly>>, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::out1", - ty: SimOnly>>, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::out2", - ty: SimOnly>>, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::out3", - ty: SimOnly>>, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper1.inp", - ty: SimOnly>>, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper1.out", - ty: SimOnly>>, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects.helper1: sim_only_connects_helper).sim_only_connects_helper::inp", - ty: SimOnly>>, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects.helper1: sim_only_connects_helper).sim_only_connects_helper::out", - ty: SimOnly>>, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1", - ty: SimOnly>>, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1$next", - ty: SimOnly>>, - }, - SlotDebugData { - name: "", - ty: SimOnly>>, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper2.inp", - ty: SimOnly>>, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper2.out", - ty: SimOnly>>, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects.helper2: sim_only_connects_helper).sim_only_connects_helper::inp", - ty: SimOnly>>, - }, - SlotDebugData { - name: "InstantiatedModule(sim_only_connects.helper2: sim_only_connects_helper).sim_only_connects_helper::out", - ty: SimOnly>>, - }, - ], - layout_data: [ - SimOnly>>, - SimOnly>>, - SimOnly>>, - SimOnly>>, - SimOnly>>, - SimOnly>>, - SimOnly>>, - SimOnly>>, - SimOnly>>, - SimOnly>>, - SimOnly>>, - SimOnly>>, - SimOnly>>, - SimOnly>>, - SimOnly>>, - ], - .. - }, - }, - memories: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - insns: [ - // at: module-XXXXXXXXXX.rs:20:1 - 0: Copy { - dest: StatePartIndex(10), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper2.cd.clk", ty: Clock }, - src: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::cd.clk", ty: Clock }, - }, - 1: Copy { - dest: StatePartIndex(11), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper2.cd.rst", ty: SyncReset }, - src: StatePartIndex(1), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::cd.rst", ty: SyncReset }, - }, - // at: module-XXXXXXXXXX.rs:19:1 - 2: CloneSimOnly { - dest: StatePartIndex(12), // ({"bar": "baz", "extra": "value", "foo": "baz"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper2.out", ty: SimOnly>> }, - src: StatePartIndex(14), // ({"bar": "baz", "extra": "value", "foo": "baz"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects.helper2: sim_only_connects_helper).sim_only_connects_helper::out", ty: SimOnly>> }, - }, - // at: module-XXXXXXXXXX.rs:22:1 - 3: CloneSimOnly { - dest: StatePartIndex(3), // ({"bar": "baz", "extra": "value", "foo": "baz"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::out3", ty: SimOnly>> }, - src: StatePartIndex(12), // ({"bar": "baz", "extra": "value", "foo": "baz"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper2.out", ty: SimOnly>> }, - }, - // at: module-XXXXXXXXXX.rs:19:1 - 4: Copy { - dest: StatePartIndex(12), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_only_connects.helper2: sim_only_connects_helper).sim_only_connects_helper::cd.clk", ty: Clock }, - src: StatePartIndex(10), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper2.cd.clk", ty: Clock }, - }, - 5: Copy { - dest: StatePartIndex(13), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects.helper2: sim_only_connects_helper).sim_only_connects_helper::cd.rst", ty: SyncReset }, - src: StatePartIndex(11), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper2.cd.rst", ty: SyncReset }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 6: Const { - dest: StatePartIndex(9), // (0x0) SlotDebugData { name: "", ty: Bool }, - value: 0x0, - }, - // at: module-XXXXXXXXXX.rs:17:1 - 7: Copy { - dest: StatePartIndex(7), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1_empty$next", ty: Bool }, - src: StatePartIndex(9), // (0x0) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:16:1 - 8: CloneSimOnly { - dest: StatePartIndex(9), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1$next", ty: SimOnly>> }, - src: StatePartIndex(0), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::inp", ty: SimOnly>> }, - }, - // at: module-XXXXXXXXXX.rs:12:1 - 9: CloneSimOnly { - dest: StatePartIndex(1), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::out1", ty: SimOnly>> }, - src: StatePartIndex(8), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1", ty: SimOnly>> }, - }, - // at: module-XXXXXXXXXX.rs:13:1 - 10: BranchIfZero { - target: 12, - value: StatePartIndex(6), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1_empty", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:15:1 - 11: CloneSimOnly { - dest: StatePartIndex(1), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::out1", ty: SimOnly>> }, - src: StatePartIndex(0), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::inp", ty: SimOnly>> }, - }, - // at: module-XXXXXXXXXX.rs:11:1 - 12: CloneSimOnly { - dest: StatePartIndex(4), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper1.inp", ty: SimOnly>> }, - src: StatePartIndex(8), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1", ty: SimOnly>> }, - }, - // at: module-XXXXXXXXXX.rs:13:1 - 13: BranchIfZero { - target: 15, - value: StatePartIndex(6), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1_empty", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:14:1 - 14: CloneSimOnly { - dest: StatePartIndex(4), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper1.inp", ty: SimOnly>> }, - src: StatePartIndex(0), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::inp", ty: SimOnly>> }, - }, - // at: module-XXXXXXXXXX.rs:10:1 - 15: Copy { - dest: StatePartIndex(2), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper1.cd.clk", ty: Clock }, - src: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::cd.clk", ty: Clock }, - }, - 16: Copy { - dest: StatePartIndex(3), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper1.cd.rst", ty: SyncReset }, - src: StatePartIndex(1), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::cd.rst", ty: SyncReset }, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 17: Const { - dest: StatePartIndex(8), // (0x1) SlotDebugData { name: "", ty: Bool }, - value: 0x1, - }, - // at: module-XXXXXXXXXX.rs:8:1 - 18: IsNonZeroDestIsSmall { - dest: StatePartIndex(3), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(1), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::cd.rst", ty: SyncReset }, - }, - 19: IsNonZeroDestIsSmall { - dest: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - src: StatePartIndex(0), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::cd.clk", ty: Clock }, - }, - 20: AndSmall { - dest: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - rhs: StatePartIndex(0), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:7:1 - 21: CloneSimOnly { - dest: StatePartIndex(5), // ({"bar": "", "extra": "value", "foo": "baz"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper1.out", ty: SimOnly>> }, - src: StatePartIndex(7), // ({"bar": "", "extra": "value", "foo": "baz"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects.helper1: sim_only_connects_helper).sim_only_connects_helper::out", ty: SimOnly>> }, - }, - // at: module-XXXXXXXXXX.rs:18:1 - 22: CloneSimOnly { - dest: StatePartIndex(2), // ({"bar": "", "extra": "value", "foo": "baz"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::out2", ty: SimOnly>> }, - src: StatePartIndex(5), // ({"bar": "", "extra": "value", "foo": "baz"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper1.out", ty: SimOnly>> }, - }, - // at: module-XXXXXXXXXX.rs:21:1 - 23: CloneSimOnly { - dest: StatePartIndex(11), // ({"bar": "", "extra": "value", "foo": "baz"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper2.inp", ty: SimOnly>> }, - src: StatePartIndex(2), // ({"bar": "", "extra": "value", "foo": "baz"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::out2", ty: SimOnly>> }, - }, - // at: module-XXXXXXXXXX.rs:19:1 - 24: CloneSimOnly { - dest: StatePartIndex(13), // ({"bar": "", "extra": "value", "foo": "baz"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects.helper2: sim_only_connects_helper).sim_only_connects_helper::inp", ty: SimOnly>> }, - src: StatePartIndex(11), // ({"bar": "", "extra": "value", "foo": "baz"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper2.inp", ty: SimOnly>> }, - }, - // at: module-XXXXXXXXXX.rs:7:1 - 25: CloneSimOnly { - dest: StatePartIndex(6), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects.helper1: sim_only_connects_helper).sim_only_connects_helper::inp", ty: SimOnly>> }, - src: StatePartIndex(4), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper1.inp", ty: SimOnly>> }, - }, - 26: Copy { - dest: StatePartIndex(4), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_only_connects.helper1: sim_only_connects_helper).sim_only_connects_helper::cd.clk", ty: Clock }, - src: StatePartIndex(2), // (0x1) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper1.cd.clk", ty: Clock }, - }, - 27: Copy { - dest: StatePartIndex(5), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects.helper1: sim_only_connects_helper).sim_only_connects_helper::cd.rst", ty: SyncReset }, - src: StatePartIndex(3), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::helper1.cd.rst", ty: SyncReset }, - }, - // at: module-XXXXXXXXXX.rs:8:1 - 28: BranchIfSmallZero { - target: 33, - value: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 29: BranchIfSmallNonZero { - target: 32, - value: StatePartIndex(3), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 30: CloneSimOnly { - dest: StatePartIndex(8), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1", ty: SimOnly>> }, - src: StatePartIndex(9), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1$next", ty: SimOnly>> }, - }, - 31: Branch { - target: 33, - }, - 32: CloneSimOnly { - dest: StatePartIndex(8), // ({"extra": "value"}) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1", ty: SimOnly>> }, - src: StatePartIndex(10), // ({}) SlotDebugData { name: "", ty: SimOnly>> }, - }, - // at: module-XXXXXXXXXX.rs:9:1 - 33: BranchIfSmallZero { - target: 38, - value: StatePartIndex(1), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 34: BranchIfSmallNonZero { - target: 37, - value: StatePartIndex(3), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - }, - 35: Copy { - dest: StatePartIndex(6), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1_empty", ty: Bool }, - src: StatePartIndex(7), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1_empty$next", ty: Bool }, - }, - 36: Branch { - target: 38, - }, - 37: Copy { - dest: StatePartIndex(6), // (0x0) SlotDebugData { name: "InstantiatedModule(sim_only_connects: sim_only_connects).sim_only_connects::delay1_empty", ty: Bool }, - src: StatePartIndex(8), // (0x1) SlotDebugData { name: "", ty: Bool }, - }, - // at: module-XXXXXXXXXX.rs:8:1 - 38: XorSmallImmediate { - dest: StatePartIndex(0), // (0x0 0) SlotDebugData { name: "", ty: Bool }, - lhs: StatePartIndex(2), // (0x1 1) SlotDebugData { name: "", ty: Bool }, - rhs: 0x1, - }, - // at: module-XXXXXXXXXX.rs:1:1 - 39: Return, - ], - .. - }, - pc: 39, - memory_write_log: [], - memories: StatePart { - value: [], - }, - small_slots: StatePart { - value: [ - 0, - 0, - 1, - 0, - ], - }, - big_slots: StatePart { - value: [ - 1, - 0, - 1, - 0, - 1, - 0, - 0, - 0, - 1, - 0, - 1, - 0, - 1, - 0, - ], - }, - sim_only_slots: StatePart { - value: [ - { - "extra": "value", - }, - { - "extra": "value", - }, - { - "bar": "", - "extra": "value", - "foo": "baz", - }, - { - "bar": "baz", - "extra": "value", - "foo": "baz", - }, - { - "extra": "value", - }, - { - "bar": "", - "extra": "value", - "foo": "baz", - }, - { - "extra": "value", - }, - { - "bar": "", - "extra": "value", - "foo": "baz", - }, - { - "extra": "value", - }, - { - "extra": "value", - }, - {}, - { - "bar": "", - "extra": "value", - "foo": "baz", - }, - { - "bar": "baz", - "extra": "value", - "foo": "baz", - }, - { - "bar": "", - "extra": "value", - "foo": "baz", - }, - { - "bar": "baz", - "extra": "value", - "foo": "baz", - }, - ], - }, - }, - io: Instance { - name: ::sim_only_connects, - instantiated: Module { - name: sim_only_connects, - .. - }, - }, - main_module: SimulationModuleState { - base_targets: [ - Instance { - name: ::sim_only_connects, - instantiated: Module { - name: sim_only_connects, - .. - }, - }.cd, - Instance { - name: ::sim_only_connects, - instantiated: Module { - name: sim_only_connects, - .. - }, - }.inp, - Instance { - name: ::sim_only_connects, - instantiated: Module { - name: sim_only_connects, - .. - }, - }.out1, - Instance { - name: ::sim_only_connects, - instantiated: Module { - name: sim_only_connects, - .. - }, - }.out2, - Instance { - name: ::sim_only_connects, - instantiated: Module { - name: sim_only_connects, - .. - }, - }.out3, - ], - uninitialized_ios: {}, - io_targets: { - Instance { - name: ::sim_only_connects, - instantiated: Module { - name: sim_only_connects, - .. - }, - }.cd, - Instance { - name: ::sim_only_connects, - instantiated: Module { - name: sim_only_connects, - .. - }, - }.cd.clk, - Instance { - name: ::sim_only_connects, - instantiated: Module { - name: sim_only_connects, - .. - }, - }.cd.rst, - Instance { - name: ::sim_only_connects, - instantiated: Module { - name: sim_only_connects, - .. - }, - }.inp, - Instance { - name: ::sim_only_connects, - instantiated: Module { - name: sim_only_connects, - .. - }, - }.out1, - Instance { - name: ::sim_only_connects, - instantiated: Module { - name: sim_only_connects, - .. - }, - }.out2, - Instance { - name: ::sim_only_connects, - instantiated: Module { - name: sim_only_connects, - .. - }, - }.out3, - }, - did_initial_settle: true, - }, - extern_modules: [ - SimulationExternModuleState { - module_state: SimulationModuleState { - base_targets: [ - ModuleIO { - name: sim_only_connects_helper::cd, - is_input: true, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: Reset, - }, - .. - }, - ModuleIO { - name: sim_only_connects_helper::inp, - is_input: true, - ty: SimOnly>>, - .. - }, - ModuleIO { - name: sim_only_connects_helper::out, - is_input: false, - ty: SimOnly>>, - .. - }, - ], - uninitialized_ios: {}, - io_targets: { - ModuleIO { - name: sim_only_connects_helper::cd, - is_input: true, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: Reset, - }, - .. - }, - ModuleIO { - name: sim_only_connects_helper::cd, - is_input: true, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: Reset, - }, - .. - }.clk, - ModuleIO { - name: sim_only_connects_helper::cd, - is_input: true, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: Reset, - }, - .. - }.rst, - ModuleIO { - name: sim_only_connects_helper::inp, - is_input: true, - ty: SimOnly>>, - .. - }, - ModuleIO { - name: sim_only_connects_helper::out, - is_input: false, - ty: SimOnly>>, - .. - }, - }, - did_initial_settle: true, - }, - sim: ExternModuleSimulation { - generator: SimGeneratorFn { - args: ( - ModuleIO { - name: sim_only_connects_helper::cd, - is_input: true, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: Reset, - }, - .. - }, - ModuleIO { - name: sim_only_connects_helper::inp, - is_input: true, - ty: SimOnly>>, - .. - }, - ModuleIO { - name: sim_only_connects_helper::out, - is_input: false, - ty: SimOnly>>, - .. - }, - ), - f: ..., - }, - sim_io_to_generator_map: { - ModuleIO { - name: sim_only_connects_helper::cd, - is_input: true, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - .. - }: ModuleIO { - name: sim_only_connects_helper::cd, - is_input: true, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: Reset, - }, - .. - }, - ModuleIO { - name: sim_only_connects_helper::inp, - is_input: true, - ty: SimOnly>>, - .. - }: ModuleIO { - name: sim_only_connects_helper::inp, - is_input: true, - ty: SimOnly>>, - .. - }, - ModuleIO { - name: sim_only_connects_helper::out, - is_input: false, - ty: SimOnly>>, - .. - }: ModuleIO { - name: sim_only_connects_helper::out, - is_input: false, - ty: SimOnly>>, - .. - }, - }, - source_location: SourceLocation( - module-XXXXXXXXXX-2.rs:5:1, - ), - }, - running_generator: Some( - ..., - ), - wait_targets: { - Change { - key: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 0, len: 0 }, - big_slots: StatePartIndexRange { start: 4, len: 1 }, - sim_only_slots: StatePartIndexRange { start: 6, len: 0 }, - }, - write: None, - }, - value: SimValue { - ty: Clock, - value: OpaqueSimValue { - bits: 0x1_u1, - sim_only_values: [], - }, - }, - }, - }, - }, - SimulationExternModuleState { - module_state: SimulationModuleState { - base_targets: [ - ModuleIO { - name: sim_only_connects_helper::cd, - is_input: true, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: Reset, - }, - .. - }, - ModuleIO { - name: sim_only_connects_helper::inp, - is_input: true, - ty: SimOnly>>, - .. - }, - ModuleIO { - name: sim_only_connects_helper::out, - is_input: false, - ty: SimOnly>>, - .. - }, - ], - uninitialized_ios: {}, - io_targets: { - ModuleIO { - name: sim_only_connects_helper::cd, - is_input: true, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: Reset, - }, - .. - }, - ModuleIO { - name: sim_only_connects_helper::cd, - is_input: true, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: Reset, - }, - .. - }.clk, - ModuleIO { - name: sim_only_connects_helper::cd, - is_input: true, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: Reset, - }, - .. - }.rst, - ModuleIO { - name: sim_only_connects_helper::inp, - is_input: true, - ty: SimOnly>>, - .. - }, - ModuleIO { - name: sim_only_connects_helper::out, - is_input: false, - ty: SimOnly>>, - .. - }, - }, - did_initial_settle: true, - }, - sim: ExternModuleSimulation { - generator: SimGeneratorFn { - args: ( - ModuleIO { - name: sim_only_connects_helper::cd, - is_input: true, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: Reset, - }, - .. - }, - ModuleIO { - name: sim_only_connects_helper::inp, - is_input: true, - ty: SimOnly>>, - .. - }, - ModuleIO { - name: sim_only_connects_helper::out, - is_input: false, - ty: SimOnly>>, - .. - }, - ), - f: ..., - }, - sim_io_to_generator_map: { - ModuleIO { - name: sim_only_connects_helper::cd, - is_input: true, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - .. - }: ModuleIO { - name: sim_only_connects_helper::cd, - is_input: true, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: Reset, - }, - .. - }, - ModuleIO { - name: sim_only_connects_helper::inp, - is_input: true, - ty: SimOnly>>, - .. - }: ModuleIO { - name: sim_only_connects_helper::inp, - is_input: true, - ty: SimOnly>>, - .. - }, - ModuleIO { - name: sim_only_connects_helper::out, - is_input: false, - ty: SimOnly>>, - .. - }: ModuleIO { - name: sim_only_connects_helper::out, - is_input: false, - ty: SimOnly>>, - .. - }, - }, - source_location: SourceLocation( - module-XXXXXXXXXX-2.rs:5:1, - ), - }, - running_generator: Some( - ..., - ), - wait_targets: { - Change { - key: CompiledValue { - layout: CompiledTypeLayout { - ty: Clock, - layout: TypeLayout { - small_slots: StatePartLayout { - len: 0, - debug_data: [], - .. - }, - big_slots: StatePartLayout { - len: 1, - debug_data: [ - SlotDebugData { - name: "", - ty: Clock, - }, - ], - .. - }, - sim_only_slots: StatePartLayout { - len: 0, - debug_data: [], - layout_data: [], - .. - }, - }, - body: Scalar, - }, - range: TypeIndexRange { - small_slots: StatePartIndexRange { start: 4, len: 0 }, - big_slots: StatePartIndexRange { start: 12, len: 1 }, - sim_only_slots: StatePartIndexRange { start: 13, len: 0 }, - }, - write: None, - }, - value: SimValue { - ty: Clock, - value: OpaqueSimValue { - bits: 0x1_u1, - sim_only_values: [], - }, - }, - }, - }, - }, - ], - state_ready_to_run: false, - trace_decls: TraceModule { - name: "sim_only_connects", - children: [ - TraceModuleIO { - name: "cd", - child: TraceBundle { - name: "cd", - fields: [ - TraceClock { - location: TraceScalarId(0), - name: "clk", - flow: Source, - }, - TraceSyncReset { - location: TraceScalarId(1), - name: "rst", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - flow: Source, - }, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - flow: Source, - }, - TraceModuleIO { - name: "inp", - child: TraceSimOnly { - location: TraceScalarId(2), - name: "inp", - ty: SimOnly>>, - flow: Source, - }, - ty: SimOnly>>, - flow: Source, - }, - TraceModuleIO { - name: "out1", - child: TraceSimOnly { - location: TraceScalarId(3), - name: "out1", - ty: SimOnly>>, - flow: Sink, - }, - ty: SimOnly>>, - flow: Sink, - }, - TraceModuleIO { - name: "out2", - child: TraceSimOnly { - location: TraceScalarId(4), - name: "out2", - ty: SimOnly>>, - flow: Sink, - }, - ty: SimOnly>>, - flow: Sink, - }, - TraceModuleIO { - name: "out3", - child: TraceSimOnly { - location: TraceScalarId(5), - name: "out3", - ty: SimOnly>>, - flow: Sink, - }, - ty: SimOnly>>, - flow: Sink, - }, - TraceInstance { - name: "helper1", - instance_io: TraceBundle { - name: "helper1", - fields: [ - TraceBundle { - name: "cd", - fields: [ - TraceClock { - location: TraceScalarId(10), - name: "clk", - flow: Sink, - }, - TraceSyncReset { - location: TraceScalarId(11), - name: "rst", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - flow: Sink, - }, - TraceSimOnly { - location: TraceScalarId(12), - name: "inp", - ty: SimOnly>>, - flow: Sink, - }, - TraceSimOnly { - location: TraceScalarId(13), - name: "out", - ty: SimOnly>>, - flow: Source, - }, - ], - ty: Bundle { - #[hdl(flip)] /* offset = 0 */ - cd: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - #[hdl(flip)] /* offset = 2 */ - inp: SimOnly>>, - /* offset = 2 */ - out: SimOnly>>, - }, - flow: Source, - }, - module: TraceModule { - name: "sim_only_connects_helper", - children: [ - TraceModuleIO { - name: "cd", - child: TraceBundle { - name: "cd", - fields: [ - TraceClock { - location: TraceScalarId(6), - name: "clk", - flow: Source, - }, - TraceSyncReset { - location: TraceScalarId(7), - name: "rst", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - flow: Source, - }, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - flow: Source, - }, - TraceModuleIO { - name: "inp", - child: TraceSimOnly { - location: TraceScalarId(8), - name: "inp", - ty: SimOnly>>, - flow: Source, - }, - ty: SimOnly>>, - flow: Source, - }, - TraceModuleIO { - name: "out", - child: TraceSimOnly { - location: TraceScalarId(9), - name: "out", - ty: SimOnly>>, - flow: Sink, - }, - ty: SimOnly>>, - flow: Sink, - }, - ], - }, - ty: Bundle { - #[hdl(flip)] /* offset = 0 */ - cd: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - #[hdl(flip)] /* offset = 2 */ - inp: SimOnly>>, - /* offset = 2 */ - out: SimOnly>>, - }, - }, - TraceReg { - name: "delay1", - child: TraceSimOnly { - location: TraceScalarId(14), - name: "delay1", - ty: SimOnly>>, - flow: Duplex, - }, - ty: SimOnly>>, - }, - TraceReg { - name: "delay1_empty", - child: TraceBool { - location: TraceScalarId(15), - name: "delay1_empty", - flow: Duplex, - }, - ty: Bool, - }, - TraceInstance { - name: "helper2", - instance_io: TraceBundle { - name: "helper2", - fields: [ - TraceBundle { - name: "cd", - fields: [ - TraceClock { - location: TraceScalarId(20), - name: "clk", - flow: Sink, - }, - TraceSyncReset { - location: TraceScalarId(21), - name: "rst", - flow: Sink, - }, - ], - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - flow: Sink, - }, - TraceSimOnly { - location: TraceScalarId(22), - name: "inp", - ty: SimOnly>>, - flow: Sink, - }, - TraceSimOnly { - location: TraceScalarId(23), - name: "out", - ty: SimOnly>>, - flow: Source, - }, - ], - ty: Bundle { - #[hdl(flip)] /* offset = 0 */ - cd: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - #[hdl(flip)] /* offset = 2 */ - inp: SimOnly>>, - /* offset = 2 */ - out: SimOnly>>, - }, - flow: Source, - }, - module: TraceModule { - name: "sim_only_connects_helper", - children: [ - TraceModuleIO { - name: "cd", - child: TraceBundle { - name: "cd", - fields: [ - TraceClock { - location: TraceScalarId(16), - name: "clk", - flow: Source, - }, - TraceSyncReset { - location: TraceScalarId(17), - name: "rst", - flow: Source, - }, - ], - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - flow: Source, - }, - ty: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - flow: Source, - }, - TraceModuleIO { - name: "inp", - child: TraceSimOnly { - location: TraceScalarId(18), - name: "inp", - ty: SimOnly>>, - flow: Source, - }, - ty: SimOnly>>, - flow: Source, - }, - TraceModuleIO { - name: "out", - child: TraceSimOnly { - location: TraceScalarId(19), - name: "out", - ty: SimOnly>>, - flow: Sink, - }, - ty: SimOnly>>, - flow: Sink, - }, - ], - }, - ty: Bundle { - #[hdl(flip)] /* offset = 0 */ - cd: Bundle { - /* offset = 0 */ - clk: Clock, - /* offset = 1 */ - rst: SyncReset, - }, - #[hdl(flip)] /* offset = 2 */ - inp: SimOnly>>, - /* offset = 2 */ - out: SimOnly>>, - }, - }, - ], - }, - traces: [ - SimTrace { - id: TraceScalarId(0), - kind: BigClock { - index: StatePartIndex(0), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(1), - kind: BigSyncReset { - index: StatePartIndex(1), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(2), - kind: SimOnly { - index: StatePartIndex(0), - ty: SimOnly>>, - }, - state: { - "extra": "value", - }, - last_state: { - "extra": "value", - }, - }, - SimTrace { - id: TraceScalarId(3), - kind: SimOnly { - index: StatePartIndex(1), - ty: SimOnly>>, - }, - state: { - "extra": "value", - }, - last_state: { - "extra": "value", - }, - }, - SimTrace { - id: TraceScalarId(4), - kind: SimOnly { - index: StatePartIndex(2), - ty: SimOnly>>, - }, - state: { - "bar": "", - "extra": "value", - "foo": "baz", - }, - last_state: { - "bar": "", - "extra": "value", - "foo": "baz", - }, - }, - SimTrace { - id: TraceScalarId(5), - kind: SimOnly { - index: StatePartIndex(3), - ty: SimOnly>>, - }, - state: { - "bar": "baz", - "extra": "value", - "foo": "baz", - }, - last_state: { - "bar": "baz", - "extra": "value", - "foo": "baz", - }, - }, - SimTrace { - id: TraceScalarId(6), - kind: BigClock { - index: StatePartIndex(4), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(7), - kind: BigSyncReset { - index: StatePartIndex(5), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(8), - kind: SimOnly { - index: StatePartIndex(6), - ty: SimOnly>>, - }, - state: { - "extra": "value", - }, - last_state: { - "extra": "value", - }, - }, - SimTrace { - id: TraceScalarId(9), - kind: SimOnly { - index: StatePartIndex(7), - ty: SimOnly>>, - }, - state: { - "bar": "", - "extra": "value", - "foo": "baz", - }, - last_state: { - "bar": "", - "extra": "value", - "foo": "baz", - }, - }, - SimTrace { - id: TraceScalarId(10), - kind: BigClock { - index: StatePartIndex(2), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(11), - kind: BigSyncReset { - index: StatePartIndex(3), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(12), - kind: SimOnly { - index: StatePartIndex(4), - ty: SimOnly>>, - }, - state: { - "extra": "value", - }, - last_state: { - "extra": "value", - }, - }, - SimTrace { - id: TraceScalarId(13), - kind: SimOnly { - index: StatePartIndex(5), - ty: SimOnly>>, - }, - state: { - "bar": "", - "extra": "value", - "foo": "baz", - }, - last_state: { - "bar": "", - "extra": "value", - "foo": "baz", - }, - }, - SimTrace { - id: TraceScalarId(14), - kind: SimOnly { - index: StatePartIndex(8), - ty: SimOnly>>, - }, - state: { - "extra": "value", - }, - last_state: { - "extra": "value", - }, - }, - SimTrace { - id: TraceScalarId(15), - kind: BigBool { - index: StatePartIndex(6), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(16), - kind: BigClock { - index: StatePartIndex(12), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(17), - kind: BigSyncReset { - index: StatePartIndex(13), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(18), - kind: SimOnly { - index: StatePartIndex(13), - ty: SimOnly>>, - }, - state: { - "bar": "", - "extra": "value", - "foo": "baz", - }, - last_state: { - "bar": "", - "extra": "value", - "foo": "baz", - }, - }, - SimTrace { - id: TraceScalarId(19), - kind: SimOnly { - index: StatePartIndex(14), - ty: SimOnly>>, - }, - state: { - "bar": "baz", - "extra": "value", - "foo": "baz", - }, - last_state: { - "bar": "baz", - "extra": "value", - "foo": "baz", - }, - }, - SimTrace { - id: TraceScalarId(20), - kind: BigClock { - index: StatePartIndex(10), - }, - state: 0x1, - last_state: 0x1, - }, - SimTrace { - id: TraceScalarId(21), - kind: BigSyncReset { - index: StatePartIndex(11), - }, - state: 0x0, - last_state: 0x0, - }, - SimTrace { - id: TraceScalarId(22), - kind: SimOnly { - index: StatePartIndex(11), - ty: SimOnly>>, - }, - state: { - "bar": "", - "extra": "value", - "foo": "baz", - }, - last_state: { - "bar": "", - "extra": "value", - "foo": "baz", - }, - }, - SimTrace { - id: TraceScalarId(23), - kind: SimOnly { - index: StatePartIndex(12), - ty: SimOnly>>, - }, - state: { - "bar": "baz", - "extra": "value", - "foo": "baz", - }, - last_state: { - "bar": "baz", - "extra": "value", - "foo": "baz", - }, - }, - ], - trace_memories: {}, - trace_writers: [ - Running( - VcdWriter { - finished_init: true, - timescale: 1 ps, - .. - }, - ), - ], - instant: 16 μs, - clocks_triggered: [ - StatePartIndex(1), - ], - .. -} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/sim_only_connects.vcd b/crates/fayalite/tests/sim/expected/sim_only_connects.vcd deleted file mode 100644 index 2f464c0..0000000 --- a/crates/fayalite/tests/sim/expected/sim_only_connects.vcd +++ /dev/null @@ -1,185 +0,0 @@ -$timescale 1 ps $end -$scope module sim_only_connects $end -$scope struct cd $end -$var wire 1 ! clk $end -$var wire 1 " rst $end -$upscope $end -$var string 1 # inp $end -$var string 1 $ out1 $end -$var string 1 % out2 $end -$var string 1 & out3 $end -$scope struct helper1 $end -$scope struct cd $end -$var wire 1 + clk $end -$var wire 1 , rst $end -$upscope $end -$var string 1 - inp $end -$var string 1 . out $end -$upscope $end -$scope module sim_only_connects_helper $end -$scope struct cd $end -$var wire 1 ' clk $end -$var wire 1 ( rst $end -$upscope $end -$var string 1 ) inp $end -$var string 1 * out $end -$upscope $end -$var string 1 / delay1 $end -$var reg 1 0 delay1_empty $end -$scope struct helper2 $end -$scope struct cd $end -$var wire 1 5 clk $end -$var wire 1 6 rst $end -$upscope $end -$var string 1 7 inp $end -$var string 1 8 out $end -$upscope $end -$scope module sim_only_connects_helper_2 $end -$scope struct cd $end -$var wire 1 1 clk $end -$var wire 1 2 rst $end -$upscope $end -$var string 1 3 inp $end -$var string 1 4 out $end -$upscope $end -$upscope $end -$enddefinitions $end -$dumpvars -0! -1" -s{\"extra\":\x20\"value\"} # -s{} $ -s{} % -s{} & -0' -1( -s{} ) -s{} * -0+ -1, -s{} - -s{} . -s{} / -00 -01 -12 -s{} 3 -s{} 4 -05 -16 -s{} 7 -s{} 8 -$end -#1000000 -1! -1' -1+ -10 -11 -15 -s{\"extra\":\x20\"value\"} $ -s{\"extra\":\x20\"value\"} ) -s{\"extra\":\x20\"value\"} - -s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} * -s{\"bar\":\x20\"\",\x20\"foo\":\x20\"baz\"} 4 -s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} % -s{\"bar\":\x20\"\",\x20\"foo\":\x20\"baz\"} & -s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} . -s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} 3 -s{\"bar\":\x20\"\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} 7 -s{\"bar\":\x20\"\",\x20\"foo\":\x20\"baz\"} 8 -#2000000 -0! -0" -0' -0( -0+ -0, -01 -02 -05 -06 -#3000000 -1! -1' -1+ -s{\"extra\":\x20\"value\"} / -00 -11 -15 -s{\"bar\":\x20\"baz\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} 4 -s{\"bar\":\x20\"baz\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} & -s{\"bar\":\x20\"baz\",\x20\"extra\":\x20\"value\",\x20\"foo\":\x20\"baz\"} 8 -#4000000 -0! -0' -0+ -01 -05 -#5000000 -1! -1' -1+ -11 -15 -#6000000 -0! -0' -0+ -01 -05 -#7000000 -1! -1' -1+ -11 -15 -#8000000 -0! -0' -0+ -01 -05 -#9000000 -1! -1' -1+ -11 -15 -#10000000 -0! -0' -0+ -01 -05 -#11000000 -1! -1' -1+ -11 -15 -#12000000 -0! -0' -0+ -01 -05 -#13000000 -1! -1' -1+ -11 -15 -#14000000 -0! -0' -0+ -01 -05 -#15000000 -1! -1' -1+ -11 -15 -#16000000 diff --git a/crates/fayalite/tests/ui/module.rs b/crates/fayalite/tests/ui/module.rs index ee0f988..36649aa 100644 --- a/crates/fayalite/tests/ui/module.rs +++ b/crates/fayalite/tests/ui/module.rs @@ -11,20 +11,4 @@ pub fn my_module(a: i32, m: u32, (m, _): (i32, u32)) { let o: UInt<8> = m.output(); } -#[hdl_module] -pub fn my_module2(platform_io_builder: PlatformIOBuilder<'_>) { - #[hdl] - let a: UInt<8> = m.input(); - #[hdl] - let b: UInt<8> = m.output(); - #[hdl] - let io = m.add_platform_io(platform_io_builder); - #[hdl] - let c: UInt<8> = m.input(); - #[hdl] - let d: UInt<8> = m.output(); - #[hdl] - let io = m.add_platform_io(platform_io_builder); -} - fn main() {} diff --git a/crates/fayalite/tests/ui/module.stderr b/crates/fayalite/tests/ui/module.stderr index 979e76f..efbd1fe 100644 --- a/crates/fayalite/tests/ui/module.stderr +++ b/crates/fayalite/tests/ui/module.stderr @@ -1,47 +1,17 @@ -error: name conflicts with implicit `m: &ModuleBuilder` +error: name conflicts with implicit `m: &mut ModuleBuilder<_>` --> tests/ui/module.rs:7:26 | 7 | pub fn my_module(a: i32, m: u32, (m, _): (i32, u32)) { | ^ -error: name conflicts with implicit `m: &ModuleBuilder` +error: name conflicts with implicit `m: &mut ModuleBuilder<_>` --> tests/ui/module.rs:7:35 | 7 | pub fn my_module(a: i32, m: u32, (m, _): (i32, u32)) { | ^ -error: name conflicts with implicit `m: &ModuleBuilder` +error: name conflicts with implicit `m: &mut ModuleBuilder<_>` --> tests/ui/module.rs:9:9 | 9 | let m: UInt<8> = m.input(); | ^ - -error: can't have other inputs/outputs in a module using m.add_platform_io() - --> tests/ui/module.rs:17:24 - | -17 | let a: UInt<8> = m.input(); - | ^^^^^ - -error: can't have other inputs/outputs in a module using m.add_platform_io() - --> tests/ui/module.rs:19:24 - | -19 | let b: UInt<8> = m.output(); - | ^^^^^^ - -error: can't have other inputs/outputs in a module using m.add_platform_io() - --> tests/ui/module.rs:23:24 - | -23 | let c: UInt<8> = m.input(); - | ^^^^^ - -error: can't have other inputs/outputs in a module using m.add_platform_io() - --> tests/ui/module.rs:25:24 - | -25 | let d: UInt<8> = m.output(); - | ^^^^^^ - -error: can't use m.add_platform_io() more than once in a single module - --> tests/ui/module.rs:27:16 - | -27 | let io = m.add_platform_io(platform_io_builder); - | ^^^^^^^^^^^^^^^ diff --git a/crates/fayalite/tests/ui/simvalue_is_not_internable.rs b/crates/fayalite/tests/ui/simvalue_is_not_internable.rs deleted file mode 100644 index d40990f..0000000 --- a/crates/fayalite/tests/ui/simvalue_is_not_internable.rs +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -//! check that SimValue can't be interned, since equality may ignore types - -use fayalite::{ - intern::{Intern, Interned}, - sim::value::SimValue, -}; - -fn f(v: SimValue<()>) -> Interned> { - Intern::intern_sized(v) -} - -fn main() {} diff --git a/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr b/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr deleted file mode 100644 index 1fd291c..0000000 --- a/crates/fayalite/tests/ui/simvalue_is_not_internable.stderr +++ /dev/null @@ -1,369 +0,0 @@ -error[E0277]: `Cell` cannot be shared between threads safely - --> tests/ui/simvalue_is_not_internable.rs:11:26 - | -11 | fn f(v: SimValue<()>) -> Interned> { - | ^^^^^^^^^^^^^^^^^^^^^^ `Cell` cannot be shared between threads safely - | - = help: within `SimValue<()>`, the trait `Sync` is not implemented for `Cell` - = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` -note: required because it appears within the type `util::alternating_cell::AlternatingCell>` - --> src/util/alternating_cell.rs - | - | pub(crate) struct AlternatingCell { - | ^^^^^^^^^^^^^^^ -note: required because it appears within the type `SimValue<()>` - --> src/sim/value.rs - | - | pub struct SimValue { - | ^^^^^^^^ -note: required by a bound in `fayalite::intern::Interned` - --> src/intern.rs - | - | pub struct Interned { - | ^^^^ required by this bound in `Interned` - -error[E0277]: `UnsafeCell>` cannot be shared between threads safely - --> tests/ui/simvalue_is_not_internable.rs:11:26 - | -11 | fn f(v: SimValue<()>) -> Interned> { - | ^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell>` cannot be shared between threads safely - | - = help: within `SimValue<()>`, the trait `Sync` is not implemented for `UnsafeCell>` -note: required because it appears within the type `util::alternating_cell::AlternatingCell>` - --> src/util/alternating_cell.rs - | - | pub(crate) struct AlternatingCell { - | ^^^^^^^^^^^^^^^ -note: required because it appears within the type `SimValue<()>` - --> src/sim/value.rs - | - | pub struct SimValue { - | ^^^^^^^^ -note: required by a bound in `fayalite::intern::Interned` - --> src/intern.rs - | - | pub struct Interned { - | ^^^^ required by this bound in `Interned` - -error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely - --> tests/ui/simvalue_is_not_internable.rs:11:26 - | -11 | fn f(v: SimValue<()>) -> Interned> { - | ^^^^^^^^^^^^^^^^^^^^^^ `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely - | - = help: within `SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` -note: required because it appears within the type `DynSimOnlyValue` - --> src/sim/value/sim_only_value_unsafe.rs - | - | pub struct DynSimOnlyValue(Rc); - | ^^^^^^^^^^^^^^^ -note: required because it appears within the type `PhantomData` - --> $RUST/core/src/marker.rs - | - | pub struct PhantomData; - | ^^^^^^^^^^^ -note: required because it appears within the type `alloc::raw_vec::RawVec` - --> $RUST/alloc/src/raw_vec/mod.rs - | - | pub(crate) struct RawVec { - | ^^^^^^ -note: required because it appears within the type `Vec` - --> $RUST/alloc/src/vec/mod.rs - | - | pub struct Vec { - | ^^^ -note: required because it appears within the type `OpaqueSimValue` - --> src/ty.rs - | - | pub struct OpaqueSimValue { - | ^^^^^^^^^^^^^^ -note: required because it appears within the type `value::SimValueInner<()>` - --> src/sim/value.rs - | - | struct SimValueInner { - | ^^^^^^^^^^^^^ -note: required because it appears within the type `UnsafeCell>` - --> $RUST/core/src/cell.rs - | - | pub struct UnsafeCell { - | ^^^^^^^^^^ -note: required because it appears within the type `util::alternating_cell::AlternatingCell>` - --> src/util/alternating_cell.rs - | - | pub(crate) struct AlternatingCell { - | ^^^^^^^^^^^^^^^ -note: required because it appears within the type `SimValue<()>` - --> src/sim/value.rs - | - | pub struct SimValue { - | ^^^^^^^^ -note: required by a bound in `fayalite::intern::Interned` - --> src/intern.rs - | - | pub struct Interned { - | ^^^^ required by this bound in `Interned` - -error[E0277]: the trait bound `SimValue<()>: Intern` is not satisfied - --> tests/ui/simvalue_is_not_internable.rs:12:26 - | -12 | Intern::intern_sized(v) - | -------------------- ^ the trait `Hash` is not implemented for `SimValue<()>` - | | - | required by a bound introduced by this call - | - = note: required for `SimValue<()>` to implement `Intern` -help: consider dereferencing here - | -12 | Intern::intern_sized(*v) - | + - -error[E0277]: the trait bound `SimValue<()>: Intern` is not satisfied - --> tests/ui/simvalue_is_not_internable.rs:12:26 - | -12 | Intern::intern_sized(v) - | -------------------- ^ the trait `std::cmp::Eq` is not implemented for `SimValue<()>` - | | - | required by a bound introduced by this call - | - = note: required for `SimValue<()>` to implement `Intern` -help: consider dereferencing here - | -12 | Intern::intern_sized(*v) - | + - -error[E0277]: `Cell` cannot be shared between threads safely - --> tests/ui/simvalue_is_not_internable.rs:12:26 - | -12 | Intern::intern_sized(v) - | -------------------- ^ `Cell` cannot be shared between threads safely - | | - | required by a bound introduced by this call - | - = help: within `SimValue<()>`, the trait `Sync` is not implemented for `Cell` - = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` -note: required because it appears within the type `util::alternating_cell::AlternatingCell>` - --> src/util/alternating_cell.rs - | - | pub(crate) struct AlternatingCell { - | ^^^^^^^^^^^^^^^ -note: required because it appears within the type `SimValue<()>` - --> src/sim/value.rs - | - | pub struct SimValue { - | ^^^^^^^^ -note: required by a bound in `intern_sized` - --> src/intern.rs - | - | pub trait Intern: Any + Send + Sync { - | ^^^^ required by this bound in `Intern::intern_sized` -... - | fn intern_sized(self) -> Interned - | ------------ required by a bound in this associated function -help: consider dereferencing here - | -12 | Intern::intern_sized(*v) - | + - -error[E0277]: `UnsafeCell>` cannot be shared between threads safely - --> tests/ui/simvalue_is_not_internable.rs:12:26 - | -12 | Intern::intern_sized(v) - | -------------------- ^ `UnsafeCell>` cannot be shared between threads safely - | | - | required by a bound introduced by this call - | - = help: within `SimValue<()>`, the trait `Sync` is not implemented for `UnsafeCell>` -note: required because it appears within the type `util::alternating_cell::AlternatingCell>` - --> src/util/alternating_cell.rs - | - | pub(crate) struct AlternatingCell { - | ^^^^^^^^^^^^^^^ -note: required because it appears within the type `SimValue<()>` - --> src/sim/value.rs - | - | pub struct SimValue { - | ^^^^^^^^ -note: required by a bound in `intern_sized` - --> src/intern.rs - | - | pub trait Intern: Any + Send + Sync { - | ^^^^ required by this bound in `Intern::intern_sized` -... - | fn intern_sized(self) -> Interned - | ------------ required by a bound in this associated function -help: consider dereferencing here - | -12 | Intern::intern_sized(*v) - | + - -error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely - --> tests/ui/simvalue_is_not_internable.rs:12:26 - | -12 | Intern::intern_sized(v) - | -------------------- ^ `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely - | | - | required by a bound introduced by this call - | - = help: within `SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` -note: required because it appears within the type `DynSimOnlyValue` - --> src/sim/value/sim_only_value_unsafe.rs - | - | pub struct DynSimOnlyValue(Rc); - | ^^^^^^^^^^^^^^^ -note: required because it appears within the type `PhantomData` - --> $RUST/core/src/marker.rs - | - | pub struct PhantomData; - | ^^^^^^^^^^^ -note: required because it appears within the type `alloc::raw_vec::RawVec` - --> $RUST/alloc/src/raw_vec/mod.rs - | - | pub(crate) struct RawVec { - | ^^^^^^ -note: required because it appears within the type `Vec` - --> $RUST/alloc/src/vec/mod.rs - | - | pub struct Vec { - | ^^^ -note: required because it appears within the type `OpaqueSimValue` - --> src/ty.rs - | - | pub struct OpaqueSimValue { - | ^^^^^^^^^^^^^^ -note: required because it appears within the type `value::SimValueInner<()>` - --> src/sim/value.rs - | - | struct SimValueInner { - | ^^^^^^^^^^^^^ -note: required because it appears within the type `UnsafeCell>` - --> $RUST/core/src/cell.rs - | - | pub struct UnsafeCell { - | ^^^^^^^^^^ -note: required because it appears within the type `util::alternating_cell::AlternatingCell>` - --> src/util/alternating_cell.rs - | - | pub(crate) struct AlternatingCell { - | ^^^^^^^^^^^^^^^ -note: required because it appears within the type `SimValue<()>` - --> src/sim/value.rs - | - | pub struct SimValue { - | ^^^^^^^^ -note: required by a bound in `intern_sized` - --> src/intern.rs - | - | pub trait Intern: Any + Send + Sync { - | ^^^^ required by this bound in `Intern::intern_sized` -... - | fn intern_sized(self) -> Interned - | ------------ required by a bound in this associated function -help: consider dereferencing here - | -12 | Intern::intern_sized(*v) - | + - -error[E0277]: `Cell` cannot be shared between threads safely - --> tests/ui/simvalue_is_not_internable.rs:12:5 - | -12 | Intern::intern_sized(v) - | ^^^^^^^^^^^^^^^^^^^^^^^ `Cell` cannot be shared between threads safely - | - = help: within `SimValue<()>`, the trait `Sync` is not implemented for `Cell` - = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` -note: required because it appears within the type `util::alternating_cell::AlternatingCell>` - --> src/util/alternating_cell.rs - | - | pub(crate) struct AlternatingCell { - | ^^^^^^^^^^^^^^^ -note: required because it appears within the type `SimValue<()>` - --> src/sim/value.rs - | - | pub struct SimValue { - | ^^^^^^^^ -note: required by a bound in `fayalite::intern::Interned` - --> src/intern.rs - | - | pub struct Interned { - | ^^^^ required by this bound in `Interned` - -error[E0277]: `UnsafeCell>` cannot be shared between threads safely - --> tests/ui/simvalue_is_not_internable.rs:12:5 - | -12 | Intern::intern_sized(v) - | ^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell>` cannot be shared between threads safely - | - = help: within `SimValue<()>`, the trait `Sync` is not implemented for `UnsafeCell>` -note: required because it appears within the type `util::alternating_cell::AlternatingCell>` - --> src/util/alternating_cell.rs - | - | pub(crate) struct AlternatingCell { - | ^^^^^^^^^^^^^^^ -note: required because it appears within the type `SimValue<()>` - --> src/sim/value.rs - | - | pub struct SimValue { - | ^^^^^^^^ -note: required by a bound in `fayalite::intern::Interned` - --> src/intern.rs - | - | pub struct Interned { - | ^^^^ required by this bound in `Interned` - -error[E0277]: `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely - --> tests/ui/simvalue_is_not_internable.rs:12:5 - | -12 | Intern::intern_sized(v) - | ^^^^^^^^^^^^^^^^^^^^^^^ `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` cannot be sent between threads safely - | - = help: within `SimValue<()>`, the trait `Send` is not implemented for `Rc<(dyn value::sim_only_value_unsafe::DynSimOnlyValueTrait + 'static)>` -note: required because it appears within the type `DynSimOnlyValue` - --> src/sim/value/sim_only_value_unsafe.rs - | - | pub struct DynSimOnlyValue(Rc); - | ^^^^^^^^^^^^^^^ -note: required because it appears within the type `PhantomData` - --> $RUST/core/src/marker.rs - | - | pub struct PhantomData; - | ^^^^^^^^^^^ -note: required because it appears within the type `alloc::raw_vec::RawVec` - --> $RUST/alloc/src/raw_vec/mod.rs - | - | pub(crate) struct RawVec { - | ^^^^^^ -note: required because it appears within the type `Vec` - --> $RUST/alloc/src/vec/mod.rs - | - | pub struct Vec { - | ^^^ -note: required because it appears within the type `OpaqueSimValue` - --> src/ty.rs - | - | pub struct OpaqueSimValue { - | ^^^^^^^^^^^^^^ -note: required because it appears within the type `value::SimValueInner<()>` - --> src/sim/value.rs - | - | struct SimValueInner { - | ^^^^^^^^^^^^^ -note: required because it appears within the type `UnsafeCell>` - --> $RUST/core/src/cell.rs - | - | pub struct UnsafeCell { - | ^^^^^^^^^^ -note: required because it appears within the type `util::alternating_cell::AlternatingCell>` - --> src/util/alternating_cell.rs - | - | pub(crate) struct AlternatingCell { - | ^^^^^^^^^^^^^^^ -note: required because it appears within the type `SimValue<()>` - --> src/sim/value.rs - | - | pub struct SimValue { - | ^^^^^^^^ -note: required by a bound in `fayalite::intern::Interned` - --> src/intern.rs - | - | pub struct Interned { - | ^^^^ required by this bound in `Interned` diff --git a/crates/fayalite/visit_types.json b/crates/fayalite/visit_types.json index 04227ef..3eff1f5 100644 --- a/crates/fayalite/visit_types.json +++ b/crates/fayalite/visit_types.json @@ -49,9 +49,7 @@ "AsyncReset": "Visible", "SyncReset": "Visible", "Reset": "Visible", - "Clock": "Visible", - "PhantomConst": "Visible", - "DynSimOnly": "Visible" + "Clock": "Visible" } }, "Bundle": { @@ -161,8 +159,7 @@ "data": { "$kind": "Struct", "verilog_name": "Visible", - "parameters": "Visible", - "simulation": "Visible" + "parameters": "Visible" } }, "ExternModuleParameter": { @@ -1176,8 +1173,7 @@ "BlackBoxInline": "Visible", "BlackBoxPath": "Visible", "DocString": "Visible", - "CustomFirrtl": "Visible", - "Xilinx": "Visible" + "CustomFirrtl": "Visible" } }, "DontTouchAnnotation": { @@ -1215,29 +1211,6 @@ "$kind": "Opaque" } }, - "XilinxAnnotation": { - "data": { - "$kind": "Enum", - "XdcLocation": "Visible", - "XdcIOStandard": "Visible", - "XdcCreateClock": "Visible" - } - }, - "XdcLocationAnnotation": { - "data": { - "$kind": "Opaque" - } - }, - "XdcIOStandardAnnotation": { - "data": { - "$kind": "Opaque" - } - }, - "XdcCreateClockAnnotation": { - "data": { - "$kind": "Opaque" - } - }, "Target": { "data": { "$kind": "Enum", @@ -1289,22 +1262,6 @@ "ArrayElement": "Visible", "DynArrayElement": "Visible" } - }, - "PhantomConst": { - "data": { - "$kind": "Opaque" - }, - "generics": "" - }, - "DynSimOnly": { - "data": { - "$kind": "Opaque" - } - }, - "ExternModuleSimulation": { - "data": { - "$kind": "ManualImpl" - } } } } \ No newline at end of file