diff --git a/.github/workflows/wai-quantum-landscape-fpga.yml b/.github/workflows/wai-quantum-landscape-fpga.yml new file mode 100644 index 000000000..1fa41fddb --- /dev/null +++ b/.github/workflows/wai-quantum-landscape-fpga.yml @@ -0,0 +1,146 @@ +name: wai-quantum-landscape-fpga reference design + +# The FPGA board's member of energy-landscape jobs (wai/wai-quantum-landscape-fpga): its unit tests and +# clippy, warnings as errors; the member certified on the model of the logic (src/model.rs) and every +# check of the conformance set, every worked example and the joint-statistics test run on it; the +# board's code built and tested on the board's processor's architecture (aarch64, linux-arm64), +# where its cache maintenance compiles; +# and the logic itself: both testbenches replay the model's session against the RTL in an +# open-source simulator, every read checked. No board and no vendor tool here: the board's own runs +# are in the crate's measurements and README. +# +# Push filters match the push's delta, so every path the jobs read is listed. + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + push: + branches: [main] + paths: + - 'wai/wai-quantum-landscape-fpga/**' + - 'wai/wai-quantum/src/quantum_landscape/**' + - 'wai/wai-quantum/src/quantum_landscape.rs' + - 'wai/wai-quantum/src/repro.rs' + - 'wai/wai-quantum/Cargo.toml' + - 'wai/quantum-conformance/landscape/**' + - 'rust-toolchain.toml' + - '.github/workflows/wai-quantum-landscape-fpga.yml' + pull_request: + paths: + - 'wai/wai-quantum-landscape-fpga/**' + - 'wai/wai-quantum/src/quantum_landscape/**' + - 'wai/wai-quantum/src/quantum_landscape.rs' + - 'wai/wai-quantum/src/repro.rs' + - 'wai/wai-quantum/Cargo.toml' + - 'wai/quantum-conformance/landscape/**' + - 'rust-toolchain.toml' + - '.github/workflows/wai-quantum-landscape-fpga.yml' + +jobs: + relevant: + name: does this change touch it + runs-on: gate + outputs: + run: ${{ steps.gate.outputs.run }} + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + - id: gate + run: | + set -euo pipefail + r=$(python3 scripts/pr-touches-paths.py .github/workflows/wai-quantum-landscape-fpga.yml \ + "${{ github.event.pull_request.base.sha }}" \ + "${{ github.event.pull_request.head.sha }}") + echo "this change touches wai-quantum-landscape-fpga: $r" + echo "run=$r" >> "$GITHUB_OUTPUT" + + model: + name: the member against the model of the logic, and the logic against the model · linux, release + needs: relevant + if: needs.relevant.outputs.run == 'true' + runs-on: linux + timeout-minutes: 60 + steps: + - uses: actions/checkout@v5 + - name: Install Rust 1.99.1 and the simulator + shell: bash + run: | + export PATH="$HOME/.cargo/bin:$PATH" + command -v rustup >/dev/null 2>&1 || \ + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.99.1 + rustup toolchain install 1.99.1 --profile minimal --component clippy + rustup default 1.99.1 + echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" + SUDO=""; [ "$(id -u)" -ne 0 ] && SUDO="sudo" + command -v iverilog >/dev/null || { $SUDO apt-get update -qq; $SUDO apt-get install -y -qq iverilog; } + - name: Unit tests and clippy + shell: bash + working-directory: wai/wai-quantum-landscape-fpga + run: | + set -euo pipefail + cargo test --locked --release 2>&1 | tee "$RUNNER_TEMP/test.log" + grep -qE '^test result: ok\. [1-9][0-9]* passed; 0 failed' "$RUNNER_TEMP/test.log" || { echo "::error::no test ran"; exit 1; } + cargo clippy --locked --release --all-targets -- -D warnings + # Every case the engine holds must give the reference's bits and every one it cannot must be + # refused (the checks); the host's certification is printed, whatever it is: under the set + # as it stands, cases beyond the engine's 64 cells cost it its certificate (README). + - name: The member certified, the conformance set and the worked examples, on the model + shell: bash + working-directory: wai/wai-quantum-landscape-fpga + run: | + set -euo pipefail + cargo run --locked --release -- selftest --scale 0.05 --seeds 5 | tee "$RUNNER_TEMP/selftest.log" + grep -q 'certified by the host on the conformance set: settle ' "$RUNNER_TEMP/selftest.log" + grep -qE '^settle cases the engine holds: ([0-9]+)/\1 bit for bit' "$RUNNER_TEMP/selftest.log" + grep -qE '^chains the engine holds: ([0-9]+)/\1 bit for bit' "$RUNNER_TEMP/selftest.log" + grep -qE '^[0-9]+ checks, 0 failed$' "$RUNNER_TEMP/selftest.log" + - name: A job on the model, certified and sealed, with the reference's answer + shell: bash + working-directory: wai/wai-quantum-landscape-fpga + run: | + set -euo pipefail + printf '{"program": "vars 2\\noppose 0 1\\nsolve\\n", "seed": "7"}' | cargo run --locked --release -- landscape run - --model --demo-key > "$RUNNER_TEMP/job.json" + grep -q '"id": "fpga:model-landscape-64"' "$RUNNER_TEMP/job.json" + grep -q '"state": "-+"' "$RUNNER_TEMP/job.json" + - name: Joint statistics against exact enumeration, on the model + shell: bash + working-directory: wai/wai-quantum-landscape-fpga + run: | + set -euo pipefail + cargo run --locked --release -- joint --model --scale 0.05 | tee "$RUNNER_TEMP/joint.log" + grep -qE '^[0-9]+ checks, 0 failed$' "$RUNNER_TEMP/joint.log" + - name: The logic against the model, both testbenches + shell: bash + working-directory: wai/wai-quantum-landscape-fpga + run: sh scripts/run_tb.sh both + + board-target: + name: the board's code on the board's processor's architecture · linux-arm64, release + needs: relevant + if: needs.relevant.outputs.run == 'true' + runs-on: linux-arm64 + timeout-minutes: 60 + steps: + - uses: actions/checkout@v5 + - name: Install Rust 1.99.1 + shell: bash + run: | + export PATH="$HOME/.cargo/bin:$PATH" + command -v rustup >/dev/null 2>&1 || \ + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.99.1 + rustup toolchain install 1.99.1 --profile minimal --component clippy + rustup default 1.99.1 + echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" + # The cache maintenance the DMA needs (dc cvac, dc civac, dsb) compiles only for aarch64. + - name: Unit tests and clippy + shell: bash + working-directory: wai/wai-quantum-landscape-fpga + run: | + set -euo pipefail + cargo test --locked --release 2>&1 | tee "$RUNNER_TEMP/test.log" + grep -qE '^test result: ok\. [1-9][0-9]* passed; 0 failed' "$RUNNER_TEMP/test.log" || { echo "::error::no test ran"; exit 1; } + cargo clippy --locked --release --all-targets -- -D warnings + diff --git a/scripts/check-public-names.sh b/scripts/check-public-names.sh index 7415e6936..adee4c89c 100755 --- a/scripts/check-public-names.sh +++ b/scripts/check-public-names.sh @@ -31,7 +31,9 @@ # CI runs it so on every change, a pull request included. # # Scope: the tracked files under wai/ with the extensions .md .rs .toml .py -# .sh .mjs .js .json .html .css .ttl .h .c .txt, and wai/'s .gitignore files; +# .sh .mjs .js .json .html .css .ttl .h .c .txt .wgsl, the logic's sources and +# build files (.v .tcl .xdc) and the measurements' logs (.dat), and wai/'s +# .gitignore files; # or, when files are given as arguments, those files (the self-test, # scripts/test-public-text-checks.sh, uses this), each a path relative to the # directory the script is run from, or absolute. No file is excluded: the @@ -116,7 +118,7 @@ else files+=("$f") done < <(git ls-files 'wai/*.md' 'wai/*.rs' 'wai/*.toml' 'wai/*.py' 'wai/*.sh' 'wai/*.mjs' 'wai/*.js' \ 'wai/*.json' 'wai/*.html' 'wai/*.css' 'wai/*.ttl' 'wai/*.h' 'wai/*.c' 'wai/*.txt' \ - 'wai/*.gitignore' 'wai/*.wgsl') + 'wai/*.gitignore' 'wai/*.wgsl' 'wai/*.v' 'wai/*.tcl' 'wai/*.xdc' 'wai/*.dat') fi if [ ${#files[@]} -eq 0 ]; then echo "::error::no file to check" >&2 diff --git a/wai/changes/2026-11-06-landscape-fpga-member.md b/wai/changes/2026-11-06-landscape-fpga-member.md new file mode 100644 index 000000000..914df0d8d --- /dev/null +++ b/wai/changes/2026-11-06-landscape-fpga-member.md @@ -0,0 +1,11 @@ +### wai-quantum-landscape-fpga: an FPGA board as a member of energy-landscape jobs + +- **`wai-quantum-landscape-fpga`** is a reference design: the settle and sample kernels of `wai.quantum.landscape/1` in programmable logic for up to 64 cells (`rtl/`), the register-level model the logic is tested against, a testbench that replays the model's session against the logic, and the host that runs jobs on the board as a `Member`, holds it to the conformance set and meters its power by run minus halt. The board, its part and its sensor are named as data in its README. +- **The sample kernel takes the reference's draws**: the logic counts and mixes them as SplitMix64 does and compares 53 bits against cut points the host computes with the reference's `cuts`, so it needs no exponential. On the board both kernels were certified bit-exact against the `settle` and `chains` vectors of 2026-11-06, and every worked example over 200 seeds answers as the CPU reference does. The set has since grown past what the engine holds (64 cells, 20-bit sampled fields, a window of 8,192 fields), and a member may not decline those cases, so under the current set the host certifies both kernels `uncertified`; every case the engine holds still gives the reference's bits. +- **An AXI link** (`rtl/landscape_axi.v`) replaces the EMIO register port as the default build: the engine's registers on AXI-Lite, bulk loads read from DDR by a write-list DMA, a sequencer that runs a job's chains in fabric, start to result, and a write-back that puts the results in DDR. The link answers every access within a few clocks whatever the engine is doing, and the host reads a signature over EMIO before every AXI access, so a design replaced by another session is caught before an access could go unanswered. A second testbench drives the link and its DMA against the model. The processor-to-logic latency is measured on the board (`latency`). +- **The sample kernel is held to its exact joint law** (`joint`, `src/exact.rs`): small workloads enumerated over every state, chains on the board against that law by chi-square and G over all states, every cell's and every pair's frequencies, and a control with the right marginals and independent cells that must be rejected. +- **The member is certified by the host** on the conformance set and the statistical battery, runs any schedule of temperatures the job gives, and maps fields and costs beyond its registers exactly for sweeps at 0. +- **One session at a time, and a reload seen:** every board command, `load` included, takes the board's lock first, and the session check sees other runs of this tool. A reload of the same design under a job, which passes the signature and the engine's ID, is seen by the engine's uptime counter and its reset registers, and the job's result is refused instead of kept. +- **CI** builds and tests the host on x86-64 and on aarch64, the board's architecture, certifies the member on the model, and replays both testbenches against the logic in an open-source simulator. `scripts/check-public-names.sh` now also reads `.v`, `.tcl`, `.xdc` and `.dat` files. +- **The measurements** are board-level, one board and one meter, each campaign with its prediction committed first (`measurements/`). No bitstream is distributed: the vendor tool's licence limits a bitstream to that vendor's devices, so the README gives the build steps. +- The design came from a private repository and is released under `Apache-2.0` by its copyright holder (`wai-quantum-landscape-fpga/PROVENANCE.md`). diff --git a/wai/wai-quantum-landscape-fpga/Cargo.lock b/wai/wai-quantum-landscape-fpga/Cargo.lock new file mode 100644 index 000000000..6e413a3b6 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/Cargo.lock @@ -0,0 +1,459 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "blake3" +version = "1.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae" +dependencies = [ + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures 0.3.1", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cc" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375989decec1a0fa424442bed520fa12ede43a48475ce8c7417d2c69b32b5f6b" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "libc" +version = "0.2.191" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "foldhash", + "indexmap", + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wai-quantum" +version = "0.8.1" +dependencies = [ + "blake3", + "ed25519-dalek", + "serde", + "serde_json", +] + +[[package]] +name = "wai-quantum-landscape-fpga" +version = "0.1.0" +dependencies = [ + "blake3", + "serde_json", + "wai-quantum", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "zeroize" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/wai/wai-quantum-landscape-fpga/Cargo.toml b/wai/wai-quantum-landscape-fpga/Cargo.toml new file mode 100644 index 000000000..bb5999a46 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "wai-quantum-landscape-fpga" +version = "0.1.0" +edition = "2024" +rust-version = "1.85" +license = "Apache-2.0" +publish = false +description = "An FPGA board as a member of wai.quantum.landscape/1: the two kernels of the energy-landscape job (the settle sweep and the sampling sweep) in programmable logic, the register-level model the logic is tested against, and the host that runs jobs on the board, holds it to the conformance set and meters its power." +repository = "https://git.transaction.science/Transaction-Science/open-standards" + +[dependencies] +# The job form, the reader, the reference kernels, the answer and its seal: the board is a member, +# so everything but the kernels stays in the reference crate. +wai-quantum = { version = "0.8.1", path = "../wai-quantum", default-features = false, features = ["quantum_landscape", "quantum_engine", "quantum_receipt"] } +serde_json = { version = "1", features = ["preserve_order"] } +blake3 = "1" + +[profile.release] +opt-level = 3 diff --git a/wai/wai-quantum-landscape-fpga/PROVENANCE.md b/wai/wai-quantum-landscape-fpga/PROVENANCE.md new file mode 100644 index 000000000..4772b67fd --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/PROVENANCE.md @@ -0,0 +1,42 @@ +# Where this design came from + +The engine's logic, its register-level model, the host and the power-measurement scripts were +written in a private repository, where the first version of the design was built and measured on +the board, at commit `24bb5c8e8032e95a614a9db1e6f2e98ac7ea1233`. There the host crate's manifest +declared `CC0-1.0`, and the logic, the build script and the shell scripts carried no licence. They +are released here under this repository's `Apache-2.0`, by their copyright holder's decision of +2026-11-05. This repository's `LICENSE` governs everything under this directory. The logic, the +testbenches, the build script, the constraints and the scripts carry +`SPDX-License-Identifier: Apache-2.0`; the Rust sources, as elsewhere in this repository, carry no +header and are covered by `LICENSE` and by `license = "Apache-2.0"` in `Cargo.toml`. + +## What changed from that code + +- **The draws.** The first version drew its own randomness from a 128-bit xoroshiro128+ register and + compared 16 bits against 16-bit cut points, so its sampling was statistical: right in distribution, + different in every bit. Here the engine computes the reference's draws, SplitMix64 over a counter, and + compares 53 bits against 54-bit cut points the host computes with the reference's `cuts`, so its + sampling kernel gives the reference's bits. +- **The table window.** The first version held fields −64 to 63 and refused a job whose uncertain + fields fell outside. Here the window's start and width are registers, and the host places them. +- **Fields and cost** widen from 11 and 10 bits to 20, and a cell update takes four clocks, not three. +- **The job form.** The first host read a request of `key=value` lines and printed a replay line of its + own. Here the host is a `Member` of `wai_quantum::quantum_landscape`, so a job is the spec's JSON + request, its answer the spec's answer, sealed, and the starts, default temperature, limits and + refusals are the reference's, because they are the reference's code. +- **The link.** The first version had only the EMIO port. The AXI link (`rtl/landscape_axi.v`, + `src/axi.rs`), its testbench, the joint-statistics test (`src/exact.rs`) and the latency + measurement (`src/latency.rs`) were written here, after the release. +- **The member's contract.** The host certifies the member and gives it a schedule of temperatures, + as the spec's member trait now says; the first host stated its own parity and took a start + temperature and a sweep count. +- **Names.** Modules, files and the engine's ID (`LAND`) are named for what they do. + +## What is not here + +No bitstream (README, "Build and load"). Nor the known-answer vehicle the power campaigns checked +the meter with: a design of the maintainers' own from 2026-09 and the script that runs it, both in +the private repository. A builder uses a known answer of their own (`KNOWN_ANSWER` in +`scripts/power_campaign.sh`) or none; the null and the clock-scaling check need nothing else. The first version's raw power logs are in +`measurements/2026-11-05/` as they were written, under that version's tool name; its predictions are +the files committed before that measurement, copied unchanged. diff --git a/wai/wai-quantum-landscape-fpga/README.md b/wai/wai-quantum-landscape-fpga/README.md new file mode 100644 index 000000000..82b9fc342 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/README.md @@ -0,0 +1,418 @@ +# wai-quantum-landscape-fpga + +An FPGA board as a member of [`wai.quantum.landscape/1`](../extensions/quantum-landscape.md): the +two kernels of the energy-landscape job, the settle sweep and the sampling sweep, in programmable +logic, with the host that runs jobs on the board, holds it to the conformance set and meters its +power. It is a reference design: the logic, the host, the scripts and the measurements are here, +under this repository's Apache-2.0. + +It is classical throughout. The cells are three-state variables in logic, the randomness is a +counter-based generator, and nothing here is a quantum effect. Every answer says so. + +## The board + +| | | +|---|---| +| board | KV260 starter kit, `SK-KV260-G` (a K26 module on a carrier) | +| programmable logic | `xck26-sfvc784-2LV-c`; board part `xilinx.com:kv260_som:part0:2.0` | +| processor running the host | the module's four Cortex-A53 cores, Ubuntu 24.04 from a microSD card (kernel `6.8.0-*-xilinx`) | +| power sensor read | the carrier's INA260 (`hwmon` name `ina260_u14`), 10 mW steps: the board's input, so every regulator's loss is inside every figure. A sample is one read of its register, once a second, not an average over the second. | +| clock | the processing system's `pl_clk0`, 100 MHz | +| link to the processor | the AXI link (the default build): AXI-Lite registers on the processing system's master port `M_AXI_HPM0_FPD` at `0xA000_0000`, bulk loads read by DMA through its high-performance port `S_AXI_HP0_FPD`, and a chain sequencer in the logic; or, in the EMIO build, 95 EMIO lines of its GPIO controller. Both through `/dev/mem`. | +| the two ports' widths | 128 bits, as this board's boot leaves them; the FPGA manager does not change them, so the AXI build meets them with width converters and writes no processor register. `ps-ports` reads them. | + +The register map is `src/regs.rs` (the engine) and `src/axi.rs` (the link). Nothing else is +board-specific except `landscape.tcl` (part and board part), `src/axi.rs` and `src/emio.rs` (the +link's address, the GPIO controller's), and `src/board.rs` (the FPGA manager, the clock register, +the sensor's name). + +## What it does + +One engine (`rtl/landscape_core.v`) holds up to 64 cells. Each cell's field +`h_i = b_i + Σ_j W_ij s_j` is computed every clock by its own adder cone. The couplings `W` (−1, 0, ++1), the fields `b` (20 bits signed), the cost `c` (20 bits) and the cut-point table are registers +the host writes. + +| mode | what it is | +|---|---| +| T0 | the settle kernel, §4.1: every cell at once to `threshold(h, c)`, one sweep a clock, stopping at a fixed point, a two-cycle or the bound. Whole-number arithmetic. | +| GIBBS | the sample kernel, §4.2: one cell at a time in order, each drawn given the cells before it have just moved. Four clocks a cell. | +| JACOBI | every cell drawn from the same old state and moved together. **Not** a kernel of the spec: it does not sample the joint distribution. It is here only as the negative control the spec's coupled test must catch. | + +**The draws are the reference's.** The draw of cell `i` in sweep `k` of a chain with seed `C` is the +top 53 bits of `out(C, k·n + i + 1) = mix(C + (k·n + i + 1)·0x9E3779B97F4A7C15)`. The index rises by +one per cell, so the engine keeps a counter, adds the constant once a cell, and runs SplitMix64's +`mix` in a nine-stage pipeline (two 64-bit products in sixteen-bit limbs, 20 DSP slices). The host +writes the counter's start, `C + 0x9E3779B97F4A7C15`. + +**The cut points come from the host.** For each sweep's temperature the host computes +`(a, b) = cuts(h, c, 1/T)` with the reference's own function, so the logic needs no exponential; a +cell returns −1 if `u < a`, 0 if `u < b`, else +1. The table holds 8,192 pairs of 54 bits, as +`2^(13−WBITS)` temperature levels of `2^WBITS` fields from `WIN_LO`. A field outside the window takes +the threshold, which is the reference's draw only where that draw is certain, so the host places the +window over every field a cell can reach whose draw is not certain at some temperature of the run, +and refuses a job for which no window fits. A run longer than the table goes in segments: the host +rewrites the table and starts every chain on the next segment from where it ended, its counter at +the draw the reference takes next. + +**The member.** `src/member.rs` implements `wai_quantum::quantum_landscape::member::Member`. It is +named `fpga:kv260-landscape-64`. It says nothing of its own parity: the host certifies it +(`member::certify`), running the conformance set's `settle` and `chains` cases on the device and +granting `bit-exact` to a kernel only if every case it takes comes back bit for bit (and, for a +sampling kernel that misses, trying the statistical battery). It declines only what the spec lets a +member decline (§5: sampling fields above 2^31 − 1). + +**What it cannot hold, and what that costs.** The engine has 64 cells, 20-bit field and cost +registers for sampling, and a table window of 8,192 fields a temperature. The conformance set as it +stands now holds cases past all three (settle cases of 65 to 1,000 cells, chains of 128 and 1,024 +cells, sampled fields up to 2^31 − 1, a battery workload whose uncertain fields span 135,000), and +the spec does not let a member decline them. The board refuses each with a sentence, never with +wrong bits, and every case it can hold it gives bit for bit (`conform`). But a refused case is a +missed vector, so the host certifies both kernels `uncertified` under the current set, and a job +on the board says so. The board was certified `bit-exact` for both kernels under the set of +2026-11-06 (`vectors.json` sha256 `43e543a634e0ffdc...`), before the set grew; the measurements +below were taken then. It runs whatever schedule the job gives, one +temperature a sweep: a run of sweeps above 0 as sampled segments, a run at 0 in T0 mode, sweep `k` +drawing from `k·n + 1` whatever came before it. The reader, the truth, the energy, the verdict, the +checks on what a member returns, the replay digest and the seal stay on the host +(`wai_quantum::quantum_landscape`), so a job's answer on the board is the spec's answer, with +`member` naming the board and the receipt naming the key that sealed it. + +**Large fields at temperature 0.** The spec allows fields and costs far beyond the engine's 20-bit +registers. At temperature 0 a cell compares its coupling sum `S`, which lies in `[−d, d]` (`d` its +couplings, at most 63), with two thresholds, `c − b` and `−c − b`; only where a threshold falls in +`[−d − 1, d + 1]` does its exact place matter. So for sweeps at 0 the host maps a field or cost too +large for the engine to one that leaves every comparison the same, and the settle is the same bit +for bit (`member::lowered_settle`; the conformance set's `fields-at-the-bound` case, fields of 2^40, +reaches three of its five cases, and the crate's tests hold all five, with 300 random workloads of +fields and costs up to 2^40, to the reference's settle). Sampling with such fields is refused. + +**Limits, and what the host refuses with a sentence:** more than 64 variables; sampling with a field +beyond ±524,287 or a cost beyond 1,048,575; a job whose uncertain fields span more than 8,192. + +## The link + +**AXI-Lite registers** (`rtl/landscape_axi.v`). Word `k` of the engine's map (`src/regs.rs`) is at +`0xA000_0000 + 4k`; the link's own registers start at word `0x8000` (`src/axi.rs`). + +**Bulk loads by DMA.** The host writes a list of 64-bit entries, `{address, value}`, into locked +pages, cleans them from its caches to DDR (the high-performance port is not coherent), and gives the +link the page's physical address; the link reads the list in 16-beat bursts and applies one entry +every two clocks. Couplings, fields, a whole cut-point table and a batch's chain starts all go this +way. A read error stops the applying and is reported; the list is still drained. + +**The anneal loop in fabric.** A batch of up to 256 chains goes into the link's chain RAM (each +chain's start and draw counter); the sequencer writes each into the engine, starts it, waits for it, +and copies its state, sweeps and status into the result RAM, chain after chain, with nothing from +the processor between them. The host fills the chain RAM by DMA. + +**Results by DMA.** A write master on the same port sends the result RAM to DDR, 32 bytes a chain, +128 chains a page. The host fills the page with all ones first (the illegal cell pair), cleans and +invalidates it before the write-back and invalidates it after, because the port is not coherent. An +error is reported, the write-back's done count proves it ran, and a result word still all ones +proves it did not write there. + +**Safe on a shared board.** A processor access to a logic address that nothing answers never +completes, and it holds the board until someone power-cycles it; another session may replace the +design between two accesses. So the link puts a constant signature on eight EMIO lines, and the host +reads it, through the GPIO controller, before every AXI access: a GPIO read always answers, so a +replaced design is caught before an AXI access is made. And the link answers every access within a +few clocks whatever the engine is doing: an engine access while the DMA or the sequencer holds the +engine is dropped and counted, never queued, and the host checks the count after every batch. + +**One session at a time, and a reload seen.** Every board command takes one lock before it touches +the board, `load` included, so a reload waits for the job that holds the board. Before a job, the +host looks for another session by name (this tool, its two scripts, the vendor's loader, and what a +site names in `WAI_QUANTUM_LANDSCAPE_FPGA_FOREIGN`). And a reload that comes anyway is seen: a +reload of the same design passes the signature and the engine's ID, but it starts the engine's +uptime counter again and resets its BOUND register, so the host checks both before it takes a +workload or a table as already loaded and after every job, and refuses a result read across a +reload instead of keeping it. + +**The EMIO build** keeps the first link: every register access a handshake over the GPIO lines. The +multi-core build has only that link. + +## What it costs to build + +| item | note | +|---|---| +| the board kit | `SK-KV260-G`, with its power supply. Its price is the vendor's list price; this README does not quote one. | +| a microSD card | 16 GB or more, with the board's Ubuntu 24.04 image | +| a network connection | the host is reached over SSH | +| the vendor's FPGA tool | Vivado 2026.1, which this design was built and measured with. Its no-charge licence tier covers this part. | +| a Linux x86-64 machine for that tool | ours had 15 GB of memory; the tool reported a peak of 5.1 GB for the AXI build | +| a Rust toolchain | the repository's pinned version (`rust-toolchain.toml`), on an aarch64 Linux machine, or with the `aarch64-unknown-linux-gnu` target and `aarch64-linux-gnu-gcc` to cross-compile | + +The design uses no licensed IP: its vendor blocks are the processing system's configuration +(`zynq_ultra_ps_e` 3.5) and, in the AXI build, the tool's AXI width and protocol converters; the +build checks out only the tool's own synthesis and implementation features. + +## Build and load + +```sh +# 1. the bitstream, on the tool's machine, in an empty directory: [MHz] [cores] [axi|emio] +sh wai-quantum-landscape-fpga/scripts/build_bitstream.sh # the AXI build -> landscape.bit.bin, and its sha256 +# 2. the host, for the board's processor +sh wai-quantum-landscape-fpga/scripts/build_host.sh # -> wai-quantum-landscape-fpga (aarch64) +# 3. on the board, as root +./wai-quantum-landscape-fpga load landscape.bit.bin # proves the load by its kernel-log line, then reads the engine's ID +./wai-quantum-landscape-fpga status # every board command finds the loaded link by its signature +``` + +If the FPGA manager's `flags` file reads non-zero (this board boots with `0x20`), a plain +bitstream load needs it set to 0 first; `scripts/run_all.sh` does that and puts it back. + +**No bitstream is distributed here.** The tool's licence (Vivado 2026.1's end-user licence agreement, +§3.1(3)C) allows a bitstream holding the vendor's components to be distributed "only for use to +program a Xilinx Device", and §4(a) grants no right to use one for other devices. That is a +field-of-use condition this repository's Apache-2.0 does not carry, so the build steps are given +instead. The bitstreams measured below had sha256 +`bb82505526e33403073924373a64d3519394344e9bf6d0193634c157e42b6dfb` (the AXI build, as these steps +make it), `3d84dbd355c9552c7593d3d5aa823284a4941acd25e5f3b7c92d5c0bc36ee441` (the first AXI build, +before the result write-back) and `feea5015b2f8d85049fd48bcc66493a411d551326365f67b1db2ae65ec00074c` +(the EMIO build); whether a rebuild gives the same bytes has not been checked. + +## Run the checks + +On the board, as root: + +```sh +./wai-quantum-landscape-fpga conform # the conformance set, the battery and its control, the jobs, random settles, field read-back +./wai-quantum-landscape-fpga agree --seeds 200 # every worked example, board against the CPU reference +./wai-quantum-landscape-fpga joint # joint statistics against exact enumeration, at the registered seed +./wai-quantum-landscape-fpga latency # processor-to-logic latency of the loaded link +./wai-quantum-landscape-fpga throughput +echo '{"program": "vars 2\noppose 0 1\nsolve\n", "seed": "7"}' | ./wai-quantum-landscape-fpga landscape run - +``` + +`landscape` takes the spec's JSON request and prints its answer, sealed with the key in +`$WAI_QUANTUM_KEY` or `~/.config/wai/quantum-key` (made on first use; `--demo-key` and `--unsealed` +as for `wai-quantum`). Anywhere, with no board: + +```sh +cargo run --release -- selftest # every check against the register-level model (src/model.rs) +cargo run --release -- joint --model # the joint-statistics test on the model +cargo run --release -- landscape run req.json --model --demo-key # a job on the model, certified and sealed +sh scripts/run_tb.sh # both testbenches against the logic, in Icarus Verilog +``` + +The testbenches (plain Verilog) replay a session recorded from the model (`gen-tb`) against the +logic and compare every read with the model's. `tb/tb_landscape.v` goes through the EMIO port and +its synchroniser. +`tb/tb_landscape_axi.v` drives the AXI link: register accesses over AXI-Lite, every bulk load and +every batch's chain starts through the DMA from a memory model that answers with irregular delays +and several bursts outstanding, every batch through the sequencer with its results read from the +result RAM and then written back to the memory model, and in every batch an engine read that must +come back at once, dropped and counted. `scripts/run_tb.sh` records both scripts and runs both in +Icarus Verilog, and CI runs it on every change: the EMIO script, 174,345 lines and 2,668 checked +reads, and the AXI script, 175,830 lines, 171 write lists, 50 batches and 4,464 checked values, both +with 0 mismatches, and the vendor's simulator (xsim 2026.1; the command is in the script) gives the +same on the same scripts (`measurements/2026-11-06/build.txt`). A flipped expectation is reported. + +`scripts/run_all.sh` does all of it on the board in order, then the power campaign. + +## The power campaign + +`scripts/power_campaign.sh`, by the rules that follow from a whole-board sensor: + +- **Run minus halt on one bitstream**: no reload between the two states, so placement and clock tree + cancel and the difference is the job's dynamic power. +- **Randomised order** of run and halt in every pass, so drift cannot alias onto it. +- **Sampling on the board, in the measuring process**, nothing else running: the processor is inside + the measurement, so any login or file copy during sampling moves the number. +- **Reload detection at every point**: the engine's uptime counter must keep counting, its ID must + read back, and the kernel log's count of FPGA writes must not move. A flagged pass is dropped. +- **Statistic**: the mean of per-pass differences of medians; error, the standard error across passes. +- **Controls**: a run/halt step response for the settle time (`scripts/step_settle.py`), a null + (halt against halt), the same job at half the clock (dynamic power must halve), and a known-answer + vehicle where one exists. The vehicle used here is a design of the maintainers' own, not in this + repository; a builder's own known answer goes in `KNOWN_ANSWER`. +- **A prediction is committed before each campaign** (`measurements/*/PREDICTION*.txt`). + +## What it measured + +Every figure: **board-level, one board, one meter, this design.** The sensor reads the whole board +at its input (about 3.1 W idle), so the power figures are differences of a few percent of the total, +regulator losses included. The figures in nJ and pJ are derived, not read: a mean power divided by +the rate the engine's own counters give. + +The build sizes, the tool and block versions, the bitstreams' sha256 and the simulator results are +in `measurements/2026-11-06/build.txt`. + +### The builds + +| build | LUTs | registers | block RAM | UltraRAM | DSP | worst slack at 100 MHz | +|---|---|---|---|---|---|---| +| AXI link, one engine (the default) | 28,145 (24.0%) | 13,773 | 4 | 4 | 20 | +0.993 ns | +| EMIO link, one engine | 25,539 (21.8%) | 11,121 | 0 | 4 | 20 | +0.294 ns | +| EMIO link, four engines | 80,927 (69.1%; 95% of slices) | 44,355 | 0 | 16 | 80 | +0.441 ns | + +### Checks on the board (2026-11-06) + +On the final AXI build and the first AXI build, the same results on each; the conformance and +agreement checks also on the EMIO build, with the same results (`measurements/2026-11-06/`): + +- **Certified by the host: settle `bit-exact`, sample `bit-exact`, under the set of that day.** The + 13 settle cases (the one with fields of 2^40 included) and the 42 chains of the `chains` cases, + bit for bit, each answer also held to the job by `check_settle` and `check_chain`. Under the set + as it stands now, on the model, which the testbenches hold the logic to: every case the engine can + hold, 21 settle cases and 227 chains, bit for bit, and 13 cases refused as beyond it, so + `uncertified` (above). +- **Cut points and draws:** the 650 `cells` cut points the host computes equal the set's; 29 of + those cells drawn 100,000 times each on the device, every draw the reference's and every frequency + within 4 standard errors. +- **The statistical battery:** all 8 workloads pass (20,000 chains each against the exact + distribution), and the all-at-once control fails 7 of them. +- **Jobs:** 31 of 31 requests answer as the set says, refusals included. The 13 worked examples that + run, over 200 seeds each, at their own temperature and at 0, answer as the CPU reference does (26 + of 26, `agree`), and the one written to be refused is refused. 2,000 random settles up to 64 cells are the reference's; 4,096 fields read back right. +- **Joint statistics against exact enumeration** (pre-registered, `measurements/2026-11-06/ + JOINT-PREREG.txt`, seed 2027, through the sequencer): every case passes every rule. + +| case | chains | bins | chi-square p | G p | cell p | pair p | control chi-square | +|---|---|---|---|---|---|---|---| +| ring 8, fixed T = 1.5, 4 sweeps | 200,000 | 2,930 | 0.095 | 0.037 | 1.000 | 1.000 | 244,079 on 3,247 bins, p < 1e-300 | +| ring 8, the job's anneal from T = 2.5, 10 sweeps | 200,000 | 45 | 0.708 | 0.702 | 1.000 | 1.000 | 1,933,336 on 181 bins, p < 1e-300 | +| dense 6, fixed T = 4, 2 sweeps | 200,000 | 729 | 0.884 | 0.870 | 1.000 | 0.047 | 91,995 on 729 bins, p < 1e-300 | +| sparse 10, the job's anneal from T = 1.5, 8 sweeps | 400,000 | 190 | 0.346 | 0.167 | 1.000 | 0.773 | 14,139,391 on 1,531 bins, p < 1e-300 | + +Every chain's final state equals the reference's (1,000,000 of 1,000,000), so this holds the +shared kernel to its exact law on the board's own outputs. The control has the exact marginals and +independent cells: its per-cell test passes (p 1.000 in every case) while its joint test fails by +hundreds of standard errors, which is what per-cell statistics alone would miss. + +### Processor-to-logic latency (`latency`, the AXI build; the EMIO lines on the EMIO build) + +Each access timed alone with the processor's generic timer (10 ns a tick), `n` times; the median, +the 99th percentile and the largest seen (`measurements/2026-11-06/axi-final/latency-axi.txt`, +`emio-checks/latency-emio.txt`). + +| access | n | median | p99 | largest | +|---|---|---|---|---| +| EMIO register read, handshake over GPIO (EMIO build) | 5,000 | 930 ns | 940 ns | 104 µs | +| EMIO register write, handshake over GPIO (EMIO build) | 5,000 | 790 ns | 800 ns | 30.5 µs | +| a GPIO register read (the AXI link's signature) | 100,000 | 230 ns | 240 ns | 89.9 µs | +| AXI-Lite read, a link register / an engine register | 100,000 | 230 / 240 ns | 230 / 240 ns | 19.9 / 25.7 µs | +| AXI-Lite write, to its response (store, then DSB) | 100,000 | 250 ns | 380 ns | 56.8 µs | +| a guarded read, as every job access goes (signature, then read) | 100,000 | 470 ns | 470 ns | 21.5 µs | +| a write list by DMA, 1 entry, kick to done | 5,000 | 7.6 µs | 9.3 µs | 25.8 µs | +| a write list by DMA, 512 entries (one page), kick to done | 2,000 | 20.3 µs | 23.5 µs | 54.7 µs | +| a batch's results by DMA, 128 chains (one page), kick to read | 2,000 | 37.6 µs | 47.9 µs | 49.7 µs | + +Posted AXI-Lite writes, back to back with nothing between them, came to 51 ns each: one loop of +100,000 timed whole, a mean. A DMA list's entries cost (20.3 − 7.6) µs / 511, about 25 ns each, +beyond the fixed cost of a kick; whole, a 512-entry list comes to 39.7 ns an entry. + +End to end, each timed once over the whole run (the table loads: the median of 6): + +| | EMIO, register accesses | AXI, register accesses | AXI, DMA, sequencer and write-back | +|---|---|---|---| +| a full cut-point table (64 levels × 128 fields, 32,835 writes) | 29.0 ms | 17.5 ms | 3.81 ms | +| chains of 8 cells × 4 sweeps | 14.6 µs a chain (4,096) | 9.4 µs a chain (16,384) | 4.34 µs a chain (65,536; 230,000 a second) | + +Of a chain's 4.34 µs, the engine is busy for 139 clocks, 1.39 µs, by its own count (the crate's +tests hold the model to that count, and the testbenches hold the logic to the model). The +sequencer's state machine adds about 33 clocks around it (`rtl/landscape_axi.v`: 12 to write the +chain in, 18 to copy its result out, and the start). The rest is the host's lists, kicks and polls, +and the DMA's transfers. + +### Power + +Each class by run minus halt on one bitstream, the pre-registered statistic, all predictions committed +first (`measurements/2026-11-06/`). The classes ran on the EMIO build (12:39 to 14:55 UTC); the AXI +builds, with the same engine, were checked against them. + +| measurement | build | result | prediction | | +|---|---|---|---|---| +| settle, dense 64-cell recall, 12.5 M settles a second | EMIO | 162.0 ± 3.3 mW (10 passes): 13.0 nJ a settle, 0.88 pJ an accumulate | 160 (130 to 200) | within | +| sequential sampling, 64 cells, 24.9 M cell draws a second | EMIO | 11.0 ± 1.8 mW (10 passes): 0.44 ± 0.07 nJ a cell draw, within the instrument's floor, not relied on | 12 (4 to 30) | within; see the null | +| the idle loop, control and counters only | EMIO | 1.9 ± 4.0 mW (8 passes) | 4 (0 to 12) | within | +| the settle job at 50 MHz | EMIO | 80.0 ± 2.6 mW: 0.494 ± 0.019 of 100 MHz | 0.5 within 2 SE | passes | +| null, halt against halt | EMIO | 8.1 ± 1.9 mW (8 passes) | \|Δ\| < 2 SE | **fails** | +| null, repeated as pre-registered (`NULL-REPEAT.txt`) | AXI, first | −1.9 ± 2.7 mW (8 passes) | \|Δ\| < 2 SE | passes | +| known-answer vehicle (the 2026-09 design), at 08:11 UTC, before the class campaign | its own | 73.8 ± 10.3 mW (8 passes; one pass's own spread 29 mW) | 61.7 ± 6.5, within 2 combined σ | passes, weakly: 37 to 86 mW would have passed | +| settle job, the AXI build's check | AXI, first | 158.3 ± 4.4 mW (3 passes) | the EMIO result within 2 combined SE | passes | +| settle job, the final build's check | AXI, final | 166.7 ± 6.7 mW (3 passes) | the EMIO result within 2 combined SE | passes | + +The board drew about 3.14 W halted and 3.30 W running the settle job. **One of the two nulls failed** +(8.1 ± 1.9 mW, no job in either slot, and not following which slot came first), so the instrument's +floor is not shown to be below about 8 mW: the sampling and idle figures, 11 and 2 mW, are within it +and are reported, not relied on. The settle figures are twenty times that floor. The class campaign's +first attempt (08:01 UTC) measured the step and the known answer, then stopped: the session check +mistook its own parent process for another session; that is fixed (`src/board.rs`). The class +campaign itself ran without the known answer, so its own instrument checks are the null that failed +and the clock-scaling check that passed. During it a status read over SSH touched the board once, at +about 13:25 UTC, during the settle class. + +**The step response** (`emio-classes/step.dat`, 300 s each way, no settle): the level is flat from +the first 15 seconds on, 3,300 mW running and 3,140 mW halted (`step_settle.py`: every 15-sample +median within 20 mW of the final level), so the 60 s settle is enough. Single samples stray all +through both segments, the last 299 s in: spikes of the sensor or the processor, which the +statistic's medians do not follow. + + +**The first version of this design** (2026-11-05, fields of 11 bits, a 128-bit xoroshiro register for +draws of its own, 16-bit cut points; sampling `statistical`, not bit-exact) measured, with its +known-answer control at 70.4 ± 7.5 mW against 61.7 ± 6.5 expected and a null of −1.2 ± 2.3 mW +(`measurements/2026-11-05/`): + +| job | one core | four cores | +|---|---|---| +| settle, dense 64-cell recall | 146.7 ± 2.0 mW: 11.7 nJ a settle, about 0.80 pJ an accumulate | 585.8 ± 1.8 mW, 3.99 ± 0.06 times one core | +| sequential sampling, 8 sweeps at T = 0.25 | 6.7 ± 1.8 mW: 0.20 ± 0.05 nJ a cell draw | 42.1 ± 1.9 mW: 0.32 ± 0.01 nJ a cell draw, 2.0 σ from the one-core figure | + +Neither is the 0.16 pJ an accumulate of the spec's price table, which comes from a different design +with its couplings fixed in the logic. + +## What is not done, and what came out worse + +- **Bitstream reproducibility** is unchecked, and no bitstream is published (above). +- **No hardware-in-the-loop CI.** The board has a lock between jobs (`src/board.rs`) but no + networked power relay, so a runner cannot power-cycle it. +- **One board, one meter.** No second unit has repeated these numbers, and the sensor reads the whole + board, not the logic's supply. +- **Four cores fit, only on the EMIO link, and the host does not use them as four.** It addresses one + core at a time or all at once (the same job on each). The AXI link drives one engine. +- **The guard leaves a window.** The host reads the signature and then makes the AXI access, usually + under half a microsecond later; the longest gap seen was 21.5 µs, and preemption can stretch it + without bound. A reload by another session landing inside that window would still hang the board. + The lock keeps this tool's own sessions out of it; another tool's reload is not excluded. +- **The DMA's pages are locked, not pinned.** The kernel may still move a locked page (compaction and + contiguous allocation do). The host reads each page's physical address before every transfer and + again after, and refuses the transfer if it moved, but a page moved during a write-back has had its + 4 KiB written where the page used to be. A buffer the kernel owns (a reserved region, a CMA or + dma-heap buffer behind a driver) would rule this out; this host has none. +- **The port widths are the boot's.** The build assumes the processing system's master port and its + high-performance port at 128 bits, as this board's boot sets them; the host reads + both and refuses otherwise, and does not set them. Another boot image may need another build. +- **Not certified under the current set.** 64 cells, sampled fields of ±524,287 and a cost of + 1,048,575, and a window of 8,192 fields a temperature: the set now holds cases past each, which a + member may not decline, so both kernels come out `uncertified` (above). At temperature 0 large + fields are mapped exactly; more cells would need the engine to tile its cells, wider sampling + fields wider registers, and a wider spread of uncertain fields more than one window. +- **The joint test's histogram is the reference's.** The board is bit-exact, so the test holds the + shared kernel to exact enumeration on the board's outputs, not an independent sampler. +- **A cell update takes four clocks**, and in sequential mode one of 64 cones is used at a time. +- **The AXI build reports one critical warning**: a false-path constraint written for the EMIO + port's synchroniser finds no such cell in it. It constrains nothing there. +- **A rebuild is not checked against the measured one.** The build stops on a tool other than + 2026.1 and takes each block at the version it was measured with, but whether the same steps give + the same bytes is unknown. A rebuild with a different sha256 is accepted by its own checks on the + board: `conform`, `agree --seeds 200` and `joint` (seed 2027), reported with the tool version and + the sha256. + +## Files + +| | | +|---|---| +| `rtl/landscape_core.v` | the engine: cones, the T0, GIBBS and JACOBI modes, the draw pipeline, the table, counters | +| `rtl/landscape_axi.v`, `rtl/landscape_top_axi.v` | the AXI link (AXI-Lite port, write-list DMA, chain sequencer) and its top level | +| `rtl/landscape_port.v`, `rtl/landscape_top.v` | the EMIO port and its top level | +| `rtl/landscape_multi.v`, `rtl/landscape_top_multi.v` | several engines behind one EMIO port | +| `landscape.tcl`, `rtl/landscape.xdc` | the build (`LINK axi` or `emio`), and the constraints on the EMIO crossing | +| `src/` | the host: register maps, the links (`axi.rs`, `emio.rs`), driver, member, model, checks, the joint-statistics test (`exact.rs`), latency (`latency.rs`), power meter, command line | +| `tb/tb_landscape.v`, `tb/tb_landscape_axi.v` | the testbenches, for the EMIO port and for the AXI link; `scripts/run_tb.sh` runs both | +| `scripts/` | build, run-everything, power campaign, and the two analysis scripts | +| `measurements/` | each campaign's prediction and raw logs | + +Where the design came from: [PROVENANCE.md](PROVENANCE.md). diff --git a/wai/wai-quantum-landscape-fpga/landscape.tcl b/wai/wai-quantum-landscape-fpga/landscape.tcl new file mode 100644 index 000000000..d03854dbb --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/landscape.tcl @@ -0,0 +1,121 @@ +# SPDX-License-Identifier: Apache-2.0 +# Bitstream build for the energy-landscape engine. Vivado batch mode: +# vivado -mode batch -source landscape.tcl -tclargs [FREQ ] [TAG ] [JOBS ] [CORES ] [LINK emio|axi] +# The part and board are data: PART and BOARD below. There is no programmable-logic I/O: the +# processing system provides the clock and the link. LINK axi (the default on one engine) gives an +# AXI-Lite register port, a write-list DMA from DDR and an in-fabric chain sequencer +# (rtl/landscape_axi.v); LINK emio carries register accesses over the EMIO GPIO lines, and is the +# only link of the multi-core build. Every block below is the vendor's no-charge processing-system +# configuration or AXI infrastructure; no licensed IP. The tool and block versions are the ones this +# design was built and measured with, and a different tool stops the build: set ANY_TOOL to go on, +# and expect a different bitstream. +set part xck26-sfvc784-2LV-c +set board xilinx.com:kv260_som:part0:2.0 +proc arg {name dflt} { + global argv + set i [lsearch $argv $name] + if {$i >= 0 && [llength $argv] > $i + 1} { return [lindex $argv [expr {$i + 1}]] } + return $dflt +} +set freq [arg FREQ 100] +set tag [arg TAG landscape] +set jobs [arg JOBS 4] +set cores [arg CORES 1] +set link [arg LINK [expr {$cores > 1 ? "emio" : "axi"}]] +if {$cores > 1 && $link ne "emio"} { error "the multi-core build has the EMIO link only" } +set tool 2026.1 +if {[version -short] ne $tool && ![info exists ::env(ANY_TOOL)]} { + error "this design was built and measured with Vivado $tool, not [version -short]: set ANY_TOOL to build anyway" +} +# Each block by its exact version. +proc block {name version} { + set d [get_ipdefs -all xilinx.com:ip:$name:$version] + if {$d eq ""} { error "no $name $version in this tool" } + return [lindex $d 0] +} +set here [file dirname [file normalize [info script]]] +puts "BUILD: tag=$tag freq=$freq jobs=$jobs cores=$cores link=$link here=$here" +create_project ev_$tag ./ev_$tag -part $part -force +set_property board_part $board [current_project] + +create_bd_design sys +create_bd_cell -type ip -vlnv [block zynq_ultra_ps_e 3.5] ps +apply_bd_automation -rule xilinx.com:bd_rule:zynq_ultra_ps_e -config {apply_board_preset 1} [get_bd_cells ps] +set_property -dict [list \ + CONFIG.PSU__FPGA_PL0_ENABLE {1} \ + CONFIG.PSU__CRL_APB__PL0_REF_CTRL__FREQMHZ $freq \ + CONFIG.PSU__USE__M_AXI_GP0 {0} CONFIG.PSU__USE__M_AXI_GP1 {0} CONFIG.PSU__USE__M_AXI_GP2 {0} \ + CONFIG.PSU__GPIO_EMIO__PERIPHERAL__ENABLE {1} \ + CONFIG.PSU__GPIO_EMIO__PERIPHERAL__IO {95} \ +] [get_bd_cells ps] +create_bd_port -dir O -from 94 -to 0 emio_o +create_bd_port -dir I -from 94 -to 0 emio_i +connect_bd_net [get_bd_pins ps/emio_gpio_o] [get_bd_ports emio_o] +connect_bd_net [get_bd_pins ps/emio_gpio_i] [get_bd_ports emio_i] +create_bd_port -dir O -type clk pl_clk0 +connect_bd_net [get_bd_pins ps/pl_clk0] [get_bd_ports pl_clk0] +if {$link eq "axi"} { + # The two port widths are the ones this board's boot leaves set (src/axi.rs, ps_ports): loading + # a bitstream through the FPGA manager does not change them, so the design meets them as they + # are and writes no processor register. M_AXI_HPM0_FPD (128-bit) -> width converter -> protocol + # converter -> LITE (32-bit) at 0xA000_0000, 256 KiB. DMA (AXI4, 64-bit) -> width converter -> + # S_AXI_HP0_FPD (128-bit) -> DDR. The reset is the fabric's own (aresetn). + set_property -dict [list CONFIG.PSU__USE__M_AXI_GP0 {1} CONFIG.PSU__MAXIGP0__DATA_WIDTH {128} \ + CONFIG.PSU__USE__S_AXI_GP2 {1} CONFIG.PSU__SAXIGP2__DATA_WIDTH {128}] [get_bd_cells ps] + connect_bd_net [get_bd_pins ps/pl_clk0] [get_bd_pins ps/maxihpm0_fpd_aclk] + connect_bd_net [get_bd_pins ps/pl_clk0] [get_bd_pins ps/saxihp0_fpd_aclk] + create_bd_port -dir I -type rst aresetn + set dw [block axi_dwidth_converter 2.1] + create_bd_cell -type ip -vlnv $dw down + create_bd_cell -type ip -vlnv $dw up + set_property -dict [list CONFIG.SI_DATA_WIDTH {128} CONFIG.MI_DATA_WIDTH {32}] [get_bd_cells down] + set_property -dict [list CONFIG.SI_DATA_WIDTH {64} CONFIG.MI_DATA_WIDTH {128}] [get_bd_cells up] + create_bd_cell -type ip -vlnv [block axi_protocol_converter 2.1] conv + set_property -dict [list CONFIG.SI_PROTOCOL {AXI4} CONFIG.MI_PROTOCOL {AXI4LITE} CONFIG.DATA_WIDTH {32}] [get_bd_cells conv] + foreach c {down up} { + connect_bd_net [get_bd_pins ps/pl_clk0] [get_bd_pins $c/s_axi_aclk] + connect_bd_net [get_bd_ports aresetn] [get_bd_pins $c/s_axi_aresetn] + } + connect_bd_net [get_bd_pins ps/pl_clk0] [get_bd_pins conv/aclk] + connect_bd_net [get_bd_ports aresetn] [get_bd_pins conv/aresetn] + connect_bd_intf_net [get_bd_intf_pins ps/M_AXI_HPM0_FPD] [get_bd_intf_pins down/S_AXI] + connect_bd_intf_net [get_bd_intf_pins down/M_AXI] [get_bd_intf_pins conv/S_AXI] + create_bd_intf_port -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 LITE + set_property -dict [list CONFIG.PROTOCOL {AXI4LITE} CONFIG.ADDR_WIDTH {32} CONFIG.DATA_WIDTH {32}] [get_bd_intf_ports LITE] + connect_bd_intf_net [get_bd_intf_pins conv/M_AXI] [get_bd_intf_ports LITE] + create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 DMA + set_property -dict [list CONFIG.PROTOCOL {AXI4} CONFIG.ADDR_WIDTH {49} CONFIG.DATA_WIDTH {64} CONFIG.ID_WIDTH {0} \ + CONFIG.HAS_REGION {0} CONFIG.HAS_QOS {0} CONFIG.HAS_LOCK {0}] [get_bd_intf_ports DMA] + connect_bd_intf_net [get_bd_intf_ports DMA] [get_bd_intf_pins up/S_AXI] + connect_bd_intf_net [get_bd_intf_pins up/M_AXI] [get_bd_intf_pins ps/S_AXI_HP0_FPD] + set_property CONFIG.ASSOCIATED_BUSIF {LITE:DMA} [get_bd_ports pl_clk0] + set_property CONFIG.ASSOCIATED_RESET {aresetn} [get_bd_ports pl_clk0] + assign_bd_address + set lite [get_bd_addr_segs -of_objects [get_bd_addr_spaces ps/Data] -filter {NAME =~ *LITE*}] + set_property offset 0xA0000000 $lite + set_property range 256K $lite + foreach seg [get_bd_addr_segs -of_objects [get_bd_addr_spaces ps/Data]] { puts "ADDR $seg [get_property offset $seg] [get_property range $seg]" } +} +validate_bd_design +make_wrapper -files [get_files sys.bd] -top -import +generate_target all [get_files sys.bd] + +if {$cores > 1} { + add_files [list $here/rtl/landscape_top_multi.v $here/rtl/landscape_multi.v $here/rtl/landscape_core.v] + set_property verilog_define [list LANDSCAPE_K=$cores] [current_fileset] +} elseif {$link eq "axi"} { + add_files [list $here/rtl/landscape_top_axi.v $here/rtl/landscape_axi.v $here/rtl/landscape_core.v] +} else { + add_files [list $here/rtl/landscape_top.v $here/rtl/landscape_port.v $here/rtl/landscape_core.v] +} +add_files -fileset constrs_1 $here/rtl/landscape.xdc +set_property top design_top [current_fileset] +update_compile_order -fileset sources_1 + +launch_runs impl_1 -to_step write_bitstream -jobs $jobs +wait_on_run impl_1 +puts "IMPL_STATUS: [get_property STATUS [get_runs impl_1]] PROGRESS: [get_property PROGRESS [get_runs impl_1]]" +open_run impl_1 +report_utilization -file ev_$tag.util.rpt +report_timing_summary -max_paths 5 -file ev_$tag.timing.rpt +puts "BITSTREAM: [glob -nocomplain ./ev_$tag/ev_$tag.runs/impl_1/*.bit]" diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/PREDICTION.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/PREDICTION.txt new file mode 100644 index 000000000..753f5782c --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/PREDICTION.txt @@ -0,0 +1,54 @@ +PRE-REGISTERED, 2026-11-05, before the vQPU-EDGE bitstream had been loaded on the board, and before +any power was read from it. Written from the RTL, the software model's activity counts +(`vqpu-edge activity`) and the board's own earlier measurements. Not edited after the data. + +WHAT IS MEASURED +Run minus halt on ONE bitstream (kv260/edge, 100 MHz pl_clk0), whole-board INA260, by the board's +written rules: no reload between states, randomised order each pass, sampling on the board in the +measuring process with nothing else running, reload detection per point (engine uptime counter must +keep counting; dmesg FPGA-write count must not move; ID must read back), pass dropped if flagged, +statistic = mean of per-pass differences of medians, error = SE across passes. Label of every +number: board-level, this KV260, this design. It is NOT the 0.1596 pJ/accumulate of the old +constant-folded vehicle and must not be quoted as that: this lowering keeps W in flops and adds a +product LUT, a compressor and a runtime-theta comparator to every cone, so it has its own rate. + +THE INSTRUMENT CHECKS, which gate everything else + K1 known answer: the September vehicle ev_rdet.bit.bin, run/halt by its own script kv_runhalt.sh, + must reproduce 61.7 mW (its 2026-09-28 run/halt value, +/- 6.5). PASS if within 2 combined sigma. + If it fails, no number below is reported as measured. + K2 null: on the vQPU-EDGE bitstream, halt against halt (one slot labelled run): 0 mW. + PASS if |delta| < 2 SE. + +PREDICTIONS (point value, and the range outside which I am wrong) +Reasoning: the old det vehicle drew 61.7 mW at 8.68 state flips per clock, i.e. ~71 pJ per flip with +its constant-folded cones. This lowering has ~3x the LUTs per cone (product + compressor + tree + +comparators), and a flip drives all 64 cones, so I take 2.5x per flip, uncertain by 2x either way. + + class what repeats flips/clock predicted P_dyn range + t0-recall dense Hebbian n=64 (8 patterns), T=0 settle 6.88 122 mW 60..250 + from a 30%-corrupted cue, 5 steps, reload + gibbs-recall same landscape, 8 sequential Gibbs sweeps at 0.028 5 mW 0..20 + beta=4 + one T=0 step, reload (1539 clocks/job) + - cones barely move; what is left is PRNG, table + read, field mux and counters + solve-assign the 3x3 equality landscape (n=9), 39-sweep anneal ~0.1 3 mW 0..15 + from T=1, final T=0 step; 55 of the 64 cones have + W=0 and cannot switch + t0-idle W=0, bound 0: the job FSM looping with a static 0 1 mW 0..10 + datapath (control and counters only) + +Derived, for t0-recall: 12.5 M settles/s at 8 clocks each => ~10 nJ per settle; with its accumulate +count (5 steps x nnz) that is about 0.5 pJ per accumulate, range 0.25..1.0. I expect it to be WORSE +than the old 0.16 pJ/accumulate, because the couplings are now data, not wiring. + +WHAT WOULD REFUTE THE REASONING + - t0-recall outside 60..250 mW: the per-flip cost of this lowering is not 1-5x the old one. + - gibbs-recall above 20 mW: something other than state flips (the field mux, the table, the PRNG) + costs far more than the toggle study's numbers say. + - t0-idle above 10 mW: control is not negligible, and every per-job figure carries it. + +WHAT THIS RUN CANNOT RESOLVE (said now, so a null is not read as a finding) + gibbs-recall, solve-assign and t0-idle are predicted at or below the protocol's floor (paired SE + ~2-7 mW at 8-12 passes). A result consistent with 0 there means "below what one core on this + meter resolves", not "free". A second meter on the PL rail (or K replicated cores) is what would + resolve them. diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/PREDICTION_4core.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/PREDICTION_4core.txt new file mode 100644 index 000000000..9f2d588f8 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/PREDICTION_4core.txt @@ -0,0 +1,23 @@ +PRE-REGISTERED, 2026-11-05, written while the single-core campaign was still running on the board +and before any of its numbers had been read, and before the four-core bitstream was ever loaded. + +WHY. The single-core prediction put gibbs-recall at ~5 mW, at or below the paired protocol's +floor. The notes' own lesson (FEASIBILITY_parity_2026-10-04.txt): amplify the effect, don't average +the noise. rtl/edge_multi.v puts four engines behind one port; `vqpu-edge meter ... --cores 4` +runs the same job on all four at once (BroadcastPort), so the effect is ~4x while the sensor quantum +and drift stay put. + +WHAT IS MEASURED. The same run/halt protocol as the single-core campaign, on the four-core +bitstream, 100 MHz, classes t0-recall and gibbs-recall. + +PREDICTIONS + 1. Scaling: P_dyn(4 cores) / P_dyn(1 core, this day's campaign) = 4.0, PASS range 3.4 .. 4.6 for + t0-recall. Outside it, cores do not add independently (shared clock tree, placement density, + rail), and the per-core numbers from the four-core build must not be divided by four. + 2. t0-recall, four cores: 4 x 122 = 488 mW (range 240 .. 1000), i.e. four times the single-core + prediction, whatever the single-core measurement turns out to be. + 3. gibbs-recall, four cores: 4 x 5 = 20 mW (range 0 .. 80). If the single-core run could not + resolve it, this is the number that can: at 20 mW and SE ~6 mW it is ~3 sigma. + +LABEL. Board-level, this KV260, this (four-core) design. Per-core figures from it are the four-core +value divided by four only if prediction 1 passes. diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/README.md b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/README.md new file mode 100644 index 000000000..660627526 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/README.md @@ -0,0 +1,16 @@ +# 2026-11-05: the first version of the design + +Raw logs from the first version (draws of its own, 16-bit cut points, fields of 11 bits), as the +meter wrote them, under that version's tool name. `PREDICTION.txt` and `PREDICTION_4core.txt` are the +predictions committed before each measurement, copied unchanged. + +| file | what | +|---|---| +| `step.dat` | the run/halt step response, 300 s each way | +| `k1_rdet.dat` | the known-answer vehicle (an earlier design measured in September at 61.7 ± 6.5 mW), by its own script | +| `null.dat` | halt against halt | +| `t0-recall.dat`, `t0-recall-50MHz.dat` | the settle job at 100 and 50 MHz | +| `gibbs-recall.dat`, `t0-idle.dat`, `solve-assign.dat` | the sampling job, the idle loop, a small annealing job | +| `t0-recall-4core.dat`, `gibbs-recall-4core.dat` | the same jobs on four cores at once | + +Summarise any of them with `wai-quantum-landscape-fpga analyze ` or `python3 scripts/power_tables.py `. diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/gibbs-recall-4core.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/gibbs-recall-4core.dat new file mode 100644 index 000000000..fab79f478 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/gibbs-recall-4core.dat @@ -0,0 +1,754 @@ +# class gibbs-recall cores 4 +# vqpu-edge meter passes=12 settle=60s samples=30 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793922349, tv_nsec: 240818196 } +# pass state sample power_uW +1 run 1 3290000 +1 run 2 3540000 +1 run 3 3290000 +1 run 4 3310000 +1 run 5 3300000 +1 run 6 3280000 +1 run 7 3700000 +1 run 8 3290000 +1 run 9 3280000 +1 run 10 3290000 +1 run 11 3280000 +1 run 12 3280000 +1 run 13 3300000 +1 run 14 3280000 +1 run 15 3280000 +1 run 16 3280000 +1 run 17 3280000 +1 run 18 3290000 +1 run 19 3280000 +1 run 20 3270000 +1 run 21 3280000 +1 run 22 3290000 +1 run 23 3290000 +1 run 24 3290000 +1 run 25 3280000 +1 run 26 3280000 +1 run 27 3290000 +1 run 28 3290000 +1 run 29 3280000 +1 run 30 3290000 +# point pass=1 state=run jobs_per_s=64976.0 updates_per_s=33267709.4 clock_hz=99998038 +1 halt 1 3260000 +1 halt 2 3240000 +1 halt 3 3240000 +1 halt 4 3250000 +1 halt 5 3240000 +1 halt 6 3240000 +1 halt 7 3250000 +1 halt 8 3250000 +1 halt 9 3240000 +1 halt 10 3240000 +1 halt 11 3240000 +1 halt 12 3240000 +1 halt 13 3240000 +1 halt 14 3240000 +1 halt 15 3240000 +1 halt 16 3250000 +1 halt 17 3240000 +1 halt 18 3240000 +1 halt 19 3240000 +1 halt 20 3240000 +1 halt 21 3250000 +1 halt 22 3240000 +1 halt 23 3240000 +1 halt 24 3260000 +1 halt 25 3260000 +1 halt 26 3240000 +1 halt 27 3240000 +1 halt 28 3260000 +1 halt 29 3240000 +1 halt 30 3240000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998032 +2 run 1 3290000 +2 run 2 3290000 +2 run 3 3290000 +2 run 4 3280000 +2 run 5 3280000 +2 run 6 3270000 +2 run 7 3270000 +2 run 8 3290000 +2 run 9 3280000 +2 run 10 3280000 +2 run 11 3280000 +2 run 12 3280000 +2 run 13 3300000 +2 run 14 3280000 +2 run 15 3280000 +2 run 16 3280000 +2 run 17 3290000 +2 run 18 3280000 +2 run 19 3280000 +2 run 20 3280000 +2 run 21 3290000 +2 run 22 3290000 +2 run 23 3280000 +2 run 24 3270000 +2 run 25 3280000 +2 run 26 3280000 +2 run 27 3280000 +2 run 28 3270000 +2 run 29 3270000 +2 run 30 3280000 +# point pass=2 state=run jobs_per_s=64976.0 updates_per_s=33267706.0 clock_hz=99998028 +2 halt 1 3250000 +2 halt 2 3240000 +2 halt 3 3240000 +2 halt 4 3240000 +2 halt 5 3240000 +2 halt 6 3240000 +2 halt 7 3240000 +2 halt 8 3240000 +2 halt 9 3260000 +2 halt 10 3260000 +2 halt 11 3240000 +2 halt 12 3240000 +2 halt 13 3260000 +2 halt 14 3240000 +2 halt 15 3250000 +2 halt 16 3250000 +2 halt 17 3240000 +2 halt 18 3250000 +2 halt 19 3240000 +2 halt 20 3240000 +2 halt 21 3240000 +2 halt 22 3240000 +2 halt 23 3240000 +2 halt 24 3240000 +2 halt 25 3240000 +2 halt 26 3250000 +2 halt 27 3240000 +2 halt 28 3240000 +2 halt 29 3240000 +2 halt 30 3240000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998024 +3 run 1 3290000 +3 run 2 3280000 +3 run 3 3280000 +3 run 4 3280000 +3 run 5 3290000 +3 run 6 3300000 +3 run 7 3290000 +3 run 8 3290000 +3 run 9 3290000 +3 run 10 3290000 +3 run 11 3290000 +3 run 12 3280000 +3 run 13 3300000 +3 run 14 3290000 +3 run 15 3310000 +3 run 16 3290000 +3 run 17 3290000 +3 run 18 3290000 +3 run 19 3290000 +3 run 20 3290000 +3 run 21 3290000 +3 run 22 3290000 +3 run 23 3280000 +3 run 24 3280000 +3 run 25 3300000 +3 run 26 3290000 +3 run 27 3290000 +3 run 28 3290000 +3 run 29 3290000 +3 run 30 3300000 +# point pass=3 state=run jobs_per_s=64976.0 updates_per_s=33267703.0 clock_hz=99998019 +3 halt 1 3250000 +3 halt 2 3260000 +3 halt 3 3270000 +3 halt 4 3260000 +3 halt 5 3270000 +3 halt 6 3260000 +3 halt 7 3250000 +3 halt 8 3250000 +3 halt 9 3260000 +3 halt 10 3250000 +3 halt 11 3250000 +3 halt 12 3250000 +3 halt 13 3250000 +3 halt 14 3250000 +3 halt 15 3250000 +3 halt 16 3250000 +3 halt 17 3250000 +3 halt 18 3270000 +3 halt 19 3260000 +3 halt 20 3250000 +3 halt 21 3240000 +3 halt 22 3250000 +3 halt 23 3250000 +3 halt 24 3250000 +3 halt 25 3250000 +3 halt 26 3280000 +3 halt 27 3270000 +3 halt 28 3240000 +3 halt 29 3250000 +3 halt 30 3250000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998016 +4 halt 1 3250000 +4 halt 2 3260000 +4 halt 3 3260000 +4 halt 4 3250000 +4 halt 5 3250000 +4 halt 6 3250000 +4 halt 7 3280000 +4 halt 8 3250000 +4 halt 9 3260000 +4 halt 10 3270000 +4 halt 11 3280000 +4 halt 12 3260000 +4 halt 13 3250000 +4 halt 14 3260000 +4 halt 15 3250000 +4 halt 16 3250000 +4 halt 17 3250000 +4 halt 18 3260000 +4 halt 19 3270000 +4 halt 20 3260000 +4 halt 21 3250000 +4 halt 22 3250000 +4 halt 23 3280000 +4 halt 24 3260000 +4 halt 25 3250000 +4 halt 26 3250000 +4 halt 27 3250000 +4 halt 28 3250000 +4 halt 29 3250000 +4 halt 30 3270000 +# point pass=4 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998014 +4 run 1 3290000 +4 run 2 3290000 +4 run 3 3280000 +4 run 4 3280000 +4 run 5 3300000 +4 run 6 3280000 +4 run 7 3290000 +4 run 8 3280000 +4 run 9 3290000 +4 run 10 3290000 +4 run 11 3290000 +4 run 12 3280000 +4 run 13 3280000 +4 run 14 3280000 +4 run 15 3290000 +4 run 16 3290000 +4 run 17 3290000 +4 run 18 3280000 +4 run 19 3290000 +4 run 20 3300000 +4 run 21 3280000 +4 run 22 3290000 +4 run 23 3280000 +4 run 24 3290000 +4 run 25 3280000 +4 run 26 3290000 +4 run 27 3280000 +4 run 28 3300000 +4 run 29 3290000 +4 run 30 3300000 +# point pass=4 state=run jobs_per_s=64976.0 updates_per_s=33267700.6 clock_hz=99998011 +5 halt 1 3250000 +5 halt 2 3250000 +5 halt 3 3250000 +5 halt 4 3240000 +5 halt 5 3240000 +5 halt 6 3250000 +5 halt 7 3250000 +5 halt 8 3260000 +5 halt 9 3250000 +5 halt 10 3240000 +5 halt 11 3240000 +5 halt 12 3250000 +5 halt 13 3240000 +5 halt 14 3250000 +5 halt 15 3250000 +5 halt 16 3260000 +5 halt 17 3260000 +5 halt 18 3250000 +5 halt 19 3250000 +5 halt 20 3240000 +5 halt 21 3240000 +5 halt 22 3240000 +5 halt 23 3250000 +5 halt 24 3240000 +5 halt 25 3260000 +5 halt 26 3240000 +5 halt 27 3250000 +5 halt 28 3250000 +5 halt 29 3250000 +5 halt 30 3240000 +# point pass=5 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998011 +5 run 1 3280000 +5 run 2 3300000 +5 run 3 3290000 +5 run 4 3290000 +5 run 5 3340000 +5 run 6 3320000 +5 run 7 3290000 +5 run 8 3290000 +5 run 9 3290000 +5 run 10 3290000 +5 run 11 3290000 +5 run 12 3290000 +5 run 13 3320000 +5 run 14 3300000 +5 run 15 3290000 +5 run 16 3290000 +5 run 17 3290000 +5 run 18 3280000 +5 run 19 3290000 +5 run 20 3300000 +5 run 21 3290000 +5 run 22 3290000 +5 run 23 3320000 +5 run 24 3290000 +5 run 25 3290000 +5 run 26 3290000 +5 run 27 3290000 +5 run 28 3300000 +5 run 29 3280000 +5 run 30 3290000 +# point pass=5 state=run jobs_per_s=64976.0 updates_per_s=33267699.6 clock_hz=99998008 +6 run 1 3300000 +6 run 2 3300000 +6 run 3 3290000 +6 run 4 3290000 +6 run 5 3280000 +6 run 6 3280000 +6 run 7 3280000 +6 run 8 3280000 +6 run 9 3280000 +6 run 10 3300000 +6 run 11 3280000 +6 run 12 3280000 +6 run 13 3280000 +6 run 14 3280000 +6 run 15 3280000 +6 run 16 3280000 +6 run 17 3280000 +6 run 18 3280000 +6 run 19 3290000 +6 run 20 3280000 +6 run 21 3280000 +6 run 22 3290000 +6 run 23 3280000 +6 run 24 3290000 +6 run 25 3310000 +6 run 26 3290000 +6 run 27 3290000 +6 run 28 3290000 +6 run 29 3280000 +6 run 30 3280000 +# point pass=6 state=run jobs_per_s=64976.0 updates_per_s=33267699.2 clock_hz=99998007 +6 halt 1 3230000 +6 halt 2 3240000 +6 halt 3 3240000 +6 halt 4 3250000 +6 halt 5 3240000 +6 halt 6 3240000 +6 halt 7 3250000 +6 halt 8 3240000 +6 halt 9 3240000 +6 halt 10 3250000 +6 halt 11 3250000 +6 halt 12 3250000 +6 halt 13 3240000 +6 halt 14 3240000 +6 halt 15 3340000 +6 halt 16 3250000 +6 halt 17 3240000 +6 halt 18 3240000 +6 halt 19 3250000 +6 halt 20 3580000 +6 halt 21 3250000 +6 halt 22 3260000 +6 halt 23 3240000 +6 halt 24 3250000 +6 halt 25 3240000 +6 halt 26 3240000 +6 halt 27 3240000 +6 halt 28 3250000 +6 halt 29 3240000 +6 halt 30 3250000 +# point pass=6 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998006 +7 halt 1 3250000 +7 halt 2 3240000 +7 halt 3 3240000 +7 halt 4 3250000 +7 halt 5 3240000 +7 halt 6 3240000 +7 halt 7 3240000 +7 halt 8 3240000 +7 halt 9 3240000 +7 halt 10 3250000 +7 halt 11 3240000 +7 halt 12 3250000 +7 halt 13 3690000 +7 halt 14 3240000 +7 halt 15 3240000 +7 halt 16 3250000 +7 halt 17 3250000 +7 halt 18 3260000 +7 halt 19 3260000 +7 halt 20 3240000 +7 halt 21 3240000 +7 halt 22 3250000 +7 halt 23 3240000 +7 halt 24 3240000 +7 halt 25 3240000 +7 halt 26 3240000 +7 halt 27 3240000 +7 halt 28 3240000 +7 halt 29 3260000 +7 halt 30 3240000 +# point pass=7 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997761 +7 run 1 3290000 +7 run 2 3280000 +7 run 3 3280000 +7 run 4 3290000 +7 run 5 3280000 +7 run 6 3280000 +7 run 7 3290000 +7 run 8 3280000 +7 run 9 3280000 +7 run 10 3290000 +7 run 11 3280000 +7 run 12 3280000 +7 run 13 3290000 +7 run 14 3290000 +7 run 15 3290000 +7 run 16 3290000 +7 run 17 3290000 +7 run 18 3300000 +7 run 19 3300000 +7 run 20 3290000 +7 run 21 3290000 +7 run 22 3280000 +7 run 23 3280000 +7 run 24 3290000 +7 run 25 3280000 +7 run 26 3280000 +7 run 27 3290000 +7 run 28 3280000 +7 run 29 3280000 +7 run 30 3290000 +# point pass=7 state=run jobs_per_s=64975.8 updates_per_s=33267628.3 clock_hz=99997794 +8 run 1 3280000 +8 run 2 3290000 +8 run 3 3280000 +8 run 4 3280000 +8 run 5 3280000 +8 run 6 3280000 +8 run 7 3300000 +8 run 8 3280000 +8 run 9 3290000 +8 run 10 3280000 +8 run 11 3320000 +8 run 12 3290000 +8 run 13 3290000 +8 run 14 3280000 +8 run 15 3310000 +8 run 16 3290000 +8 run 17 3280000 +8 run 18 3270000 +8 run 19 3290000 +8 run 20 3290000 +8 run 21 3270000 +8 run 22 3290000 +8 run 23 3280000 +8 run 24 3290000 +8 run 25 3280000 +8 run 26 3280000 +8 run 27 3290000 +8 run 28 3280000 +8 run 29 3290000 +8 run 30 3310000 +# point pass=8 state=run jobs_per_s=64975.8 updates_per_s=33267638.1 clock_hz=99997823 +8 halt 1 3250000 +8 halt 2 3240000 +8 halt 3 3260000 +8 halt 4 3260000 +8 halt 5 3240000 +8 halt 6 3240000 +8 halt 7 3240000 +8 halt 8 3250000 +8 halt 9 3240000 +8 halt 10 3240000 +8 halt 11 3250000 +8 halt 12 3260000 +8 halt 13 3240000 +8 halt 14 3250000 +8 halt 15 3230000 +8 halt 16 3240000 +8 halt 17 3250000 +8 halt 18 3250000 +8 halt 19 3250000 +8 halt 20 3250000 +8 halt 21 3240000 +8 halt 22 3260000 +8 halt 23 3250000 +8 halt 24 3240000 +8 halt 25 3250000 +8 halt 26 3240000 +8 halt 27 3260000 +8 halt 28 3250000 +8 halt 29 3250000 +8 halt 30 3250000 +# point pass=8 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997846 +9 halt 1 3250000 +9 halt 2 3240000 +9 halt 3 3240000 +9 halt 4 3250000 +9 halt 5 3240000 +9 halt 6 3250000 +9 halt 7 3250000 +9 halt 8 3240000 +9 halt 9 3240000 +9 halt 10 3240000 +9 halt 11 3250000 +9 halt 12 3240000 +9 halt 13 3240000 +9 halt 14 3250000 +9 halt 15 3250000 +9 halt 16 3240000 +9 halt 17 3240000 +9 halt 18 3240000 +9 halt 19 3240000 +9 halt 20 3240000 +9 halt 21 3240000 +9 halt 22 3240000 +9 halt 23 3250000 +9 halt 24 3260000 +9 halt 25 3240000 +9 halt 26 3240000 +9 halt 27 3240000 +9 halt 28 3240000 +9 halt 29 3240000 +9 halt 30 3240000 +# point pass=9 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997867 +9 run 1 3280000 +9 run 2 3290000 +9 run 3 3290000 +9 run 4 3290000 +9 run 5 3290000 +9 run 6 3300000 +9 run 7 3290000 +9 run 8 3290000 +9 run 9 3290000 +9 run 10 3290000 +9 run 11 3290000 +9 run 12 3310000 +9 run 13 3290000 +9 run 14 3290000 +9 run 15 3290000 +9 run 16 3290000 +9 run 17 3290000 +9 run 18 3280000 +9 run 19 3300000 +9 run 20 3310000 +9 run 21 3300000 +9 run 22 3290000 +9 run 23 3280000 +9 run 24 3290000 +9 run 25 3280000 +9 run 26 3290000 +9 run 27 3290000 +9 run 28 3290000 +9 run 29 3300000 +9 run 30 3290000 +# point pass=9 state=run jobs_per_s=64975.9 updates_per_s=33267658.0 clock_hz=99997883 +10 halt 1 3250000 +10 halt 2 3250000 +10 halt 3 3250000 +10 halt 4 3240000 +10 halt 5 3250000 +10 halt 6 3240000 +10 halt 7 3240000 +10 halt 8 3250000 +10 halt 9 3260000 +10 halt 10 3240000 +10 halt 11 3260000 +10 halt 12 3250000 +10 halt 13 3240000 +10 halt 14 3240000 +10 halt 15 3240000 +10 halt 16 3250000 +10 halt 17 3250000 +10 halt 18 3240000 +10 halt 19 3250000 +10 halt 20 3250000 +10 halt 21 3240000 +10 halt 22 3240000 +10 halt 23 3240000 +10 halt 24 3250000 +10 halt 25 3230000 +10 halt 26 3230000 +10 halt 27 3240000 +10 halt 28 3240000 +10 halt 29 3240000 +10 halt 30 3240000 +# point pass=10 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997898 +10 run 1 3280000 +10 run 2 3280000 +10 run 3 3290000 +10 run 4 3270000 +10 run 5 3280000 +10 run 6 3290000 +10 run 7 3290000 +10 run 8 3290000 +10 run 9 3290000 +10 run 10 3290000 +10 run 11 3290000 +10 run 12 3290000 +10 run 13 3290000 +10 run 14 3290000 +10 run 15 3290000 +10 run 16 3300000 +10 run 17 3290000 +10 run 18 3290000 +10 run 19 3290000 +10 run 20 3310000 +10 run 21 3290000 +10 run 22 3280000 +10 run 23 3290000 +10 run 24 3290000 +10 run 25 3290000 +10 run 26 3280000 +10 run 27 3300000 +10 run 28 3290000 +10 run 29 3290000 +10 run 30 3290000 +# point pass=10 state=run jobs_per_s=64975.9 updates_per_s=33267667.1 clock_hz=99997910 +11 run 1 3290000 +11 run 2 3290000 +11 run 3 3300000 +11 run 4 3280000 +11 run 5 3280000 +11 run 6 3280000 +11 run 7 3280000 +11 run 8 3290000 +11 run 9 3290000 +11 run 10 3280000 +11 run 11 3310000 +11 run 12 3280000 +11 run 13 3290000 +11 run 14 3280000 +11 run 15 3280000 +11 run 16 3290000 +11 run 17 3280000 +11 run 18 3280000 +11 run 19 3280000 +11 run 20 3280000 +11 run 21 3290000 +11 run 22 3280000 +11 run 23 3280000 +11 run 24 3280000 +11 run 25 3290000 +11 run 26 3290000 +11 run 27 3280000 +11 run 28 3280000 +11 run 29 3280000 +11 run 30 3290000 +# point pass=11 state=run jobs_per_s=64975.9 updates_per_s=33267670.1 clock_hz=99997920 +11 halt 1 3240000 +11 halt 2 3240000 +11 halt 3 3250000 +11 halt 4 3240000 +11 halt 5 3240000 +11 halt 6 3240000 +11 halt 7 3230000 +11 halt 8 3270000 +11 halt 9 3250000 +11 halt 10 3250000 +11 halt 11 3250000 +11 halt 12 3250000 +11 halt 13 3250000 +11 halt 14 3240000 +11 halt 15 3240000 +11 halt 16 3240000 +11 halt 17 3250000 +11 halt 18 3250000 +11 halt 19 3240000 +11 halt 20 3250000 +11 halt 21 3240000 +11 halt 22 3250000 +11 halt 23 3260000 +11 halt 24 3240000 +11 halt 25 3240000 +11 halt 26 3250000 +11 halt 27 3240000 +11 halt 28 3240000 +11 halt 29 3240000 +11 halt 30 3250000 +# point pass=11 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997928 +12 halt 1 3250000 +12 halt 2 3260000 +12 halt 3 3260000 +12 halt 4 3250000 +12 halt 5 3250000 +12 halt 6 3250000 +12 halt 7 3250000 +12 halt 8 3250000 +12 halt 9 3280000 +12 halt 10 3250000 +12 halt 11 3260000 +12 halt 12 3250000 +12 halt 13 3260000 +12 halt 14 3260000 +12 halt 15 3250000 +12 halt 16 3250000 +12 halt 17 3280000 +12 halt 18 3270000 +12 halt 19 3260000 +12 halt 20 3260000 +12 halt 21 3250000 +12 halt 22 3250000 +12 halt 23 3270000 +12 halt 24 3250000 +12 halt 25 3250000 +12 halt 26 3280000 +12 halt 27 3250000 +12 halt 28 3250000 +12 halt 29 3260000 +12 halt 30 3260000 +# point pass=12 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997935 +12 run 1 3280000 +12 run 2 3290000 +12 run 3 3280000 +12 run 4 3280000 +12 run 5 3280000 +12 run 6 3300000 +12 run 7 3280000 +12 run 8 3290000 +12 run 9 3280000 +12 run 10 3280000 +12 run 11 3290000 +12 run 12 3290000 +12 run 13 3280000 +12 run 14 3300000 +12 run 15 3280000 +12 run 16 3280000 +12 run 17 3290000 +12 run 18 3280000 +12 run 19 3280000 +12 run 20 3280000 +12 run 21 3290000 +12 run 22 3290000 +12 run 23 3280000 +12 run 24 3280000 +12 run 25 3280000 +12 run 26 3290000 +12 run 27 3290000 +12 run 28 3280000 +12 run 29 3300000 +12 run 30 3280000 +# point pass=12 state=run jobs_per_s=64975.9 updates_per_s=33267677.2 clock_hz=99997941 +# done SystemTime { tv_sec: 1793924510, tv_nsec: 651905562 } +# passes used 12 of 12 (dropped: []) +# run - halt = 42.1 +/- 1.9 mW (per-pass sd 6.6); 12/12 passes positive; 7 sample excursions beyond 6 MAD +# per-pass differences (mW): 50.0 40.0 40.0 40.0 40.0 40.0 50.0 35.0 50.0 50.0 40.0 30.0 +# board power while running 3286 mW; jobs/s 64975.9; updates/s 33267679.7; measured PL clock 99.998 MHz +# pre-registered prediction 20.0 mW: measured/predicted = 2.10, 11.7 sigma from it +# jobs/s and updates/s above are core 0's; all 4 cores run the same job diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/gibbs-recall.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/gibbs-recall.dat new file mode 100644 index 000000000..71ef4dbc3 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/gibbs-recall.dat @@ -0,0 +1,753 @@ +# class gibbs-recall +# vqpu-edge meter passes=12 settle=60s samples=30 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793913111, tv_nsec: 946190018 } +# pass state sample power_uW +1 run 1 3120000 +1 run 2 3110000 +1 run 3 3120000 +1 run 4 3100000 +1 run 5 3110000 +1 run 6 3120000 +1 run 7 3110000 +1 run 8 3110000 +1 run 9 3110000 +1 run 10 3110000 +1 run 11 3110000 +1 run 12 3120000 +1 run 13 3110000 +1 run 14 3110000 +1 run 15 3110000 +1 run 16 3120000 +1 run 17 3120000 +1 run 18 3140000 +1 run 19 3120000 +1 run 20 3110000 +1 run 21 3120000 +1 run 22 3130000 +1 run 23 3130000 +1 run 24 3120000 +1 run 25 3120000 +1 run 26 3140000 +1 run 27 3120000 +1 run 28 3110000 +1 run 29 3120000 +1 run 30 3130000 +# point pass=1 state=run jobs_per_s=64975.9 updates_per_s=33267684.8 clock_hz=99997963 +1 halt 1 3120000 +1 halt 2 3110000 +1 halt 3 3110000 +1 halt 4 3100000 +1 halt 5 3100000 +1 halt 6 3130000 +1 halt 7 3110000 +1 halt 8 3100000 +1 halt 9 3110000 +1 halt 10 3110000 +1 halt 11 3490000 +1 halt 12 3110000 +1 halt 13 3110000 +1 halt 14 3120000 +1 halt 15 3130000 +1 halt 16 3100000 +1 halt 17 3110000 +1 halt 18 3100000 +1 halt 19 3110000 +1 halt 20 3100000 +1 halt 21 3100000 +1 halt 22 3110000 +1 halt 23 3110000 +1 halt 24 3100000 +1 halt 25 3110000 +1 halt 26 3100000 +1 halt 27 3100000 +1 halt 28 3100000 +1 halt 29 3100000 +1 halt 30 3100000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997942 +2 run 1 3130000 +2 run 2 3110000 +2 run 3 3140000 +2 run 4 3130000 +2 run 5 3120000 +2 run 6 3120000 +2 run 7 3120000 +2 run 8 3120000 +2 run 9 3120000 +2 run 10 3120000 +2 run 11 3130000 +2 run 12 3140000 +2 run 13 3120000 +2 run 14 3120000 +2 run 15 3110000 +2 run 16 3120000 +2 run 17 3120000 +2 run 18 3110000 +2 run 19 3120000 +2 run 20 3130000 +2 run 21 3120000 +2 run 22 3110000 +2 run 23 3120000 +2 run 24 3120000 +2 run 25 3150000 +2 run 26 3120000 +2 run 27 3120000 +2 run 28 3120000 +2 run 29 3110000 +2 run 30 3110000 +# point pass=2 state=run jobs_per_s=64975.9 updates_per_s=33267678.8 clock_hz=99997946 +2 halt 1 3120000 +2 halt 2 3120000 +2 halt 3 3100000 +2 halt 4 3110000 +2 halt 5 3110000 +2 halt 6 3120000 +2 halt 7 3110000 +2 halt 8 3140000 +2 halt 9 3120000 +2 halt 10 3100000 +2 halt 11 3110000 +2 halt 12 3110000 +2 halt 13 3110000 +2 halt 14 3110000 +2 halt 15 3110000 +2 halt 16 3110000 +2 halt 17 3110000 +2 halt 18 3110000 +2 halt 19 3110000 +2 halt 20 3110000 +2 halt 21 3110000 +2 halt 22 3110000 +2 halt 23 3120000 +2 halt 24 3120000 +2 halt 25 3110000 +2 halt 26 3100000 +2 halt 27 3100000 +2 halt 28 3110000 +2 halt 29 3120000 +2 halt 30 3110000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997947 +3 halt 1 3110000 +3 halt 2 3110000 +3 halt 3 3120000 +3 halt 4 3110000 +3 halt 5 3120000 +3 halt 6 3110000 +3 halt 7 3110000 +3 halt 8 3110000 +3 halt 9 3110000 +3 halt 10 3110000 +3 halt 11 3120000 +3 halt 12 3110000 +3 halt 13 3110000 +3 halt 14 3110000 +3 halt 15 3110000 +3 halt 16 3110000 +3 halt 17 3100000 +3 halt 18 3110000 +3 halt 19 3110000 +3 halt 20 3130000 +3 halt 21 3110000 +3 halt 22 3110000 +3 halt 23 3110000 +3 halt 24 3110000 +3 halt 25 3110000 +3 halt 26 3110000 +3 halt 27 3110000 +3 halt 28 3120000 +3 halt 29 3130000 +3 halt 30 3100000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997949 +3 run 1 3110000 +3 run 2 3120000 +3 run 3 3120000 +3 run 4 3120000 +3 run 5 3120000 +3 run 6 3110000 +3 run 7 3110000 +3 run 8 3120000 +3 run 9 3110000 +3 run 10 3120000 +3 run 11 3110000 +3 run 12 3110000 +3 run 13 3120000 +3 run 14 3110000 +3 run 15 3110000 +3 run 16 3130000 +3 run 17 3140000 +3 run 18 3120000 +3 run 19 3110000 +3 run 20 3110000 +3 run 21 3100000 +3 run 22 3120000 +3 run 23 3110000 +3 run 24 3120000 +3 run 25 3140000 +3 run 26 3110000 +3 run 27 3110000 +3 run 28 3120000 +3 run 29 3120000 +3 run 30 3100000 +# point pass=3 state=run jobs_per_s=64976.0 updates_per_s=33267680.8 clock_hz=99997951 +4 halt 1 3110000 +4 halt 2 3110000 +4 halt 3 3110000 +4 halt 4 3100000 +4 halt 5 3130000 +4 halt 6 3110000 +4 halt 7 3110000 +4 halt 8 3120000 +4 halt 9 3110000 +4 halt 10 3110000 +4 halt 11 3120000 +4 halt 12 3110000 +4 halt 13 3110000 +4 halt 14 3130000 +4 halt 15 3110000 +4 halt 16 3110000 +4 halt 17 3110000 +4 halt 18 3140000 +4 halt 19 3110000 +4 halt 20 3110000 +4 halt 21 3100000 +4 halt 22 3120000 +4 halt 23 3110000 +4 halt 24 3110000 +4 halt 25 3110000 +4 halt 26 3110000 +4 halt 27 3110000 +4 halt 28 3110000 +4 halt 29 3110000 +4 halt 30 3110000 +# point pass=4 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997953 +4 run 1 3110000 +4 run 2 3140000 +4 run 3 3130000 +4 run 4 3130000 +4 run 5 3110000 +4 run 6 3110000 +4 run 7 3110000 +4 run 8 3110000 +4 run 9 3110000 +4 run 10 3140000 +4 run 11 3120000 +4 run 12 3110000 +4 run 13 3120000 +4 run 14 3110000 +4 run 15 3110000 +4 run 16 3110000 +4 run 17 3110000 +4 run 18 3110000 +4 run 19 3110000 +4 run 20 3110000 +4 run 21 3120000 +4 run 22 3100000 +4 run 23 3110000 +4 run 24 3120000 +4 run 25 3120000 +4 run 26 3100000 +4 run 27 3110000 +4 run 28 3120000 +4 run 29 3120000 +4 run 30 3110000 +# point pass=4 state=run jobs_per_s=64976.0 updates_per_s=33267681.8 clock_hz=99997954 +5 halt 1 3110000 +5 halt 2 3110000 +5 halt 3 3110000 +5 halt 4 3110000 +5 halt 5 3120000 +5 halt 6 3120000 +5 halt 7 3130000 +5 halt 8 3110000 +5 halt 9 3120000 +5 halt 10 3110000 +5 halt 11 3110000 +5 halt 12 3110000 +5 halt 13 3110000 +5 halt 14 3120000 +5 halt 15 3110000 +5 halt 16 3120000 +5 halt 17 3110000 +5 halt 18 3120000 +5 halt 19 3110000 +5 halt 20 3110000 +5 halt 21 3120000 +5 halt 22 3130000 +5 halt 23 3120000 +5 halt 24 3110000 +5 halt 25 3110000 +5 halt 26 3110000 +5 halt 27 3110000 +5 halt 28 3120000 +5 halt 29 3120000 +5 halt 30 3130000 +# point pass=5 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997955 +5 run 1 3110000 +5 run 2 3110000 +5 run 3 3110000 +5 run 4 3130000 +5 run 5 3110000 +5 run 6 3110000 +5 run 7 3110000 +5 run 8 3110000 +5 run 9 3270000 +5 run 10 3100000 +5 run 11 3110000 +5 run 12 3110000 +5 run 13 3110000 +5 run 14 3110000 +5 run 15 3110000 +5 run 16 3110000 +5 run 17 3110000 +5 run 18 3110000 +5 run 19 3120000 +5 run 20 3110000 +5 run 21 3100000 +5 run 22 3120000 +5 run 23 3120000 +5 run 24 3100000 +5 run 25 3100000 +5 run 26 3120000 +5 run 27 3120000 +5 run 28 3110000 +5 run 29 3110000 +5 run 30 3120000 +# point pass=5 state=run jobs_per_s=64975.9 updates_per_s=33267682.4 clock_hz=99997956 +6 run 1 3120000 +6 run 2 3120000 +6 run 3 3110000 +6 run 4 3140000 +6 run 5 3120000 +6 run 6 3130000 +6 run 7 3140000 +6 run 8 3120000 +6 run 9 3120000 +6 run 10 3120000 +6 run 11 3120000 +6 run 12 3140000 +6 run 13 3120000 +6 run 14 3120000 +6 run 15 3150000 +6 run 16 3140000 +6 run 17 3130000 +6 run 18 3130000 +6 run 19 3120000 +6 run 20 3120000 +6 run 21 3120000 +6 run 22 3130000 +6 run 23 3120000 +6 run 24 3130000 +6 run 25 3120000 +6 run 26 3120000 +6 run 27 3110000 +6 run 28 3110000 +6 run 29 3120000 +6 run 30 3120000 +# point pass=6 state=run jobs_per_s=64976.0 updates_per_s=33267682.5 clock_hz=99997957 +6 halt 1 3110000 +6 halt 2 3120000 +6 halt 3 3110000 +6 halt 4 3130000 +6 halt 5 3140000 +6 halt 6 3120000 +6 halt 7 3110000 +6 halt 8 3110000 +6 halt 9 3120000 +6 halt 10 3120000 +6 halt 11 3120000 +6 halt 12 3110000 +6 halt 13 3140000 +6 halt 14 3110000 +6 halt 15 3120000 +6 halt 16 3110000 +6 halt 17 3110000 +6 halt 18 3100000 +6 halt 19 3110000 +6 halt 20 3110000 +6 halt 21 3100000 +6 halt 22 3100000 +6 halt 23 3110000 +6 halt 24 3110000 +6 halt 25 3110000 +6 halt 26 3110000 +6 halt 27 3100000 +6 halt 28 3120000 +6 halt 29 3110000 +6 halt 30 3110000 +# point pass=6 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997957 +7 run 1 3140000 +7 run 2 3130000 +7 run 3 3120000 +7 run 4 3120000 +7 run 5 3120000 +7 run 6 3130000 +7 run 7 3130000 +7 run 8 3110000 +7 run 9 3110000 +7 run 10 3120000 +7 run 11 3110000 +7 run 12 3110000 +7 run 13 3110000 +7 run 14 3120000 +7 run 15 3110000 +7 run 16 3110000 +7 run 17 3110000 +7 run 18 3120000 +7 run 19 3450000 +7 run 20 3110000 +7 run 21 3110000 +7 run 22 3120000 +7 run 23 3110000 +7 run 24 3170000 +7 run 25 3140000 +7 run 26 3120000 +7 run 27 3110000 +7 run 28 3120000 +7 run 29 3110000 +7 run 30 3120000 +# point pass=7 state=run jobs_per_s=64976.0 updates_per_s=33267683.0 clock_hz=99997958 +7 halt 1 3120000 +7 halt 2 3110000 +7 halt 3 3110000 +7 halt 4 3120000 +7 halt 5 3110000 +7 halt 6 3130000 +7 halt 7 3110000 +7 halt 8 3110000 +7 halt 9 3110000 +7 halt 10 3110000 +7 halt 11 3110000 +7 halt 12 3120000 +7 halt 13 3150000 +7 halt 14 3120000 +7 halt 15 3120000 +7 halt 16 3120000 +7 halt 17 3110000 +7 halt 18 3120000 +7 halt 19 3120000 +7 halt 20 3110000 +7 halt 21 3140000 +7 halt 22 3130000 +7 halt 23 3120000 +7 halt 24 3120000 +7 halt 25 3120000 +7 halt 26 3120000 +7 halt 27 3120000 +7 halt 28 3110000 +7 halt 29 3110000 +7 halt 30 3130000 +# point pass=7 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997959 +8 halt 1 3120000 +8 halt 2 3120000 +8 halt 3 3120000 +8 halt 4 3110000 +8 halt 5 3110000 +8 halt 6 3110000 +8 halt 7 3120000 +8 halt 8 3110000 +8 halt 9 3120000 +8 halt 10 3140000 +8 halt 11 3120000 +8 halt 12 3110000 +8 halt 13 3110000 +8 halt 14 3110000 +8 halt 15 3110000 +8 halt 16 3120000 +8 halt 17 3130000 +8 halt 18 3120000 +8 halt 19 3130000 +8 halt 20 3110000 +8 halt 21 3110000 +8 halt 22 3110000 +8 halt 23 3120000 +8 halt 24 3120000 +8 halt 25 3110000 +8 halt 26 3120000 +8 halt 27 3120000 +8 halt 28 3110000 +8 halt 29 3110000 +8 halt 30 3120000 +# point pass=8 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997959 +8 run 1 3120000 +8 run 2 3120000 +8 run 3 3120000 +8 run 4 3110000 +8 run 5 3120000 +8 run 6 3130000 +8 run 7 3140000 +8 run 8 3120000 +8 run 9 3130000 +8 run 10 3110000 +8 run 11 3120000 +8 run 12 3110000 +8 run 13 3120000 +8 run 14 3120000 +8 run 15 3140000 +8 run 16 3120000 +8 run 17 3130000 +8 run 18 3110000 +8 run 19 3120000 +8 run 20 3130000 +8 run 21 3130000 +8 run 22 3120000 +8 run 23 3120000 +8 run 24 3120000 +8 run 25 3120000 +8 run 26 3120000 +8 run 27 3130000 +8 run 28 3120000 +8 run 29 3120000 +8 run 30 3140000 +# point pass=8 state=run jobs_per_s=64975.9 updates_per_s=33267683.7 clock_hz=99997960 +9 halt 1 3120000 +9 halt 2 3110000 +9 halt 3 3130000 +9 halt 4 3120000 +9 halt 5 3110000 +9 halt 6 3110000 +9 halt 7 3110000 +9 halt 8 3110000 +9 halt 9 3120000 +9 halt 10 3110000 +9 halt 11 3110000 +9 halt 12 3130000 +9 halt 13 3110000 +9 halt 14 3120000 +9 halt 15 3110000 +9 halt 16 3110000 +9 halt 17 3110000 +9 halt 18 3110000 +9 halt 19 3120000 +9 halt 20 3110000 +9 halt 21 3110000 +9 halt 22 3110000 +9 halt 23 3110000 +9 halt 24 3110000 +9 halt 25 3110000 +9 halt 26 3110000 +9 halt 27 3130000 +9 halt 28 3110000 +9 halt 29 3100000 +9 halt 30 3110000 +# point pass=9 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997960 +9 run 1 3130000 +9 run 2 3120000 +9 run 3 3110000 +9 run 4 3120000 +9 run 5 3110000 +9 run 6 3120000 +9 run 7 3120000 +9 run 8 3130000 +9 run 9 3130000 +9 run 10 3110000 +9 run 11 3110000 +9 run 12 3120000 +9 run 13 3120000 +9 run 14 3130000 +9 run 15 3130000 +9 run 16 3120000 +9 run 17 3120000 +9 run 18 3120000 +9 run 19 3120000 +9 run 20 3120000 +9 run 21 3120000 +9 run 22 3110000 +9 run 23 3130000 +9 run 24 3140000 +9 run 25 3120000 +9 run 26 3120000 +9 run 27 3110000 +9 run 28 3120000 +9 run 29 3110000 +9 run 30 3110000 +# point pass=9 state=run jobs_per_s=64976.0 updates_per_s=33267683.6 clock_hz=99997960 +10 run 1 3120000 +10 run 2 3110000 +10 run 3 3380000 +10 run 4 3110000 +10 run 5 3110000 +10 run 6 3110000 +10 run 7 3100000 +10 run 8 3110000 +10 run 9 3110000 +10 run 10 3110000 +10 run 11 3100000 +10 run 12 3130000 +10 run 13 3110000 +10 run 14 3110000 +10 run 15 3110000 +10 run 16 3110000 +10 run 17 3110000 +10 run 18 3110000 +10 run 19 3110000 +10 run 20 3120000 +10 run 21 3130000 +10 run 22 3110000 +10 run 23 3110000 +10 run 24 3110000 +10 run 25 3110000 +10 run 26 3110000 +10 run 27 3110000 +10 run 28 3100000 +10 run 29 3120000 +10 run 30 3110000 +# point pass=10 state=run jobs_per_s=64975.9 updates_per_s=33267683.9 clock_hz=99997961 +10 halt 1 3100000 +10 halt 2 3100000 +10 halt 3 3110000 +10 halt 4 3100000 +10 halt 5 3100000 +10 halt 6 3100000 +10 halt 7 3110000 +10 halt 8 3100000 +10 halt 9 3120000 +10 halt 10 3110000 +10 halt 11 3120000 +10 halt 12 3100000 +10 halt 13 3100000 +10 halt 14 3100000 +10 halt 15 3110000 +10 halt 16 3120000 +10 halt 17 3120000 +10 halt 18 3110000 +10 halt 19 3100000 +10 halt 20 3110000 +10 halt 21 3100000 +10 halt 22 3110000 +10 halt 23 3100000 +10 halt 24 3100000 +10 halt 25 3110000 +10 halt 26 3110000 +10 halt 27 3100000 +10 halt 28 3100000 +10 halt 29 3100000 +10 halt 30 3090000 +# point pass=10 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997961 +11 halt 1 3120000 +11 halt 2 3110000 +11 halt 3 3090000 +11 halt 4 3100000 +11 halt 5 3130000 +11 halt 6 3110000 +11 halt 7 3100000 +11 halt 8 3110000 +11 halt 9 3100000 +11 halt 10 3090000 +11 halt 11 3100000 +11 halt 12 3110000 +11 halt 13 3100000 +11 halt 14 3120000 +11 halt 15 3100000 +11 halt 16 3120000 +11 halt 17 3100000 +11 halt 18 3100000 +11 halt 19 3100000 +11 halt 20 3100000 +11 halt 21 3100000 +11 halt 22 3110000 +11 halt 23 3100000 +11 halt 24 3110000 +11 halt 25 3100000 +11 halt 26 3110000 +11 halt 27 3100000 +11 halt 28 3110000 +11 halt 29 3110000 +11 halt 30 3110000 +# point pass=11 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997961 +11 run 1 3110000 +11 run 2 3140000 +11 run 3 3150000 +11 run 4 3120000 +11 run 5 3120000 +11 run 6 3120000 +11 run 7 3120000 +11 run 8 3120000 +11 run 9 3120000 +11 run 10 3120000 +11 run 11 3130000 +11 run 12 3110000 +11 run 13 3130000 +11 run 14 3120000 +11 run 15 3130000 +11 run 16 3120000 +11 run 17 3130000 +11 run 18 3120000 +11 run 19 3120000 +11 run 20 3120000 +11 run 21 3120000 +11 run 22 3130000 +11 run 23 3120000 +11 run 24 3120000 +11 run 25 3120000 +11 run 26 3140000 +11 run 27 3120000 +11 run 28 3120000 +11 run 29 3120000 +11 run 30 3130000 +# point pass=11 state=run jobs_per_s=64976.0 updates_per_s=33267683.6 clock_hz=99997960 +12 halt 1 3110000 +12 halt 2 3110000 +12 halt 3 3110000 +12 halt 4 3110000 +12 halt 5 3110000 +12 halt 6 3100000 +12 halt 7 3110000 +12 halt 8 3100000 +12 halt 9 3100000 +12 halt 10 3110000 +12 halt 11 3110000 +12 halt 12 3110000 +12 halt 13 3110000 +12 halt 14 3120000 +12 halt 15 3110000 +12 halt 16 3100000 +12 halt 17 3110000 +12 halt 18 3110000 +12 halt 19 3110000 +12 halt 20 3100000 +12 halt 21 3120000 +12 halt 22 3120000 +12 halt 23 3130000 +12 halt 24 3100000 +12 halt 25 3110000 +12 halt 26 3100000 +12 halt 27 3110000 +12 halt 28 3110000 +12 halt 29 3110000 +12 halt 30 3110000 +# point pass=12 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997961 +12 run 1 3110000 +12 run 2 3110000 +12 run 3 3110000 +12 run 4 3130000 +12 run 5 3110000 +12 run 6 3110000 +12 run 7 3110000 +12 run 8 3110000 +12 run 9 3120000 +12 run 10 3110000 +12 run 11 3150000 +12 run 12 3110000 +12 run 13 3120000 +12 run 14 3110000 +12 run 15 3120000 +12 run 16 3120000 +12 run 17 3110000 +12 run 18 3120000 +12 run 19 3130000 +12 run 20 3140000 +12 run 21 3120000 +12 run 22 3110000 +12 run 23 3120000 +12 run 24 3110000 +12 run 25 3120000 +12 run 26 3120000 +12 run 27 3120000 +12 run 28 3120000 +12 run 29 3110000 +12 run 30 3110000 +# point pass=12 state=run jobs_per_s=64976.0 updates_per_s=33267687.8 clock_hz=99997972 +# done SystemTime { tv_sec: 1793915273, tv_nsec: 319036681 } +# passes used 12 of 12 (dropped: []) +# run - halt = 6.7 +/- 1.8 mW (per-pass sd 6.2); 8/12 passes positive; 5 sample excursions beyond 6 MAD +# per-pass differences (mW): 10.0 10.0 5.0 0.0 0.0 10.0 0.0 0.0 10.0 10.0 20.0 5.0 +# board power while running 3117 mW; jobs/s 64976.0; updates/s 33267683.1; measured PL clock 99.998 MHz +# pre-registered prediction 5.0 mW: measured/predicted = 1.33, 0.9 sigma from it diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/k1_rdet.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/k1_rdet.dat new file mode 100644 index 000000000..660172d76 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/k1_rdet.dat @@ -0,0 +1,723 @@ +# kv_runhalt bitstream=ev_rdet.bit.bin gpio=594 settle=60s passes=12 samples=30 +# pass vehicle sample power_uW +1 run 1 3180000 +1 run 2 3170000 +1 run 3 3170000 +1 run 4 3160000 +1 run 5 3170000 +1 run 6 3150000 +1 run 7 3180000 +1 run 8 3150000 +1 run 9 3190000 +1 run 10 3140000 +1 run 11 3190000 +1 run 12 3140000 +1 run 13 3180000 +1 run 14 3140000 +1 run 15 3190000 +1 run 16 3140000 +1 run 17 3210000 +1 run 18 3140000 +1 run 19 3210000 +1 run 20 3140000 +1 run 21 3230000 +1 run 22 3150000 +1 run 23 3220000 +1 run 24 3150000 +1 run 25 3190000 +1 run 26 3140000 +1 run 27 3190000 +1 run 28 3150000 +1 run 29 3190000 +1 run 30 3140000 +1 halt 1 3070000 +1 halt 2 3080000 +1 halt 3 3080000 +1 halt 4 3110000 +1 halt 5 3070000 +1 halt 6 3080000 +1 halt 7 3080000 +1 halt 8 3070000 +1 halt 9 3080000 +1 halt 10 3090000 +1 halt 11 3080000 +1 halt 12 3080000 +1 halt 13 3080000 +1 halt 14 3080000 +1 halt 15 3140000 +1 halt 16 3080000 +1 halt 17 3100000 +1 halt 18 3080000 +1 halt 19 3080000 +1 halt 20 3090000 +1 halt 21 3090000 +1 halt 22 3080000 +1 halt 23 3140000 +1 halt 24 3100000 +1 halt 25 3100000 +1 halt 26 3080000 +1 halt 27 3090000 +1 halt 28 3080000 +1 halt 29 3110000 +1 halt 30 3080000 +2 run 1 3150000 +2 run 2 3150000 +2 run 3 3160000 +2 run 4 3150000 +2 run 5 3150000 +2 run 6 3140000 +2 run 7 3150000 +2 run 8 3150000 +2 run 9 3150000 +2 run 10 3150000 +2 run 11 3160000 +2 run 12 3170000 +2 run 13 3170000 +2 run 14 3150000 +2 run 15 3160000 +2 run 16 3150000 +2 run 17 3190000 +2 run 18 3150000 +2 run 19 3170000 +2 run 20 3140000 +2 run 21 3160000 +2 run 22 3160000 +2 run 23 3150000 +2 run 24 3150000 +2 run 25 3150000 +2 run 26 3160000 +2 run 27 3170000 +2 run 28 3160000 +2 run 29 3160000 +2 run 30 3150000 +2 halt 1 3190000 +2 halt 2 3100000 +2 halt 3 3170000 +2 halt 4 3080000 +2 halt 5 3180000 +2 halt 6 3080000 +2 halt 7 3210000 +2 halt 8 3090000 +2 halt 9 3180000 +2 halt 10 3080000 +2 halt 11 3160000 +2 halt 12 3080000 +2 halt 13 3080000 +2 halt 14 3200000 +2 halt 15 3090000 +2 halt 16 3190000 +2 halt 17 3080000 +2 halt 18 3210000 +2 halt 19 3080000 +2 halt 20 3200000 +2 halt 21 3100000 +2 halt 22 3220000 +2 halt 23 3080000 +2 halt 24 3200000 +2 halt 25 3080000 +2 halt 26 3220000 +2 halt 27 3080000 +2 halt 28 3230000 +2 halt 29 3080000 +2 halt 30 3090000 +3 run 1 3150000 +3 run 2 3240000 +3 run 3 3150000 +3 run 4 3240000 +3 run 5 3140000 +3 run 6 3250000 +3 run 7 3140000 +3 run 8 3240000 +3 run 9 3140000 +3 run 10 3250000 +3 run 11 3140000 +3 run 12 3240000 +3 run 13 3140000 +3 run 14 3240000 +3 run 15 3140000 +3 run 16 3240000 +3 run 17 3150000 +3 run 18 3250000 +3 run 19 3150000 +3 run 20 3250000 +3 run 21 3140000 +3 run 22 3260000 +3 run 23 3160000 +3 run 24 3250000 +3 run 25 3140000 +3 run 26 3260000 +3 run 27 3150000 +3 run 28 3260000 +3 run 29 3160000 +3 run 30 3280000 +3 halt 1 3170000 +3 halt 2 3070000 +3 halt 3 3180000 +3 halt 4 3090000 +3 halt 5 3160000 +3 halt 6 3090000 +3 halt 7 3170000 +3 halt 8 3080000 +3 halt 9 3150000 +3 halt 10 3090000 +3 halt 11 3140000 +3 halt 12 3100000 +3 halt 13 3130000 +3 halt 14 3080000 +3 halt 15 3130000 +3 halt 16 3080000 +3 halt 17 3160000 +3 halt 18 3100000 +3 halt 19 3140000 +3 halt 20 3100000 +3 halt 21 3160000 +3 halt 22 3090000 +3 halt 23 3170000 +3 halt 24 3080000 +3 halt 25 3160000 +3 halt 26 3090000 +3 halt 27 3170000 +3 halt 28 3100000 +3 halt 29 3170000 +3 halt 30 3090000 +4 halt 1 3100000 +4 halt 2 3170000 +4 halt 3 3090000 +4 halt 4 3190000 +4 halt 5 3090000 +4 halt 6 3190000 +4 halt 7 3100000 +4 halt 8 3170000 +4 halt 9 3080000 +4 halt 10 3220000 +4 halt 11 3080000 +4 halt 12 3240000 +4 halt 13 3090000 +4 halt 14 3230000 +4 halt 15 3090000 +4 halt 16 3250000 +4 halt 17 3090000 +4 halt 18 3240000 +4 halt 19 3080000 +4 halt 20 3270000 +4 halt 21 3480000 +4 halt 22 3080000 +4 halt 23 3090000 +4 halt 24 3100000 +4 halt 25 3090000 +4 halt 26 3110000 +4 halt 27 3080000 +4 halt 28 3080000 +4 halt 29 3090000 +4 halt 30 3090000 +4 run 1 3150000 +4 run 2 3150000 +4 run 3 3150000 +4 run 4 3140000 +4 run 5 3150000 +4 run 6 3160000 +4 run 7 3150000 +4 run 8 3150000 +4 run 9 3150000 +4 run 10 3160000 +4 run 11 3150000 +4 run 12 3150000 +4 run 13 3150000 +4 run 14 3160000 +4 run 15 3150000 +4 run 16 3190000 +4 run 17 3140000 +4 run 18 3190000 +4 run 19 3140000 +4 run 20 3180000 +4 run 21 3150000 +4 run 22 3180000 +4 run 23 3160000 +4 run 24 3170000 +4 run 25 3140000 +4 run 26 3180000 +4 run 27 3140000 +4 run 28 3150000 +4 run 29 3180000 +4 run 30 3160000 +5 run 1 3160000 +5 run 2 3160000 +5 run 3 3150000 +5 run 4 3170000 +5 run 5 3150000 +5 run 6 3160000 +5 run 7 3150000 +5 run 8 3150000 +5 run 9 3150000 +5 run 10 3170000 +5 run 11 3160000 +5 run 12 3180000 +5 run 13 3150000 +5 run 14 3160000 +5 run 15 3150000 +5 run 16 3180000 +5 run 17 3150000 +5 run 18 3200000 +5 run 19 3150000 +5 run 20 3180000 +5 run 21 3160000 +5 run 22 3180000 +5 run 23 3150000 +5 run 24 3180000 +5 run 25 3160000 +5 run 26 3210000 +5 run 27 3160000 +5 run 28 3190000 +5 run 29 3160000 +5 run 30 3200000 +5 halt 1 3170000 +5 halt 2 3090000 +5 halt 3 3160000 +5 halt 4 3070000 +5 halt 5 3140000 +5 halt 6 3090000 +5 halt 7 3150000 +5 halt 8 3070000 +5 halt 9 3130000 +5 halt 10 3070000 +5 halt 11 3160000 +5 halt 12 3070000 +5 halt 13 3150000 +5 halt 14 3070000 +5 halt 15 3160000 +5 halt 16 3080000 +5 halt 17 3160000 +5 halt 18 3070000 +5 halt 19 3160000 +5 halt 20 3070000 +5 halt 21 3190000 +5 halt 22 3080000 +5 halt 23 3170000 +5 halt 24 3070000 +5 halt 25 3170000 +5 halt 26 3070000 +5 halt 27 3170000 +5 halt 28 3070000 +5 halt 29 3170000 +5 halt 30 3070000 +6 run 1 3250000 +6 run 2 3150000 +6 run 3 3240000 +6 run 4 3150000 +6 run 5 3250000 +6 run 6 3150000 +6 run 7 3240000 +6 run 8 3150000 +6 run 9 3250000 +6 run 10 3160000 +6 run 11 3240000 +6 run 12 3150000 +6 run 13 3240000 +6 run 14 3150000 +6 run 15 3240000 +6 run 16 3160000 +6 run 17 3240000 +6 run 18 3150000 +6 run 19 3250000 +6 run 20 3160000 +6 run 21 3230000 +6 run 22 3150000 +6 run 23 3220000 +6 run 24 3150000 +6 run 25 3210000 +6 run 26 3150000 +6 run 27 3220000 +6 run 28 3150000 +6 run 29 3260000 +6 run 30 3150000 +6 halt 1 3070000 +6 halt 2 3070000 +6 halt 3 3080000 +6 halt 4 3080000 +6 halt 5 3070000 +6 halt 6 3080000 +6 halt 7 3070000 +6 halt 8 3070000 +6 halt 9 3080000 +6 halt 10 3100000 +6 halt 11 3070000 +6 halt 12 3120000 +6 halt 13 3070000 +6 halt 14 3090000 +6 halt 15 3070000 +6 halt 16 3120000 +6 halt 17 3070000 +6 halt 18 3130000 +6 halt 19 3070000 +6 halt 20 3110000 +6 halt 21 3080000 +6 halt 22 3120000 +6 halt 23 3070000 +6 halt 24 3100000 +6 halt 25 3070000 +6 halt 26 3110000 +6 halt 27 3070000 +6 halt 28 3130000 +6 halt 29 3070000 +6 halt 30 3140000 +7 halt 1 3090000 +7 halt 2 3080000 +7 halt 3 3070000 +7 halt 4 3070000 +7 halt 5 3070000 +7 halt 6 3070000 +7 halt 7 3250000 +7 halt 8 3070000 +7 halt 9 3080000 +7 halt 10 3070000 +7 halt 11 3240000 +7 halt 12 3070000 +7 halt 13 3230000 +7 halt 14 3070000 +7 halt 15 3220000 +7 halt 16 3080000 +7 halt 17 3210000 +7 halt 18 3070000 +7 halt 19 3200000 +7 halt 20 3080000 +7 halt 21 3200000 +7 halt 22 3070000 +7 halt 23 3210000 +7 halt 24 3070000 +7 halt 25 3190000 +7 halt 26 3080000 +7 halt 27 3220000 +7 halt 28 3070000 +7 halt 29 3180000 +7 halt 30 3080000 +7 run 1 3140000 +7 run 2 3210000 +7 run 3 3140000 +7 run 4 3210000 +7 run 5 3140000 +7 run 6 3210000 +7 run 7 3140000 +7 run 8 3220000 +7 run 9 3150000 +7 run 10 3230000 +7 run 11 3140000 +7 run 12 3220000 +7 run 13 3140000 +7 run 14 3210000 +7 run 15 3150000 +7 run 16 3230000 +7 run 17 3150000 +7 run 18 3220000 +7 run 19 3150000 +7 run 20 3200000 +7 run 21 3150000 +7 run 22 3210000 +7 run 23 3160000 +7 run 24 3210000 +7 run 25 3150000 +7 run 26 3220000 +7 run 27 3150000 +7 run 28 3200000 +7 run 29 3160000 +7 run 30 3190000 +8 halt 1 3070000 +8 halt 2 3070000 +8 halt 3 3080000 +8 halt 4 3070000 +8 halt 5 3240000 +8 halt 6 3070000 +8 halt 7 3210000 +8 halt 8 3080000 +8 halt 9 3200000 +8 halt 10 3080000 +8 halt 11 3210000 +8 halt 12 3090000 +8 halt 13 3210000 +8 halt 14 3080000 +8 halt 15 3540000 +8 halt 16 3080000 +8 halt 17 3170000 +8 halt 18 3100000 +8 halt 19 3160000 +8 halt 20 3140000 +8 halt 21 3190000 +8 halt 22 3080000 +8 halt 23 3190000 +8 halt 24 3070000 +8 halt 25 3170000 +8 halt 26 3080000 +8 halt 27 3170000 +8 halt 28 3080000 +8 halt 29 3160000 +8 halt 30 3080000 +8 run 1 3280000 +8 run 2 3130000 +8 run 3 3250000 +8 run 4 3140000 +8 run 5 3260000 +8 run 6 3140000 +8 run 7 3260000 +8 run 8 3150000 +8 run 9 3240000 +8 run 10 3140000 +8 run 11 3260000 +8 run 12 3140000 +8 run 13 3260000 +8 run 14 3140000 +8 run 15 3260000 +8 run 16 3140000 +8 run 17 3270000 +8 run 18 3140000 +8 run 19 3260000 +8 run 20 3150000 +8 run 21 3280000 +8 run 22 3150000 +8 run 23 3260000 +8 run 24 3140000 +8 run 25 3270000 +8 run 26 3140000 +8 run 27 3290000 +8 run 28 3140000 +8 run 29 3290000 +8 run 30 3150000 +9 halt 1 3170000 +9 halt 2 3090000 +9 halt 3 3170000 +9 halt 4 3080000 +9 halt 5 3180000 +9 halt 6 3080000 +9 halt 7 3170000 +9 halt 8 3070000 +9 halt 9 3190000 +9 halt 10 3090000 +9 halt 11 3160000 +9 halt 12 3080000 +9 halt 13 3190000 +9 halt 14 3080000 +9 halt 15 3180000 +9 halt 16 3080000 +9 halt 17 3160000 +9 halt 18 3080000 +9 halt 19 3170000 +9 halt 20 3090000 +9 halt 21 3170000 +9 halt 22 3090000 +9 halt 23 3170000 +9 halt 24 3080000 +9 halt 25 3180000 +9 halt 26 3090000 +9 halt 27 3190000 +9 halt 28 3080000 +9 halt 29 3220000 +9 halt 30 3080000 +9 run 1 3150000 +9 run 2 3190000 +9 run 3 3140000 +9 run 4 3220000 +9 run 5 3140000 +9 run 6 3220000 +9 run 7 3140000 +9 run 8 3220000 +9 run 9 3140000 +9 run 10 3220000 +9 run 11 3150000 +9 run 12 3240000 +9 run 13 3140000 +9 run 14 3230000 +9 run 15 3140000 +9 run 16 3230000 +9 run 17 3130000 +9 run 18 3230000 +9 run 19 3140000 +9 run 20 3210000 +9 run 21 3150000 +9 run 22 3230000 +9 run 23 3160000 +9 run 24 3240000 +9 run 25 3160000 +9 run 26 3240000 +9 run 27 3150000 +9 run 28 3240000 +9 run 29 3150000 +9 run 30 3240000 +10 halt 1 3080000 +10 halt 2 3110000 +10 halt 3 3070000 +10 halt 4 3130000 +10 halt 5 3070000 +10 halt 6 3150000 +10 halt 7 3080000 +10 halt 8 3130000 +10 halt 9 3070000 +10 halt 10 3120000 +10 halt 11 3070000 +10 halt 12 3130000 +10 halt 13 3080000 +10 halt 14 3110000 +10 halt 15 3070000 +10 halt 16 3110000 +10 halt 17 3070000 +10 halt 18 3120000 +10 halt 19 3070000 +10 halt 20 3100000 +10 halt 21 3080000 +10 halt 22 3120000 +10 halt 23 3070000 +10 halt 24 3110000 +10 halt 25 3170000 +10 halt 26 3070000 +10 halt 27 3170000 +10 halt 28 3100000 +10 halt 29 3170000 +10 halt 30 3080000 +10 run 1 3150000 +10 run 2 3180000 +10 run 3 3150000 +10 run 4 3180000 +10 run 5 3160000 +10 run 6 3170000 +10 run 7 3160000 +10 run 8 3190000 +10 run 9 3150000 +10 run 10 3200000 +10 run 11 3150000 +10 run 12 3210000 +10 run 13 3150000 +10 run 14 3200000 +10 run 15 3150000 +10 run 16 3240000 +10 run 17 3160000 +10 run 18 3240000 +10 run 19 3150000 +10 run 20 3240000 +10 run 21 3160000 +10 run 22 3240000 +10 run 23 3150000 +10 run 24 3250000 +10 run 25 3270000 +10 run 26 3150000 +10 run 27 3280000 +10 run 28 3150000 +10 run 29 3320000 +10 run 30 3160000 +11 halt 1 3180000 +11 halt 2 3090000 +11 halt 3 3180000 +11 halt 4 3090000 +11 halt 5 3200000 +11 halt 6 3080000 +11 halt 7 3190000 +11 halt 8 3080000 +11 halt 9 3180000 +11 halt 10 3090000 +11 halt 11 3170000 +11 halt 12 3120000 +11 halt 13 3180000 +11 halt 14 3090000 +11 halt 15 3180000 +11 halt 16 3110000 +11 halt 17 3170000 +11 halt 18 3110000 +11 halt 19 3190000 +11 halt 20 3090000 +11 halt 21 3170000 +11 halt 22 3090000 +11 halt 23 3170000 +11 halt 24 3100000 +11 halt 25 3170000 +11 halt 26 3100000 +11 halt 27 3170000 +11 halt 28 3090000 +11 halt 29 3160000 +11 halt 30 3090000 +11 run 1 3160000 +11 run 2 3160000 +11 run 3 3160000 +11 run 4 3150000 +11 run 5 3160000 +11 run 6 3160000 +11 run 7 3150000 +11 run 8 3170000 +11 run 9 3180000 +11 run 10 3180000 +11 run 11 3160000 +11 run 12 3180000 +11 run 13 3160000 +11 run 14 3170000 +11 run 15 3150000 +11 run 16 3180000 +11 run 17 3150000 +11 run 18 3190000 +11 run 19 3170000 +11 run 20 3190000 +11 run 21 3160000 +11 run 22 3220000 +11 run 23 3150000 +11 run 24 3220000 +11 run 25 3160000 +11 run 26 3220000 +11 run 27 3160000 +11 run 28 3230000 +11 run 29 3150000 +11 run 30 3220000 +12 halt 1 3080000 +12 halt 2 3080000 +12 halt 3 3080000 +12 halt 4 3080000 +12 halt 5 3080000 +12 halt 6 3090000 +12 halt 7 3070000 +12 halt 8 3080000 +12 halt 9 3070000 +12 halt 10 3070000 +12 halt 11 3100000 +12 halt 12 3070000 +12 halt 13 3070000 +12 halt 14 3190000 +12 halt 15 3080000 +12 halt 16 3070000 +12 halt 17 3100000 +12 halt 18 3070000 +12 halt 19 3090000 +12 halt 20 3070000 +12 halt 21 3070000 +12 halt 22 3070000 +12 halt 23 3070000 +12 halt 24 3080000 +12 halt 25 3070000 +12 halt 26 3070000 +12 halt 27 3080000 +12 halt 28 3080000 +12 halt 29 3080000 +12 halt 30 3090000 +12 run 1 3150000 +12 run 2 3260000 +12 run 3 3150000 +12 run 4 3260000 +12 run 5 3150000 +12 run 6 3290000 +12 run 7 3150000 +12 run 8 3160000 +12 run 9 3150000 +12 run 10 3160000 +12 run 11 3160000 +12 run 12 3170000 +12 run 13 3160000 +12 run 14 3150000 +12 run 15 3150000 +12 run 16 3150000 +12 run 17 3180000 +12 run 18 3150000 +12 run 19 3170000 +12 run 20 3160000 +12 run 21 3150000 +12 run 22 3170000 +12 run 23 3150000 +12 run 24 3200000 +12 run 25 3150000 +12 run 26 3180000 +12 run 27 3150000 +12 run 28 3210000 +12 run 29 3150000 +12 run 30 3190000 +# done diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/null.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/null.dat new file mode 100644 index 000000000..5d1f5056d --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/null.dat @@ -0,0 +1,505 @@ +# class t0-recall +# vqpu-edge meter passes=8 settle=60s samples=30 null=true sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793909509, tv_nsec: 550481081 } +# pass state sample power_uW +1 halt 1 3110000 +1 halt 2 3110000 +1 halt 3 3140000 +1 halt 4 3110000 +1 halt 5 3110000 +1 halt 6 3110000 +1 halt 7 3110000 +1 halt 8 3100000 +1 halt 9 3120000 +1 halt 10 3110000 +1 halt 11 3110000 +1 halt 12 3110000 +1 halt 13 3120000 +1 halt 14 3120000 +1 halt 15 3110000 +1 halt 16 3110000 +1 halt 17 3110000 +1 halt 18 3130000 +1 halt 19 3120000 +1 halt 20 3110000 +1 halt 21 3120000 +1 halt 22 3110000 +1 halt 23 3120000 +1 halt 24 3120000 +1 halt 25 3120000 +1 halt 26 3120000 +1 halt 27 3120000 +1 halt 28 3110000 +1 halt 29 3120000 +1 halt 30 3110000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998042 +1 run 1 3120000 +1 run 2 3110000 +1 run 3 3120000 +1 run 4 3110000 +1 run 5 3110000 +1 run 6 3110000 +1 run 7 3120000 +1 run 8 3110000 +1 run 9 3100000 +1 run 10 3110000 +1 run 11 3110000 +1 run 12 3110000 +1 run 13 3110000 +1 run 14 3120000 +1 run 15 3140000 +1 run 16 3120000 +1 run 17 3110000 +1 run 18 3110000 +1 run 19 3110000 +1 run 20 3110000 +1 run 21 3110000 +1 run 22 3100000 +1 run 23 3120000 +1 run 24 3140000 +1 run 25 3110000 +1 run 26 3110000 +1 run 27 3110000 +1 run 28 3120000 +1 run 29 3100000 +1 run 30 3120000 +# point pass=1 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998030 +2 halt 1 3120000 +2 halt 2 3110000 +2 halt 3 3110000 +2 halt 4 3110000 +2 halt 5 3110000 +2 halt 6 3180000 +2 halt 7 3110000 +2 halt 8 3110000 +2 halt 9 3110000 +2 halt 10 3100000 +2 halt 11 3120000 +2 halt 12 3130000 +2 halt 13 3110000 +2 halt 14 3110000 +2 halt 15 3110000 +2 halt 16 3120000 +2 halt 17 3110000 +2 halt 18 3110000 +2 halt 19 3110000 +2 halt 20 3120000 +2 halt 21 3110000 +2 halt 22 3110000 +2 halt 23 3110000 +2 halt 24 3120000 +2 halt 25 3110000 +2 halt 26 3120000 +2 halt 27 3100000 +2 halt 28 3110000 +2 halt 29 3110000 +2 halt 30 3110000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998021 +2 run 1 3110000 +2 run 2 3110000 +2 run 3 3110000 +2 run 4 3110000 +2 run 5 3110000 +2 run 6 3110000 +2 run 7 3110000 +2 run 8 3120000 +2 run 9 3130000 +2 run 10 3110000 +2 run 11 3110000 +2 run 12 3110000 +2 run 13 3110000 +2 run 14 3110000 +2 run 15 3110000 +2 run 16 3110000 +2 run 17 3130000 +2 run 18 3130000 +2 run 19 3100000 +2 run 20 3110000 +2 run 21 3110000 +2 run 22 3120000 +2 run 23 3110000 +2 run 24 3110000 +2 run 25 3110000 +2 run 26 3120000 +2 run 27 3110000 +2 run 28 3110000 +2 run 29 3110000 +2 run 30 3110000 +# point pass=2 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998014 +3 halt 1 3110000 +3 halt 2 3110000 +3 halt 3 3110000 +3 halt 4 3100000 +3 halt 5 3120000 +3 halt 6 3130000 +3 halt 7 3110000 +3 halt 8 3110000 +3 halt 9 3110000 +3 halt 10 3110000 +3 halt 11 3110000 +3 halt 12 3110000 +3 halt 13 3110000 +3 halt 14 3130000 +3 halt 15 3110000 +3 halt 16 3110000 +3 halt 17 3110000 +3 halt 18 3110000 +3 halt 19 3100000 +3 halt 20 3110000 +3 halt 21 3100000 +3 halt 22 3110000 +3 halt 23 3110000 +3 halt 24 3110000 +3 halt 25 3110000 +3 halt 26 3110000 +3 halt 27 3110000 +3 halt 28 3130000 +3 halt 29 3130000 +3 halt 30 3110000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998007 +3 run 1 3110000 +3 run 2 3130000 +3 run 3 3110000 +3 run 4 3110000 +3 run 5 3110000 +3 run 6 3110000 +3 run 7 3120000 +3 run 8 3110000 +3 run 9 3110000 +3 run 10 3110000 +3 run 11 3110000 +3 run 12 3110000 +3 run 13 3110000 +3 run 14 3110000 +3 run 15 3110000 +3 run 16 3110000 +3 run 17 3120000 +3 run 18 3110000 +3 run 19 3110000 +3 run 20 3110000 +3 run 21 3110000 +3 run 22 3110000 +3 run 23 3110000 +3 run 24 3110000 +3 run 25 3130000 +3 run 26 3130000 +3 run 27 3100000 +3 run 28 3120000 +3 run 29 3110000 +3 run 30 3110000 +# point pass=3 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998002 +4 halt 1 3110000 +4 halt 2 3110000 +4 halt 3 3120000 +4 halt 4 3120000 +4 halt 5 3110000 +4 halt 6 3110000 +4 halt 7 3110000 +4 halt 8 3110000 +4 halt 9 3110000 +4 halt 10 3110000 +4 halt 11 3110000 +4 halt 12 3110000 +4 halt 13 3100000 +4 halt 14 3120000 +4 halt 15 3110000 +4 halt 16 3110000 +4 halt 17 3100000 +4 halt 18 3110000 +4 halt 19 3110000 +4 halt 20 3110000 +4 halt 21 3100000 +4 halt 22 3120000 +4 halt 23 3110000 +4 halt 24 3100000 +4 halt 25 3110000 +4 halt 26 3100000 +4 halt 27 3110000 +4 halt 28 3100000 +4 halt 29 3100000 +4 halt 30 3110000 +# point pass=4 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997997 +4 run 1 3100000 +4 run 2 3110000 +4 run 3 3110000 +4 run 4 3100000 +4 run 5 3110000 +4 run 6 3110000 +4 run 7 3100000 +4 run 8 3110000 +4 run 9 3110000 +4 run 10 3120000 +4 run 11 3120000 +4 run 12 3110000 +4 run 13 3100000 +4 run 14 3110000 +4 run 15 3100000 +4 run 16 3110000 +4 run 17 3110000 +4 run 18 3100000 +4 run 19 3130000 +4 run 20 3110000 +4 run 21 3100000 +4 run 22 3130000 +4 run 23 3120000 +4 run 24 3100000 +4 run 25 3100000 +4 run 26 3110000 +4 run 27 3490000 +4 run 28 3100000 +4 run 29 3110000 +4 run 30 3110000 +# point pass=4 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997993 +5 run 1 3110000 +5 run 2 3110000 +5 run 3 3100000 +5 run 4 3110000 +5 run 5 3110000 +5 run 6 3110000 +5 run 7 3120000 +5 run 8 3140000 +5 run 9 3100000 +5 run 10 3110000 +5 run 11 3110000 +5 run 12 3110000 +5 run 13 3110000 +5 run 14 3110000 +5 run 15 3100000 +5 run 16 3140000 +5 run 17 3110000 +5 run 18 3100000 +5 run 19 3100000 +5 run 20 3110000 +5 run 21 3100000 +5 run 22 3110000 +5 run 23 3110000 +5 run 24 3100000 +5 run 25 3110000 +5 run 26 3100000 +5 run 27 3110000 +5 run 28 3110000 +5 run 29 3110000 +5 run 30 3110000 +# point pass=5 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997990 +5 halt 1 3130000 +5 halt 2 3120000 +5 halt 3 3120000 +5 halt 4 3140000 +5 halt 5 3140000 +5 halt 6 3120000 +5 halt 7 3110000 +5 halt 8 3120000 +5 halt 9 3130000 +5 halt 10 3110000 +5 halt 11 3120000 +5 halt 12 3130000 +5 halt 13 3140000 +5 halt 14 3120000 +5 halt 15 3120000 +5 halt 16 3120000 +5 halt 17 3110000 +5 halt 18 3110000 +5 halt 19 3120000 +5 halt 20 3110000 +5 halt 21 3110000 +5 halt 22 3120000 +5 halt 23 3110000 +5 halt 24 3120000 +5 halt 25 3120000 +5 halt 26 3110000 +5 halt 27 3120000 +5 halt 28 3140000 +5 halt 29 3120000 +5 halt 30 3120000 +# point pass=5 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997987 +6 halt 1 3140000 +6 halt 2 3120000 +6 halt 3 3130000 +6 halt 4 3110000 +6 halt 5 3120000 +6 halt 6 3110000 +6 halt 7 3110000 +6 halt 8 3120000 +6 halt 9 3120000 +6 halt 10 3110000 +6 halt 11 3120000 +6 halt 12 3100000 +6 halt 13 3110000 +6 halt 14 3120000 +6 halt 15 3120000 +6 halt 16 3140000 +6 halt 17 3120000 +6 halt 18 3120000 +6 halt 19 3130000 +6 halt 20 3120000 +6 halt 21 3120000 +6 halt 22 3120000 +6 halt 23 3110000 +6 halt 24 3140000 +6 halt 25 3140000 +6 halt 26 3120000 +6 halt 27 3120000 +6 halt 28 3110000 +6 halt 29 3110000 +6 halt 30 3120000 +# point pass=6 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997985 +6 run 1 3110000 +6 run 2 3110000 +6 run 3 3290000 +6 run 4 3100000 +6 run 5 3100000 +6 run 6 3110000 +6 run 7 3110000 +6 run 8 3110000 +6 run 9 3110000 +6 run 10 3110000 +6 run 11 3110000 +6 run 12 3110000 +6 run 13 3130000 +6 run 14 3110000 +6 run 15 3120000 +6 run 16 3110000 +6 run 17 3110000 +6 run 18 3110000 +6 run 19 3130000 +6 run 20 3110000 +6 run 21 3140000 +6 run 22 3130000 +6 run 23 3110000 +6 run 24 3110000 +6 run 25 3110000 +6 run 26 3110000 +6 run 27 3110000 +6 run 28 3110000 +6 run 29 3110000 +6 run 30 3120000 +# point pass=6 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997983 +7 run 1 3110000 +7 run 2 3120000 +7 run 3 3120000 +7 run 4 3120000 +7 run 5 3110000 +7 run 6 3120000 +7 run 7 3110000 +7 run 8 3130000 +7 run 9 3110000 +7 run 10 3140000 +7 run 11 3110000 +7 run 12 3120000 +7 run 13 3120000 +7 run 14 3110000 +7 run 15 3120000 +7 run 16 3120000 +7 run 17 3120000 +7 run 18 3140000 +7 run 19 3120000 +7 run 20 3110000 +7 run 21 3120000 +7 run 22 3110000 +7 run 23 3110000 +7 run 24 3130000 +7 run 25 3110000 +7 run 26 3110000 +7 run 27 3120000 +7 run 28 3110000 +7 run 29 3120000 +7 run 30 3120000 +# point pass=7 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997982 +7 halt 1 3110000 +7 halt 2 3110000 +7 halt 3 3110000 +7 halt 4 3110000 +7 halt 5 3110000 +7 halt 6 3120000 +7 halt 7 3130000 +7 halt 8 3130000 +7 halt 9 3110000 +7 halt 10 3110000 +7 halt 11 3110000 +7 halt 12 3110000 +7 halt 13 3120000 +7 halt 14 3110000 +7 halt 15 3140000 +7 halt 16 3120000 +7 halt 17 3110000 +7 halt 18 3120000 +7 halt 19 3110000 +7 halt 20 3120000 +7 halt 21 3110000 +7 halt 22 3120000 +7 halt 23 3110000 +7 halt 24 3110000 +7 halt 25 3110000 +7 halt 26 3110000 +7 halt 27 3110000 +7 halt 28 3110000 +7 halt 29 3110000 +7 halt 30 3140000 +# point pass=7 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997980 +8 run 1 3110000 +8 run 2 3100000 +8 run 3 3120000 +8 run 4 3120000 +8 run 5 3110000 +8 run 6 3100000 +8 run 7 3100000 +8 run 8 3100000 +8 run 9 3100000 +8 run 10 3110000 +8 run 11 3110000 +8 run 12 3110000 +8 run 13 3100000 +8 run 14 3100000 +8 run 15 3110000 +8 run 16 3110000 +8 run 17 3100000 +8 run 18 3110000 +8 run 19 3110000 +8 run 20 3100000 +8 run 21 3100000 +8 run 22 3110000 +8 run 23 3100000 +8 run 24 3110000 +8 run 25 3100000 +8 run 26 3110000 +8 run 27 3110000 +8 run 28 3110000 +8 run 29 3110000 +8 run 30 3110000 +# point pass=8 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997980 +8 halt 1 3100000 +8 halt 2 3110000 +8 halt 3 3110000 +8 halt 4 3110000 +8 halt 5 3120000 +8 halt 6 3110000 +8 halt 7 3100000 +8 halt 8 3120000 +8 halt 9 3120000 +8 halt 10 3110000 +8 halt 11 3110000 +8 halt 12 3120000 +8 halt 13 3110000 +8 halt 14 3110000 +8 halt 15 3130000 +8 halt 16 3120000 +8 halt 17 3110000 +8 halt 18 3100000 +8 halt 19 3110000 +8 halt 20 3120000 +8 halt 21 3150000 +8 halt 22 3110000 +8 halt 23 3140000 +8 halt 24 3130000 +8 halt 25 3120000 +8 halt 26 3110000 +8 halt 27 3110000 +8 halt 28 3110000 +8 halt 29 3110000 +8 halt 30 3110000 +# point pass=8 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997978 +# done SystemTime { tv_sec: 1793910950, tv_nsec: 445594110 } +# passes used 8 of 8 (dropped: []) +# run - halt = -1.2 +/- 2.3 mW (per-pass sd 6.4); 1/8 passes positive; 4 sample excursions beyond 6 MAD +# per-pass differences (mW): 0.0 0.0 0.0 0.0 -10.0 -10.0 10.0 0.0 +# board power while running 3111 mW; jobs/s 0.0; updates/s 0.0; measured PL clock 99.998 MHz +# pre-registered prediction 0.0 mW: measured/predicted = -inf, -0.6 sigma from it diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/solve-assign.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/solve-assign.dat new file mode 100644 index 000000000..fd1bf1dee --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/solve-assign.dat @@ -0,0 +1,505 @@ +# class solve-assign +# vqpu-edge meter passes=8 settle=60s samples=30 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793916714, tv_nsec: 341051123 } +# pass state sample power_uW +1 halt 1 3140000 +1 halt 2 3110000 +1 halt 3 3130000 +1 halt 4 3110000 +1 halt 5 3130000 +1 halt 6 3120000 +1 halt 7 3110000 +1 halt 8 3120000 +1 halt 9 3140000 +1 halt 10 3130000 +1 halt 11 3110000 +1 halt 12 3120000 +1 halt 13 3110000 +1 halt 14 3120000 +1 halt 15 3130000 +1 halt 16 3110000 +1 halt 17 3120000 +1 halt 18 3140000 +1 halt 19 3120000 +1 halt 20 3120000 +1 halt 21 3120000 +1 halt 22 3110000 +1 halt 23 3120000 +1 halt 24 3110000 +1 halt 25 3110000 +1 halt 26 3110000 +1 halt 27 3110000 +1 halt 28 3110000 +1 halt 29 3110000 +1 halt 30 3120000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998005 +1 run 1 3110000 +1 run 2 3110000 +1 run 3 3110000 +1 run 4 3110000 +1 run 5 3130000 +1 run 6 3140000 +1 run 7 3120000 +1 run 8 3100000 +1 run 9 3110000 +1 run 10 3110000 +1 run 11 3110000 +1 run 12 3110000 +1 run 13 3120000 +1 run 14 3100000 +1 run 15 3110000 +1 run 16 3110000 +1 run 17 3110000 +1 run 18 3110000 +1 run 19 3110000 +1 run 20 3110000 +1 run 21 3130000 +1 run 22 3110000 +1 run 23 3110000 +1 run 24 3110000 +1 run 25 3110000 +1 run 26 3110000 +1 run 27 3120000 +1 run 28 3110000 +1 run 29 3130000 +1 run 30 3130000 +# point pass=1 state=run jobs_per_s=94695.1 updates_per_s=33237978.4 clock_hz=99998002 +2 halt 1 3100000 +2 halt 2 3100000 +2 halt 3 3120000 +2 halt 4 3100000 +2 halt 5 3100000 +2 halt 6 3110000 +2 halt 7 3100000 +2 halt 8 3110000 +2 halt 9 3110000 +2 halt 10 3110000 +2 halt 11 3110000 +2 halt 12 3110000 +2 halt 13 3110000 +2 halt 14 3100000 +2 halt 15 3100000 +2 halt 16 3110000 +2 halt 17 3100000 +2 halt 18 3120000 +2 halt 19 3100000 +2 halt 20 3110000 +2 halt 21 3120000 +2 halt 22 3120000 +2 halt 23 3110000 +2 halt 24 3110000 +2 halt 25 3110000 +2 halt 26 3130000 +2 halt 27 3310000 +2 halt 28 3110000 +2 halt 29 3110000 +2 halt 30 3110000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998000 +2 run 1 3120000 +2 run 2 3120000 +2 run 3 3110000 +2 run 4 3110000 +2 run 5 3110000 +2 run 6 3120000 +2 run 7 3120000 +2 run 8 3110000 +2 run 9 3120000 +2 run 10 3110000 +2 run 11 3110000 +2 run 12 3110000 +2 run 13 3110000 +2 run 14 3110000 +2 run 15 3140000 +2 run 16 3120000 +2 run 17 3120000 +2 run 18 3110000 +2 run 19 3130000 +2 run 20 3110000 +2 run 21 3130000 +2 run 22 3110000 +2 run 23 3140000 +2 run 24 3110000 +2 run 25 3120000 +2 run 26 3110000 +2 run 27 3120000 +2 run 28 3120000 +2 run 29 3110000 +2 run 30 3110000 +# point pass=2 state=run jobs_per_s=94695.1 updates_per_s=33237977.4 clock_hz=99997999 +3 run 1 3110000 +3 run 2 3120000 +3 run 3 3130000 +3 run 4 3120000 +3 run 5 3110000 +3 run 6 3120000 +3 run 7 3120000 +3 run 8 3110000 +3 run 9 3120000 +3 run 10 3110000 +3 run 11 3140000 +3 run 12 3140000 +3 run 13 3110000 +3 run 14 3120000 +3 run 15 3120000 +3 run 16 3120000 +3 run 17 3110000 +3 run 18 3130000 +3 run 19 3120000 +3 run 20 3130000 +3 run 21 3120000 +3 run 22 3110000 +3 run 23 3130000 +3 run 24 3110000 +3 run 25 3110000 +3 run 26 3120000 +3 run 27 3110000 +3 run 28 3120000 +3 run 29 3120000 +3 run 30 3120000 +# point pass=3 state=run jobs_per_s=94695.1 updates_per_s=33237977.1 clock_hz=99997998 +3 halt 1 3110000 +3 halt 2 3110000 +3 halt 3 3100000 +3 halt 4 3100000 +3 halt 5 3100000 +3 halt 6 3100000 +3 halt 7 3100000 +3 halt 8 3120000 +3 halt 9 3120000 +3 halt 10 3100000 +3 halt 11 3100000 +3 halt 12 3100000 +3 halt 13 3100000 +3 halt 14 3100000 +3 halt 15 3100000 +3 halt 16 3110000 +3 halt 17 3100000 +3 halt 18 3100000 +3 halt 19 3100000 +3 halt 20 3100000 +3 halt 21 3100000 +3 halt 22 3100000 +3 halt 23 3110000 +3 halt 24 3100000 +3 halt 25 3110000 +3 halt 26 3110000 +3 halt 27 3110000 +3 halt 28 3090000 +3 halt 29 3110000 +3 halt 30 3100000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997997 +4 run 1 3110000 +4 run 2 3110000 +4 run 3 3140000 +4 run 4 3120000 +4 run 5 3120000 +4 run 6 3110000 +4 run 7 3110000 +4 run 8 3530000 +4 run 9 3110000 +4 run 10 3100000 +4 run 11 3110000 +4 run 12 3110000 +4 run 13 3100000 +4 run 14 3110000 +4 run 15 3100000 +4 run 16 3100000 +4 run 17 3110000 +4 run 18 3110000 +4 run 19 3100000 +4 run 20 3130000 +4 run 21 3110000 +4 run 22 3110000 +4 run 23 3110000 +4 run 24 3110000 +4 run 25 3100000 +4 run 26 3100000 +4 run 27 3110000 +4 run 28 3120000 +4 run 29 3130000 +4 run 30 3110000 +# point pass=4 state=run jobs_per_s=94695.1 updates_per_s=33237993.2 clock_hz=99998046 +4 halt 1 3110000 +4 halt 2 3110000 +4 halt 3 3100000 +4 halt 4 3110000 +4 halt 5 3110000 +4 halt 6 3090000 +4 halt 7 3100000 +4 halt 8 3100000 +4 halt 9 3110000 +4 halt 10 3100000 +4 halt 11 3110000 +4 halt 12 3110000 +4 halt 13 3100000 +4 halt 14 3110000 +4 halt 15 3100000 +4 halt 16 3100000 +4 halt 17 3120000 +4 halt 18 3090000 +4 halt 19 3100000 +4 halt 20 3100000 +4 halt 21 3100000 +4 halt 22 3100000 +4 halt 23 3100000 +4 halt 24 3100000 +4 halt 25 3110000 +4 halt 26 3110000 +4 halt 27 3100000 +4 halt 28 3100000 +4 halt 29 3110000 +4 halt 30 3110000 +# point pass=4 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998049 +5 halt 1 3170000 +5 halt 2 3110000 +5 halt 3 3120000 +5 halt 4 3100000 +5 halt 5 3130000 +5 halt 6 3120000 +5 halt 7 3120000 +5 halt 8 3100000 +5 halt 9 3120000 +5 halt 10 3120000 +5 halt 11 3120000 +5 halt 12 3120000 +5 halt 13 3130000 +5 halt 14 3140000 +5 halt 15 3120000 +5 halt 16 3110000 +5 halt 17 3120000 +5 halt 18 3110000 +5 halt 19 3110000 +5 halt 20 3110000 +5 halt 21 3110000 +5 halt 22 3130000 +5 halt 23 3110000 +5 halt 24 3110000 +5 halt 25 3120000 +5 halt 26 3110000 +5 halt 27 3120000 +5 halt 28 3110000 +5 halt 29 3120000 +5 halt 30 3120000 +# point pass=5 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998040 +5 run 1 3120000 +5 run 2 3130000 +5 run 3 3120000 +5 run 4 3130000 +5 run 5 3130000 +5 run 6 3110000 +5 run 7 3110000 +5 run 8 3120000 +5 run 9 3130000 +5 run 10 3140000 +5 run 11 3140000 +5 run 12 3120000 +5 run 13 3110000 +5 run 14 3120000 +5 run 15 3120000 +5 run 16 3120000 +5 run 17 3120000 +5 run 18 3110000 +5 run 19 3140000 +5 run 20 3120000 +5 run 21 3110000 +5 run 22 3140000 +5 run 23 3120000 +5 run 24 3120000 +5 run 25 3130000 +5 run 26 3120000 +5 run 27 3120000 +5 run 28 3130000 +5 run 29 3120000 +5 run 30 3130000 +# point pass=5 state=run jobs_per_s=94695.1 updates_per_s=33237988.9 clock_hz=99998033 +6 run 1 3120000 +6 run 2 3120000 +6 run 3 3140000 +6 run 4 3140000 +6 run 5 3120000 +6 run 6 3120000 +6 run 7 3130000 +6 run 8 3110000 +6 run 9 3110000 +6 run 10 3120000 +6 run 11 3110000 +6 run 12 3110000 +6 run 13 3110000 +6 run 14 3120000 +6 run 15 3110000 +6 run 16 3110000 +6 run 17 3110000 +6 run 18 3110000 +6 run 19 3110000 +6 run 20 3120000 +6 run 21 3120000 +6 run 22 3140000 +6 run 23 3120000 +6 run 24 3120000 +6 run 25 3120000 +6 run 26 3110000 +6 run 27 3110000 +6 run 28 3120000 +6 run 29 3110000 +6 run 30 3130000 +# point pass=6 state=run jobs_per_s=94695.1 updates_per_s=33237987.0 clock_hz=99998028 +6 halt 1 3110000 +6 halt 2 3110000 +6 halt 3 3110000 +6 halt 4 3100000 +6 halt 5 3150000 +6 halt 6 3120000 +6 halt 7 3110000 +6 halt 8 3120000 +6 halt 9 3110000 +6 halt 10 3110000 +6 halt 11 3100000 +6 halt 12 3120000 +6 halt 13 3110000 +6 halt 14 3110000 +6 halt 15 3120000 +6 halt 16 3110000 +6 halt 17 3110000 +6 halt 18 3110000 +6 halt 19 3110000 +6 halt 20 3110000 +6 halt 21 3110000 +6 halt 22 3110000 +6 halt 23 3110000 +6 halt 24 3110000 +6 halt 25 3110000 +6 halt 26 3110000 +6 halt 27 3120000 +6 halt 28 3130000 +6 halt 29 3130000 +6 halt 30 3100000 +# point pass=6 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998023 +7 halt 1 3100000 +7 halt 2 3110000 +7 halt 3 3130000 +7 halt 4 3110000 +7 halt 5 3100000 +7 halt 6 3110000 +7 halt 7 3120000 +7 halt 8 3120000 +7 halt 9 3120000 +7 halt 10 3120000 +7 halt 11 3130000 +7 halt 12 3110000 +7 halt 13 3110000 +7 halt 14 3130000 +7 halt 15 3110000 +7 halt 16 3110000 +7 halt 17 3120000 +7 halt 18 3120000 +7 halt 19 3120000 +7 halt 20 3140000 +7 halt 21 3120000 +7 halt 22 3120000 +7 halt 23 3130000 +7 halt 24 3110000 +7 halt 25 3140000 +7 halt 26 3130000 +7 halt 27 3120000 +7 halt 28 3120000 +7 halt 29 3120000 +7 halt 30 3110000 +# point pass=7 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998019 +7 run 1 3110000 +7 run 2 3120000 +7 run 3 3120000 +7 run 4 3120000 +7 run 5 3110000 +7 run 6 3120000 +7 run 7 3140000 +7 run 8 3110000 +7 run 9 3110000 +7 run 10 3120000 +7 run 11 3110000 +7 run 12 3110000 +7 run 13 3110000 +7 run 14 3110000 +7 run 15 3120000 +7 run 16 3120000 +7 run 17 3110000 +7 run 18 3120000 +7 run 19 3110000 +7 run 20 3110000 +7 run 21 3120000 +7 run 22 3130000 +7 run 23 3110000 +7 run 24 3110000 +7 run 25 3110000 +7 run 26 3110000 +7 run 27 3120000 +7 run 28 3110000 +7 run 29 3120000 +7 run 30 3140000 +# point pass=7 state=run jobs_per_s=94695.1 updates_per_s=33237983.0 clock_hz=99998016 +8 run 1 3120000 +8 run 2 3110000 +8 run 3 3120000 +8 run 4 3130000 +8 run 5 3110000 +8 run 6 3130000 +8 run 7 3130000 +8 run 8 3120000 +8 run 9 3120000 +8 run 10 3140000 +8 run 11 3120000 +8 run 12 3120000 +8 run 13 3110000 +8 run 14 3120000 +8 run 15 3110000 +8 run 16 3120000 +8 run 17 3120000 +8 run 18 3130000 +8 run 19 3140000 +8 run 20 3110000 +8 run 21 3120000 +8 run 22 3120000 +8 run 23 3110000 +8 run 24 3110000 +8 run 25 3110000 +8 run 26 3110000 +8 run 27 3140000 +8 run 28 3120000 +8 run 29 3120000 +8 run 30 3110000 +# point pass=8 state=run jobs_per_s=94695.1 updates_per_s=33237982.4 clock_hz=99998013 +8 halt 1 3090000 +8 halt 2 3110000 +8 halt 3 3110000 +8 halt 4 3100000 +8 halt 5 3110000 +8 halt 6 3110000 +8 halt 7 3120000 +8 halt 8 3110000 +8 halt 9 3110000 +8 halt 10 3110000 +8 halt 11 3110000 +8 halt 12 3110000 +8 halt 13 3110000 +8 halt 14 3100000 +8 halt 15 3120000 +8 halt 16 3120000 +8 halt 17 3110000 +8 halt 18 3110000 +8 halt 19 3110000 +8 halt 20 3110000 +8 halt 21 3120000 +8 halt 22 3110000 +8 halt 23 3110000 +8 halt 24 3120000 +8 halt 25 3100000 +8 halt 26 3110000 +8 halt 27 3100000 +8 halt 28 3100000 +8 halt 29 3100000 +8 halt 30 3110000 +# point pass=8 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998011 +# done SystemTime { tv_sec: 1793918155, tv_nsec: 266403554 } +# passes used 8 of 8 (dropped: []) +# run - halt = 3.8 +/- 3.8 mW (per-pass sd 10.6); 4/8 passes positive; 3 sample excursions beyond 6 MAD +# per-pass differences (mW): -10.0 0.0 20.0 10.0 0.0 10.0 -10.0 10.0 +# board power while running 3115 mW; jobs/s 94695.1; updates/s 33237983.4; measured PL clock 99.998 MHz +# pre-registered prediction 3.0 mW: measured/predicted = 1.25, 0.2 sigma from it diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/step.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/step.dat new file mode 100644 index 000000000..099a4918b --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/step.dat @@ -0,0 +1,610 @@ +# class t0-recall +# vqpu-edge meter passes=1 settle=0s samples=300 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793906728, tv_nsec: 609413995 } +# pass state sample power_uW +1 halt 1 3360000 +1 halt 2 3130000 +1 halt 3 3120000 +1 halt 4 3120000 +1 halt 5 3120000 +1 halt 6 3120000 +1 halt 7 3130000 +1 halt 8 3120000 +1 halt 9 3120000 +1 halt 10 3120000 +1 halt 11 3120000 +1 halt 12 3120000 +1 halt 13 3120000 +1 halt 14 3120000 +1 halt 15 3120000 +1 halt 16 3130000 +1 halt 17 3120000 +1 halt 18 3110000 +1 halt 19 3120000 +1 halt 20 3120000 +1 halt 21 3110000 +1 halt 22 3130000 +1 halt 23 3120000 +1 halt 24 3120000 +1 halt 25 3120000 +1 halt 26 3120000 +1 halt 27 3120000 +1 halt 28 3120000 +1 halt 29 3130000 +1 halt 30 3130000 +1 halt 31 3130000 +1 halt 32 3130000 +1 halt 33 3110000 +1 halt 34 3120000 +1 halt 35 3140000 +1 halt 36 3110000 +1 halt 37 3120000 +1 halt 38 3120000 +1 halt 39 3110000 +1 halt 40 3120000 +1 halt 41 3120000 +1 halt 42 3140000 +1 halt 43 3110000 +1 halt 44 3120000 +1 halt 45 3140000 +1 halt 46 3120000 +1 halt 47 3110000 +1 halt 48 3140000 +1 halt 49 3120000 +1 halt 50 3110000 +1 halt 51 3110000 +1 halt 52 3120000 +1 halt 53 3120000 +1 halt 54 3120000 +1 halt 55 3110000 +1 halt 56 3120000 +1 halt 57 3140000 +1 halt 58 3110000 +1 halt 59 3150000 +1 halt 60 3120000 +1 halt 61 3120000 +1 halt 62 3120000 +1 halt 63 3110000 +1 halt 64 3120000 +1 halt 65 3130000 +1 halt 66 3120000 +1 halt 67 3130000 +1 halt 68 3120000 +1 halt 69 3120000 +1 halt 70 3120000 +1 halt 71 3120000 +1 halt 72 3130000 +1 halt 73 3120000 +1 halt 74 3140000 +1 halt 75 3110000 +1 halt 76 3110000 +1 halt 77 3110000 +1 halt 78 3110000 +1 halt 79 3170000 +1 halt 80 3130000 +1 halt 81 3110000 +1 halt 82 3100000 +1 halt 83 3110000 +1 halt 84 3110000 +1 halt 85 3110000 +1 halt 86 3110000 +1 halt 87 3120000 +1 halt 88 3110000 +1 halt 89 3110000 +1 halt 90 3110000 +1 halt 91 3110000 +1 halt 92 3110000 +1 halt 93 3130000 +1 halt 94 3110000 +1 halt 95 3110000 +1 halt 96 3130000 +1 halt 97 3110000 +1 halt 98 3110000 +1 halt 99 3110000 +1 halt 100 3120000 +1 halt 101 3130000 +1 halt 102 3110000 +1 halt 103 3090000 +1 halt 104 3120000 +1 halt 105 3110000 +1 halt 106 3490000 +1 halt 107 3120000 +1 halt 108 3110000 +1 halt 109 3110000 +1 halt 110 3100000 +1 halt 111 3110000 +1 halt 112 3110000 +1 halt 113 3120000 +1 halt 114 3110000 +1 halt 115 3100000 +1 halt 116 3110000 +1 halt 117 3130000 +1 halt 118 3110000 +1 halt 119 3110000 +1 halt 120 3110000 +1 halt 121 3120000 +1 halt 122 3110000 +1 halt 123 3110000 +1 halt 124 3120000 +1 halt 125 3130000 +1 halt 126 3110000 +1 halt 127 3120000 +1 halt 128 3140000 +1 halt 129 3120000 +1 halt 130 3110000 +1 halt 131 3110000 +1 halt 132 3110000 +1 halt 133 3110000 +1 halt 134 3100000 +1 halt 135 3110000 +1 halt 136 3120000 +1 halt 137 3120000 +1 halt 138 3150000 +1 halt 139 3110000 +1 halt 140 3120000 +1 halt 141 3120000 +1 halt 142 3110000 +1 halt 143 3130000 +1 halt 144 3110000 +1 halt 145 3140000 +1 halt 146 3110000 +1 halt 147 3120000 +1 halt 148 3120000 +1 halt 149 3110000 +1 halt 150 3120000 +1 halt 151 3120000 +1 halt 152 3130000 +1 halt 153 3120000 +1 halt 154 3120000 +1 halt 155 3140000 +1 halt 156 3120000 +1 halt 157 3120000 +1 halt 158 3120000 +1 halt 159 3120000 +1 halt 160 3120000 +1 halt 161 3120000 +1 halt 162 3130000 +1 halt 163 3130000 +1 halt 164 3130000 +1 halt 165 3110000 +1 halt 166 3110000 +1 halt 167 3120000 +1 halt 168 3120000 +1 halt 169 3120000 +1 halt 170 3120000 +1 halt 171 3120000 +1 halt 172 3150000 +1 halt 173 3110000 +1 halt 174 3120000 +1 halt 175 3120000 +1 halt 176 3120000 +1 halt 177 3120000 +1 halt 178 3120000 +1 halt 179 3140000 +1 halt 180 3120000 +1 halt 181 3120000 +1 halt 182 3110000 +1 halt 183 3140000 +1 halt 184 3110000 +1 halt 185 3120000 +1 halt 186 3120000 +1 halt 187 3120000 +1 halt 188 3120000 +1 halt 189 3120000 +1 halt 190 3130000 +1 halt 191 3120000 +1 halt 192 3120000 +1 halt 193 3110000 +1 halt 194 3120000 +1 halt 195 3120000 +1 halt 196 3120000 +1 halt 197 3110000 +1 halt 198 3110000 +1 halt 199 3110000 +1 halt 200 3130000 +1 halt 201 3130000 +1 halt 202 3110000 +1 halt 203 3110000 +1 halt 204 3120000 +1 halt 205 3110000 +1 halt 206 3110000 +1 halt 207 3130000 +1 halt 208 3110000 +1 halt 209 3110000 +1 halt 210 3110000 +1 halt 211 3110000 +1 halt 212 3110000 +1 halt 213 3120000 +1 halt 214 3110000 +1 halt 215 3110000 +1 halt 216 3120000 +1 halt 217 3120000 +1 halt 218 3110000 +1 halt 219 3110000 +1 halt 220 3110000 +1 halt 221 3110000 +1 halt 222 3110000 +1 halt 223 3110000 +1 halt 224 3110000 +1 halt 225 3110000 +1 halt 226 3110000 +1 halt 227 3110000 +1 halt 228 3110000 +1 halt 229 3110000 +1 halt 230 3120000 +1 halt 231 3120000 +1 halt 232 3110000 +1 halt 233 3110000 +1 halt 234 3100000 +1 halt 235 3110000 +1 halt 236 3110000 +1 halt 237 3100000 +1 halt 238 3100000 +1 halt 239 3120000 +1 halt 240 3120000 +1 halt 241 3110000 +1 halt 242 3110000 +1 halt 243 3110000 +1 halt 244 3110000 +1 halt 245 3100000 +1 halt 246 3100000 +1 halt 247 3110000 +1 halt 248 3120000 +1 halt 249 3100000 +1 halt 250 3110000 +1 halt 251 3110000 +1 halt 252 3100000 +1 halt 253 3110000 +1 halt 254 3110000 +1 halt 255 3110000 +1 halt 256 3110000 +1 halt 257 3100000 +1 halt 258 3110000 +1 halt 259 3110000 +1 halt 260 3110000 +1 halt 261 3120000 +1 halt 262 3120000 +1 halt 263 3140000 +1 halt 264 3120000 +1 halt 265 3120000 +1 halt 266 3100000 +1 halt 267 3120000 +1 halt 268 3110000 +1 halt 269 3120000 +1 halt 270 3110000 +1 halt 271 3140000 +1 halt 272 3140000 +1 halt 273 3120000 +1 halt 274 3110000 +1 halt 275 3120000 +1 halt 276 3120000 +1 halt 277 3110000 +1 halt 278 3110000 +1 halt 279 3110000 +1 halt 280 3140000 +1 halt 281 3110000 +1 halt 282 3110000 +1 halt 283 3110000 +1 halt 284 3120000 +1 halt 285 3110000 +1 halt 286 3110000 +1 halt 287 3120000 +1 halt 288 3120000 +1 halt 289 3110000 +1 halt 290 3110000 +1 halt 291 3110000 +1 halt 292 3120000 +1 halt 293 3120000 +1 halt 294 3110000 +1 halt 295 3120000 +1 halt 296 3120000 +1 halt 297 3110000 +1 halt 298 3110000 +1 halt 299 3130000 +1 halt 300 3120000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997939 +1 run 1 3490000 +1 run 2 3260000 +1 run 3 3260000 +1 run 4 3260000 +1 run 5 3280000 +1 run 6 3270000 +1 run 7 3260000 +1 run 8 3260000 +1 run 9 3270000 +1 run 10 3260000 +1 run 11 3260000 +1 run 12 3260000 +1 run 13 3260000 +1 run 14 3270000 +1 run 15 3290000 +1 run 16 3260000 +1 run 17 3260000 +1 run 18 3260000 +1 run 19 3260000 +1 run 20 3280000 +1 run 21 3260000 +1 run 22 3260000 +1 run 23 3270000 +1 run 24 3250000 +1 run 25 3250000 +1 run 26 3250000 +1 run 27 3250000 +1 run 28 3260000 +1 run 29 3280000 +1 run 30 3260000 +1 run 31 3250000 +1 run 32 3260000 +1 run 33 3250000 +1 run 34 3260000 +1 run 35 3250000 +1 run 36 3260000 +1 run 37 3250000 +1 run 38 3250000 +1 run 39 3250000 +1 run 40 3250000 +1 run 41 3250000 +1 run 42 3250000 +1 run 43 3250000 +1 run 44 3260000 +1 run 45 3250000 +1 run 46 3250000 +1 run 47 3250000 +1 run 48 3260000 +1 run 49 3250000 +1 run 50 3250000 +1 run 51 3250000 +1 run 52 3280000 +1 run 53 3260000 +1 run 54 3260000 +1 run 55 3260000 +1 run 56 3260000 +1 run 57 3260000 +1 run 58 3250000 +1 run 59 3260000 +1 run 60 3250000 +1 run 61 3260000 +1 run 62 3250000 +1 run 63 3260000 +1 run 64 3310000 +1 run 65 3260000 +1 run 66 3250000 +1 run 67 3250000 +1 run 68 3260000 +1 run 69 3250000 +1 run 70 3250000 +1 run 71 3250000 +1 run 72 3250000 +1 run 73 3250000 +1 run 74 3250000 +1 run 75 3250000 +1 run 76 3270000 +1 run 77 3250000 +1 run 78 3250000 +1 run 79 3250000 +1 run 80 3250000 +1 run 81 3250000 +1 run 82 3260000 +1 run 83 3280000 +1 run 84 3280000 +1 run 85 3280000 +1 run 86 3280000 +1 run 87 3270000 +1 run 88 3260000 +1 run 89 3260000 +1 run 90 3250000 +1 run 91 3270000 +1 run 92 3260000 +1 run 93 3280000 +1 run 94 3280000 +1 run 95 3260000 +1 run 96 3260000 +1 run 97 3270000 +1 run 98 3260000 +1 run 99 3270000 +1 run 100 3260000 +1 run 101 3260000 +1 run 102 3270000 +1 run 103 3260000 +1 run 104 3260000 +1 run 105 3250000 +1 run 106 3260000 +1 run 107 3260000 +1 run 108 3280000 +1 run 109 3260000 +1 run 110 3260000 +1 run 111 3260000 +1 run 112 3270000 +1 run 113 3280000 +1 run 114 3270000 +1 run 115 3260000 +1 run 116 3290000 +1 run 117 3280000 +1 run 118 3260000 +1 run 119 3260000 +1 run 120 3270000 +1 run 121 3260000 +1 run 122 3270000 +1 run 123 3260000 +1 run 124 3260000 +1 run 125 3270000 +1 run 126 3250000 +1 run 127 3500000 +1 run 128 3260000 +1 run 129 3260000 +1 run 130 3260000 +1 run 131 3270000 +1 run 132 3460000 +1 run 133 3260000 +1 run 134 3260000 +1 run 135 3260000 +1 run 136 3280000 +1 run 137 3260000 +1 run 138 3260000 +1 run 139 3280000 +1 run 140 3280000 +1 run 141 3260000 +1 run 142 3260000 +1 run 143 3260000 +1 run 144 3270000 +1 run 145 3270000 +1 run 146 3260000 +1 run 147 3250000 +1 run 148 3280000 +1 run 149 3260000 +1 run 150 3260000 +1 run 151 3260000 +1 run 152 3260000 +1 run 153 3260000 +1 run 154 3250000 +1 run 155 3260000 +1 run 156 3260000 +1 run 157 3260000 +1 run 158 3260000 +1 run 159 3260000 +1 run 160 3260000 +1 run 161 3260000 +1 run 162 3260000 +1 run 163 3280000 +1 run 164 3260000 +1 run 165 3270000 +1 run 166 3260000 +1 run 167 3260000 +1 run 168 3260000 +1 run 169 3260000 +1 run 170 3260000 +1 run 171 3290000 +1 run 172 3290000 +1 run 173 3260000 +1 run 174 3270000 +1 run 175 3260000 +1 run 176 3260000 +1 run 177 3260000 +1 run 178 3270000 +1 run 179 3260000 +1 run 180 3280000 +1 run 181 3260000 +1 run 182 3260000 +1 run 183 3260000 +1 run 184 3270000 +1 run 185 3260000 +1 run 186 3260000 +1 run 187 3260000 +1 run 188 3270000 +1 run 189 3260000 +1 run 190 3260000 +1 run 191 3260000 +1 run 192 3260000 +1 run 193 3260000 +1 run 194 3250000 +1 run 195 3280000 +1 run 196 3260000 +1 run 197 3260000 +1 run 198 3260000 +1 run 199 3270000 +1 run 200 3260000 +1 run 201 3260000 +1 run 202 3260000 +1 run 203 3290000 +1 run 204 3280000 +1 run 205 3260000 +1 run 206 3250000 +1 run 207 3280000 +1 run 208 3260000 +1 run 209 3260000 +1 run 210 3260000 +1 run 211 3260000 +1 run 212 3260000 +1 run 213 3260000 +1 run 214 3270000 +1 run 215 3270000 +1 run 216 3250000 +1 run 217 3250000 +1 run 218 3280000 +1 run 219 3260000 +1 run 220 3280000 +1 run 221 3250000 +1 run 222 3250000 +1 run 223 3260000 +1 run 224 3270000 +1 run 225 3260000 +1 run 226 3270000 +1 run 227 3280000 +1 run 228 3260000 +1 run 229 3260000 +1 run 230 3260000 +1 run 231 3260000 +1 run 232 3270000 +1 run 233 3260000 +1 run 234 3260000 +1 run 235 3280000 +1 run 236 3260000 +1 run 237 3260000 +1 run 238 3260000 +1 run 239 3260000 +1 run 240 3260000 +1 run 241 3260000 +1 run 242 3260000 +1 run 243 3250000 +1 run 244 3260000 +1 run 245 3260000 +1 run 246 3260000 +1 run 247 3260000 +1 run 248 3260000 +1 run 249 3280000 +1 run 250 3270000 +1 run 251 3260000 +1 run 252 3260000 +1 run 253 3260000 +1 run 254 3260000 +1 run 255 3260000 +1 run 256 3260000 +1 run 257 3270000 +1 run 258 3280000 +1 run 259 3290000 +1 run 260 3260000 +1 run 261 3260000 +1 run 262 3260000 +1 run 263 3260000 +1 run 264 3260000 +1 run 265 3260000 +1 run 266 3260000 +1 run 267 3270000 +1 run 268 3260000 +1 run 269 3260000 +1 run 270 3260000 +1 run 271 3260000 +1 run 272 3250000 +1 run 273 3260000 +1 run 274 3270000 +1 run 275 3260000 +1 run 276 3260000 +1 run 277 3260000 +1 run 278 3260000 +1 run 279 3260000 +1 run 280 3290000 +1 run 281 3250000 +1 run 282 3280000 +1 run 283 3260000 +1 run 284 3270000 +1 run 285 3260000 +1 run 286 3250000 +1 run 287 3260000 +1 run 288 3260000 +1 run 289 3260000 +1 run 290 3280000 +1 run 291 3260000 +1 run 292 3250000 +1 run 293 3260000 +1 run 294 3270000 +1 run 295 3250000 +1 run 296 3260000 +1 run 297 3260000 +1 run 298 3260000 +1 run 299 3260000 +1 run 300 3260000 +# point pass=1 state=run jobs_per_s=12499749.7 updates_per_s=0.0 clock_hz=99997996 +# done SystemTime { tv_sec: 1793907328, tv_nsec: 966768242 } +# passes used 1 of 1 (dropped: []) +# run - halt = 140.0 +/- NaN mW (per-pass sd NaN); 1/1 passes positive; 6 sample excursions beyond 6 MAD +# per-pass differences (mW): 140.0 +# board power while running 3260 mW; jobs/s 12499749.7; updates/s 0.0; measured PL clock 99.998 MHz diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/t0-idle.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/t0-idle.dat new file mode 100644 index 000000000..dd89dc6cb --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/t0-idle.dat @@ -0,0 +1,505 @@ +# class t0-idle +# vqpu-edge meter passes=8 settle=60s samples=30 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793915273, tv_nsec: 378650480 } +# pass state sample power_uW +1 run 1 3110000 +1 run 2 3110000 +1 run 3 3120000 +1 run 4 3120000 +1 run 5 3110000 +1 run 6 3110000 +1 run 7 3130000 +1 run 8 3120000 +1 run 9 3110000 +1 run 10 3110000 +1 run 11 3110000 +1 run 12 3110000 +1 run 13 3110000 +1 run 14 3170000 +1 run 15 3120000 +1 run 16 3110000 +1 run 17 3110000 +1 run 18 3120000 +1 run 19 3120000 +1 run 20 3180000 +1 run 21 3130000 +1 run 22 3130000 +1 run 23 3120000 +1 run 24 3110000 +1 run 25 3110000 +1 run 26 3110000 +1 run 27 3110000 +1 run 28 3100000 +1 run 29 3110000 +1 run 30 3120000 +# point pass=1 state=run jobs_per_s=33332741.4 updates_per_s=0.0 clock_hz=99998201 +1 halt 1 3140000 +1 halt 2 3110000 +1 halt 3 3110000 +1 halt 4 3110000 +1 halt 5 3130000 +1 halt 6 3110000 +1 halt 7 3110000 +1 halt 8 3110000 +1 halt 9 3110000 +1 halt 10 3110000 +1 halt 11 3110000 +1 halt 12 3110000 +1 halt 13 3130000 +1 halt 14 3110000 +1 halt 15 3110000 +1 halt 16 3110000 +1 halt 17 3110000 +1 halt 18 3120000 +1 halt 19 3120000 +1 halt 20 3120000 +1 halt 21 3110000 +1 halt 22 3110000 +1 halt 23 3110000 +1 halt 24 3100000 +1 halt 25 3120000 +1 halt 26 3110000 +1 halt 27 3140000 +1 halt 28 3110000 +1 halt 29 3120000 +1 halt 30 3120000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998166 +2 run 1 3120000 +2 run 2 3130000 +2 run 3 3120000 +2 run 4 3130000 +2 run 5 3130000 +2 run 6 3120000 +2 run 7 3140000 +2 run 8 3120000 +2 run 9 3120000 +2 run 10 3120000 +2 run 11 3130000 +2 run 12 3120000 +2 run 13 3140000 +2 run 14 3150000 +2 run 15 3130000 +2 run 16 3140000 +2 run 17 3120000 +2 run 18 3110000 +2 run 19 3120000 +2 run 20 3110000 +2 run 21 3120000 +2 run 22 3120000 +2 run 23 3110000 +2 run 24 3140000 +2 run 25 3120000 +2 run 26 3120000 +2 run 27 3120000 +2 run 28 3110000 +2 run 29 3120000 +2 run 30 3110000 +# point pass=2 state=run jobs_per_s=33332720.0 updates_per_s=0.0 clock_hz=99998138 +2 halt 1 3110000 +2 halt 2 3110000 +2 halt 3 3110000 +2 halt 4 3140000 +2 halt 5 3100000 +2 halt 6 3110000 +2 halt 7 3120000 +2 halt 8 3110000 +2 halt 9 3120000 +2 halt 10 3120000 +2 halt 11 3110000 +2 halt 12 3120000 +2 halt 13 3120000 +2 halt 14 3110000 +2 halt 15 3110000 +2 halt 16 3100000 +2 halt 17 3110000 +2 halt 18 3110000 +2 halt 19 3100000 +2 halt 20 3110000 +2 halt 21 3110000 +2 halt 22 3110000 +2 halt 23 3270000 +2 halt 24 3110000 +2 halt 25 3110000 +2 halt 26 3100000 +2 halt 27 3120000 +2 halt 28 3460000 +2 halt 29 3110000 +2 halt 30 3110000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998114 +3 halt 1 3120000 +3 halt 2 3110000 +3 halt 3 3110000 +3 halt 4 3100000 +3 halt 5 3110000 +3 halt 6 3110000 +3 halt 7 3100000 +3 halt 8 3100000 +3 halt 9 3150000 +3 halt 10 3110000 +3 halt 11 3100000 +3 halt 12 3100000 +3 halt 13 3110000 +3 halt 14 3100000 +3 halt 15 3110000 +3 halt 16 3110000 +3 halt 17 3110000 +3 halt 18 3100000 +3 halt 19 3110000 +3 halt 20 3120000 +3 halt 21 3120000 +3 halt 22 3120000 +3 halt 23 3110000 +3 halt 24 3150000 +3 halt 25 3110000 +3 halt 26 3120000 +3 halt 27 3120000 +3 halt 28 3110000 +3 halt 29 3110000 +3 halt 30 3120000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998094 +3 run 1 3110000 +3 run 2 3120000 +3 run 3 3120000 +3 run 4 3110000 +3 run 5 3120000 +3 run 6 3140000 +3 run 7 3110000 +3 run 8 3110000 +3 run 9 3120000 +3 run 10 3110000 +3 run 11 3120000 +3 run 12 3120000 +3 run 13 3120000 +3 run 14 3120000 +3 run 15 3110000 +3 run 16 3120000 +3 run 17 3120000 +3 run 18 3120000 +3 run 19 3120000 +3 run 20 3120000 +3 run 21 3140000 +3 run 22 3110000 +3 run 23 3110000 +3 run 24 3120000 +3 run 25 3110000 +3 run 26 3120000 +3 run 27 3120000 +3 run 28 3110000 +3 run 29 3140000 +3 run 30 3140000 +# point pass=3 state=run jobs_per_s=33332700.4 updates_per_s=0.0 clock_hz=99998079 +4 run 1 3110000 +4 run 2 3110000 +4 run 3 3130000 +4 run 4 3110000 +4 run 5 3120000 +4 run 6 3110000 +4 run 7 3110000 +4 run 8 3110000 +4 run 9 3110000 +4 run 10 3110000 +4 run 11 3120000 +4 run 12 3110000 +4 run 13 3130000 +4 run 14 3120000 +4 run 15 3120000 +4 run 16 3110000 +4 run 17 3130000 +4 run 18 3130000 +4 run 19 3110000 +4 run 20 3110000 +4 run 21 3120000 +4 run 22 3100000 +4 run 23 3120000 +4 run 24 3120000 +4 run 25 3120000 +4 run 26 3130000 +4 run 27 3110000 +4 run 28 3110000 +4 run 29 3120000 +4 run 30 3110000 +# point pass=4 state=run jobs_per_s=33332695.3 updates_per_s=0.0 clock_hz=99998064 +4 halt 1 3100000 +4 halt 2 3110000 +4 halt 3 3100000 +4 halt 4 3110000 +4 halt 5 3110000 +4 halt 6 3120000 +4 halt 7 3110000 +4 halt 8 3110000 +4 halt 9 3100000 +4 halt 10 3110000 +4 halt 11 3100000 +4 halt 12 3110000 +4 halt 13 3100000 +4 halt 14 3120000 +4 halt 15 3110000 +4 halt 16 3110000 +4 halt 17 3110000 +4 halt 18 3110000 +4 halt 19 3110000 +4 halt 20 3100000 +4 halt 21 3110000 +4 halt 22 3110000 +4 halt 23 3120000 +4 halt 24 3100000 +4 halt 25 3110000 +4 halt 26 3110000 +4 halt 27 3090000 +4 halt 28 3100000 +4 halt 29 3090000 +4 halt 30 3110000 +# point pass=4 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998052 +5 run 1 3140000 +5 run 2 3120000 +5 run 3 3110000 +5 run 4 3110000 +5 run 5 3120000 +5 run 6 3140000 +5 run 7 3120000 +5 run 8 3110000 +5 run 9 3110000 +5 run 10 3110000 +5 run 11 3110000 +5 run 12 3110000 +5 run 13 3120000 +5 run 14 3120000 +5 run 15 3130000 +5 run 16 3120000 +5 run 17 3110000 +5 run 18 3120000 +5 run 19 3120000 +5 run 20 3110000 +5 run 21 3110000 +5 run 22 3110000 +5 run 23 3130000 +5 run 24 3110000 +5 run 25 3110000 +5 run 26 3120000 +5 run 27 3120000 +5 run 28 3120000 +5 run 29 3110000 +5 run 30 3110000 +# point pass=5 state=run jobs_per_s=33332688.2 updates_per_s=0.0 clock_hz=99998042 +5 halt 1 3110000 +5 halt 2 3120000 +5 halt 3 3130000 +5 halt 4 3110000 +5 halt 5 3110000 +5 halt 6 3100000 +5 halt 7 3100000 +5 halt 8 3110000 +5 halt 9 3110000 +5 halt 10 3120000 +5 halt 11 3120000 +5 halt 12 3110000 +5 halt 13 3110000 +5 halt 14 3120000 +5 halt 15 3110000 +5 halt 16 3100000 +5 halt 17 3110000 +5 halt 18 3120000 +5 halt 19 3110000 +5 halt 20 3100000 +5 halt 21 3110000 +5 halt 22 3110000 +5 halt 23 3110000 +5 halt 24 3110000 +5 halt 25 3110000 +5 halt 26 3120000 +5 halt 27 3110000 +5 halt 28 3110000 +5 halt 29 3110000 +5 halt 30 3110000 +# point pass=5 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998034 +6 halt 1 3120000 +6 halt 2 3110000 +6 halt 3 3110000 +6 halt 4 3110000 +6 halt 5 3110000 +6 halt 6 3110000 +6 halt 7 3120000 +6 halt 8 3140000 +6 halt 9 3110000 +6 halt 10 3120000 +6 halt 11 3110000 +6 halt 12 3110000 +6 halt 13 3110000 +6 halt 14 3110000 +6 halt 15 3110000 +6 halt 16 3120000 +6 halt 17 3120000 +6 halt 18 3110000 +6 halt 19 3110000 +6 halt 20 3120000 +6 halt 21 3120000 +6 halt 22 3100000 +6 halt 23 3130000 +6 halt 24 3110000 +6 halt 25 3110000 +6 halt 26 3110000 +6 halt 27 3110000 +6 halt 28 3110000 +6 halt 29 3110000 +6 halt 30 3110000 +# point pass=6 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998028 +6 run 1 3110000 +6 run 2 3110000 +6 run 3 3110000 +6 run 4 3120000 +6 run 5 3130000 +6 run 6 3110000 +6 run 7 3110000 +6 run 8 3110000 +6 run 9 3110000 +6 run 10 3110000 +6 run 11 3120000 +6 run 12 3110000 +6 run 13 3120000 +6 run 14 3110000 +6 run 15 3110000 +6 run 16 3120000 +6 run 17 3120000 +6 run 18 3110000 +6 run 19 3110000 +6 run 20 3140000 +6 run 21 3120000 +6 run 22 3120000 +6 run 23 3120000 +6 run 24 3110000 +6 run 25 3120000 +6 run 26 3120000 +6 run 27 3110000 +6 run 28 3140000 +6 run 29 3120000 +6 run 30 3120000 +# point pass=6 state=run jobs_per_s=33332681.5 updates_per_s=0.0 clock_hz=99998021 +7 run 1 3110000 +7 run 2 3110000 +7 run 3 3110000 +7 run 4 3110000 +7 run 5 3110000 +7 run 6 3110000 +7 run 7 3110000 +7 run 8 3120000 +7 run 9 3110000 +7 run 10 3110000 +7 run 11 3110000 +7 run 12 3110000 +7 run 13 3110000 +7 run 14 3100000 +7 run 15 3100000 +7 run 16 3120000 +7 run 17 3120000 +7 run 18 3110000 +7 run 19 3100000 +7 run 20 3110000 +7 run 21 3110000 +7 run 22 3120000 +7 run 23 3110000 +7 run 24 3110000 +7 run 25 3140000 +7 run 26 3110000 +7 run 27 3100000 +7 run 28 3110000 +7 run 29 3110000 +7 run 30 3110000 +# point pass=7 state=run jobs_per_s=33332680.2 updates_per_s=0.0 clock_hz=99998017 +7 halt 1 3110000 +7 halt 2 3110000 +7 halt 3 3110000 +7 halt 4 3130000 +7 halt 5 3130000 +7 halt 6 3110000 +7 halt 7 3110000 +7 halt 8 3120000 +7 halt 9 3110000 +7 halt 10 3120000 +7 halt 11 3110000 +7 halt 12 3100000 +7 halt 13 3130000 +7 halt 14 3130000 +7 halt 15 3100000 +7 halt 16 3110000 +7 halt 17 3120000 +7 halt 18 3120000 +7 halt 19 3120000 +7 halt 20 3110000 +7 halt 21 3110000 +7 halt 22 3140000 +7 halt 23 3110000 +7 halt 24 3110000 +7 halt 25 3110000 +7 halt 26 3110000 +7 halt 27 3120000 +7 halt 28 3120000 +7 halt 29 3120000 +7 halt 30 3110000 +# point pass=7 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998014 +8 run 1 3110000 +8 run 2 3130000 +8 run 3 3110000 +8 run 4 3110000 +8 run 5 3110000 +8 run 6 3110000 +8 run 7 3110000 +8 run 8 3110000 +8 run 9 3110000 +8 run 10 3130000 +8 run 11 3110000 +8 run 12 3110000 +8 run 13 3110000 +8 run 14 3110000 +8 run 15 3120000 +8 run 16 3110000 +8 run 17 3110000 +8 run 18 3110000 +8 run 19 3110000 +8 run 20 3120000 +8 run 21 3110000 +8 run 22 3110000 +8 run 23 3110000 +8 run 24 3110000 +8 run 25 3130000 +8 run 26 3120000 +8 run 27 3110000 +8 run 28 3120000 +8 run 29 3110000 +8 run 30 3130000 +# point pass=8 state=run jobs_per_s=33332678.3 updates_per_s=0.0 clock_hz=99998009 +8 halt 1 3110000 +8 halt 2 3110000 +8 halt 3 3110000 +8 halt 4 3110000 +8 halt 5 3110000 +8 halt 6 3110000 +8 halt 7 3120000 +8 halt 8 3120000 +8 halt 9 3110000 +8 halt 10 3100000 +8 halt 11 3110000 +8 halt 12 3110000 +8 halt 13 3110000 +8 halt 14 3110000 +8 halt 15 3110000 +8 halt 16 3110000 +8 halt 17 3100000 +8 halt 18 3100000 +8 halt 19 3110000 +8 halt 20 3110000 +8 halt 21 3120000 +8 halt 22 3130000 +8 halt 23 3110000 +8 halt 24 3110000 +8 halt 25 3110000 +8 halt 26 3110000 +8 halt 27 3110000 +8 halt 28 3110000 +8 halt 29 3110000 +8 halt 30 3140000 +# point pass=8 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998006 +# done SystemTime { tv_sec: 1793916714, tv_nsec: 281430358 } +# passes used 8 of 8 (dropped: []) +# run - halt = 3.8 +/- 1.6 mW (per-pass sd 4.4); 4/8 passes positive; 4 sample excursions beyond 6 MAD +# per-pass differences (mW): 0.0 10.0 10.0 0.0 5.0 5.0 0.0 0.0 +# board power while running 3114 mW; jobs/s 33332698.2; updates/s 0.0; measured PL clock 99.998 MHz +# pre-registered prediction 1.0 mW: measured/predicted = 3.75, 1.8 sigma from it diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/t0-recall-4core.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/t0-recall-4core.dat new file mode 100644 index 000000000..52aed011c --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/t0-recall-4core.dat @@ -0,0 +1,754 @@ +# class t0-recall cores 4 +# vqpu-edge meter passes=12 settle=60s samples=30 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793920187, tv_nsec: 861113367 } +# pass state sample power_uW +1 halt 1 3250000 +1 halt 2 3250000 +1 halt 3 3250000 +1 halt 4 3250000 +1 halt 5 3250000 +1 halt 6 3280000 +1 halt 7 3250000 +1 halt 8 3250000 +1 halt 9 3260000 +1 halt 10 3260000 +1 halt 11 3250000 +1 halt 12 3260000 +1 halt 13 3240000 +1 halt 14 3260000 +1 halt 15 3240000 +1 halt 16 3250000 +1 halt 17 3250000 +1 halt 18 3250000 +1 halt 19 3250000 +1 halt 20 3240000 +1 halt 21 3240000 +1 halt 22 3250000 +1 halt 23 3250000 +1 halt 24 3250000 +1 halt 25 3250000 +1 halt 26 3240000 +1 halt 27 3260000 +1 halt 28 3250000 +1 halt 29 3260000 +1 halt 30 3250000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997938 +1 run 1 3840000 +1 run 2 3820000 +1 run 3 3840000 +1 run 4 3850000 +1 run 5 3830000 +1 run 6 3840000 +1 run 7 3830000 +1 run 8 4070000 +1 run 9 3830000 +1 run 10 3830000 +1 run 11 3830000 +1 run 12 3830000 +1 run 13 3840000 +1 run 14 3830000 +1 run 15 3840000 +1 run 16 3830000 +1 run 17 3840000 +1 run 18 3850000 +1 run 19 3830000 +1 run 20 3840000 +1 run 21 3830000 +1 run 22 3830000 +1 run 23 3830000 +1 run 24 3840000 +1 run 25 3840000 +1 run 26 3820000 +1 run 27 3830000 +1 run 28 3840000 +1 run 29 3850000 +1 run 30 3830000 +# point pass=1 state=run jobs_per_s=12499746.0 updates_per_s=0.0 clock_hz=99997944 +2 halt 1 3260000 +2 halt 2 3260000 +2 halt 3 3260000 +2 halt 4 3260000 +2 halt 5 3250000 +2 halt 6 3250000 +2 halt 7 3260000 +2 halt 8 3250000 +2 halt 9 3260000 +2 halt 10 3260000 +2 halt 11 3270000 +2 halt 12 3260000 +2 halt 13 3250000 +2 halt 14 3260000 +2 halt 15 3260000 +2 halt 16 3260000 +2 halt 17 3260000 +2 halt 18 3250000 +2 halt 19 3280000 +2 halt 20 3250000 +2 halt 21 3260000 +2 halt 22 3250000 +2 halt 23 3250000 +2 halt 24 3260000 +2 halt 25 3260000 +2 halt 26 3260000 +2 halt 27 3260000 +2 halt 28 3260000 +2 halt 29 3260000 +2 halt 30 3260000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997946 +2 run 1 3840000 +2 run 2 3830000 +2 run 3 3840000 +2 run 4 3840000 +2 run 5 3850000 +2 run 6 3840000 +2 run 7 3850000 +2 run 8 3830000 +2 run 9 3840000 +2 run 10 3850000 +2 run 11 3910000 +2 run 12 3830000 +2 run 13 3840000 +2 run 14 3840000 +2 run 15 3840000 +2 run 16 3830000 +2 run 17 3850000 +2 run 18 3840000 +2 run 19 3830000 +2 run 20 3850000 +2 run 21 3840000 +2 run 22 3840000 +2 run 23 3840000 +2 run 24 3840000 +2 run 25 3850000 +2 run 26 3840000 +2 run 27 3840000 +2 run 28 3850000 +2 run 29 3840000 +2 run 30 3840000 +# point pass=2 state=run jobs_per_s=12499746.6 updates_per_s=0.0 clock_hz=99997951 +3 halt 1 3240000 +3 halt 2 3250000 +3 halt 3 3250000 +3 halt 4 3250000 +3 halt 5 3250000 +3 halt 6 3240000 +3 halt 7 3250000 +3 halt 8 3250000 +3 halt 9 3250000 +3 halt 10 3250000 +3 halt 11 3240000 +3 halt 12 3240000 +3 halt 13 3250000 +3 halt 14 3250000 +3 halt 15 3250000 +3 halt 16 3260000 +3 halt 17 3260000 +3 halt 18 3250000 +3 halt 19 3250000 +3 halt 20 3270000 +3 halt 21 3250000 +3 halt 22 3270000 +3 halt 23 3240000 +3 halt 24 3250000 +3 halt 25 3250000 +3 halt 26 3240000 +3 halt 27 3250000 +3 halt 28 3250000 +3 halt 29 3240000 +3 halt 30 3250000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997953 +3 run 1 3850000 +3 run 2 3830000 +3 run 3 3840000 +3 run 4 3830000 +3 run 5 3850000 +3 run 6 3870000 +3 run 7 3840000 +3 run 8 3830000 +3 run 9 3840000 +3 run 10 3840000 +3 run 11 3820000 +3 run 12 3840000 +3 run 13 3840000 +3 run 14 3860000 +3 run 15 3830000 +3 run 16 3840000 +3 run 17 3830000 +3 run 18 3830000 +3 run 19 3840000 +3 run 20 3830000 +3 run 21 3830000 +3 run 22 3860000 +3 run 23 3830000 +3 run 24 3840000 +3 run 25 3840000 +3 run 26 3830000 +3 run 27 3840000 +3 run 28 3830000 +3 run 29 3840000 +3 run 30 3850000 +# point pass=3 state=run jobs_per_s=12499747.2 updates_per_s=0.0 clock_hz=99997955 +4 run 1 3830000 +4 run 2 3840000 +4 run 3 3830000 +4 run 4 3830000 +4 run 5 3830000 +4 run 6 3840000 +4 run 7 3830000 +4 run 8 3820000 +4 run 9 3820000 +4 run 10 3820000 +4 run 11 3830000 +4 run 12 3820000 +4 run 13 3830000 +4 run 14 3850000 +4 run 15 3830000 +4 run 16 3820000 +4 run 17 3840000 +4 run 18 3830000 +4 run 19 3830000 +4 run 20 3820000 +4 run 21 3830000 +4 run 22 3840000 +4 run 23 3820000 +4 run 24 3830000 +4 run 25 3840000 +4 run 26 3840000 +4 run 27 3820000 +4 run 28 3830000 +4 run 29 3820000 +4 run 30 3820000 +# point pass=4 state=run jobs_per_s=12499747.5 updates_per_s=0.0 clock_hz=99997957 +4 halt 1 3240000 +4 halt 2 3240000 +4 halt 3 3240000 +4 halt 4 3230000 +4 halt 5 3240000 +4 halt 6 3240000 +4 halt 7 3240000 +4 halt 8 3250000 +4 halt 9 3250000 +4 halt 10 3240000 +4 halt 11 3240000 +4 halt 12 3240000 +4 halt 13 3230000 +4 halt 14 3250000 +4 halt 15 3240000 +4 halt 16 3240000 +4 halt 17 3230000 +4 halt 18 3240000 +4 halt 19 3230000 +4 halt 20 3240000 +4 halt 21 3240000 +4 halt 22 3260000 +4 halt 23 3250000 +4 halt 24 3240000 +4 halt 25 3230000 +4 halt 26 3240000 +4 halt 27 3250000 +4 halt 28 3240000 +4 halt 29 3240000 +4 halt 30 3240000 +# point pass=4 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997959 +5 halt 1 3250000 +5 halt 2 3240000 +5 halt 3 3250000 +5 halt 4 3250000 +5 halt 5 3240000 +5 halt 6 3250000 +5 halt 7 3230000 +5 halt 8 3240000 +5 halt 9 3250000 +5 halt 10 3250000 +5 halt 11 3260000 +5 halt 12 3240000 +5 halt 13 3250000 +5 halt 14 3240000 +5 halt 15 3240000 +5 halt 16 3240000 +5 halt 17 3250000 +5 halt 18 3240000 +5 halt 19 3270000 +5 halt 20 3250000 +5 halt 21 3240000 +5 halt 22 3240000 +5 halt 23 3250000 +5 halt 24 3250000 +5 halt 25 3250000 +5 halt 26 3250000 +5 halt 27 3260000 +5 halt 28 3240000 +5 halt 29 3250000 +5 halt 30 3240000 +# point pass=5 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997960 +5 run 1 3830000 +5 run 2 3830000 +5 run 3 3840000 +5 run 4 3840000 +5 run 5 3830000 +5 run 6 3830000 +5 run 7 3850000 +5 run 8 3840000 +5 run 9 3820000 +5 run 10 3830000 +5 run 11 3840000 +5 run 12 3830000 +5 run 13 3840000 +5 run 14 3830000 +5 run 15 3830000 +5 run 16 3840000 +5 run 17 3830000 +5 run 18 3910000 +5 run 19 3830000 +5 run 20 3830000 +5 run 21 3830000 +5 run 22 3830000 +5 run 23 4190000 +5 run 24 3830000 +5 run 25 3830000 +5 run 26 3840000 +5 run 27 3830000 +5 run 28 3830000 +5 run 29 3830000 +5 run 30 3830000 +# point pass=5 state=run jobs_per_s=12499747.9 updates_per_s=0.0 clock_hz=99997961 +6 halt 1 3240000 +6 halt 2 3250000 +6 halt 3 3260000 +6 halt 4 3260000 +6 halt 5 3280000 +6 halt 6 3250000 +6 halt 7 3250000 +6 halt 8 3250000 +6 halt 9 3250000 +6 halt 10 3250000 +6 halt 11 3240000 +6 halt 12 3240000 +6 halt 13 3260000 +6 halt 14 3260000 +6 halt 15 3240000 +6 halt 16 3250000 +6 halt 17 3250000 +6 halt 18 3250000 +6 halt 19 3250000 +6 halt 20 3250000 +6 halt 21 3250000 +6 halt 22 3250000 +6 halt 23 3250000 +6 halt 24 3250000 +6 halt 25 3250000 +6 halt 26 3250000 +6 halt 27 3250000 +6 halt 28 3260000 +6 halt 29 3250000 +6 halt 30 3250000 +# point pass=6 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997962 +6 run 1 3840000 +6 run 2 3830000 +6 run 3 3830000 +6 run 4 3830000 +6 run 5 3830000 +6 run 6 3820000 +6 run 7 3820000 +6 run 8 3840000 +6 run 9 3820000 +6 run 10 3830000 +6 run 11 3830000 +6 run 12 3830000 +6 run 13 3830000 +6 run 14 3830000 +6 run 15 3830000 +6 run 16 3840000 +6 run 17 3820000 +6 run 18 3830000 +6 run 19 3840000 +6 run 20 3830000 +6 run 21 3830000 +6 run 22 3830000 +6 run 23 3830000 +6 run 24 3850000 +6 run 25 3850000 +6 run 26 3840000 +6 run 27 3830000 +6 run 28 3830000 +6 run 29 3820000 +6 run 30 3840000 +# point pass=6 state=run jobs_per_s=12499748.0 updates_per_s=0.0 clock_hz=99997963 +7 run 1 3830000 +7 run 2 3830000 +7 run 3 3830000 +7 run 4 3830000 +7 run 5 3840000 +7 run 6 3830000 +7 run 7 3830000 +7 run 8 3830000 +7 run 9 3820000 +7 run 10 3830000 +7 run 11 3830000 +7 run 12 3830000 +7 run 13 3850000 +7 run 14 3830000 +7 run 15 3840000 +7 run 16 3830000 +7 run 17 3840000 +7 run 18 3830000 +7 run 19 3830000 +7 run 20 3830000 +7 run 21 3850000 +7 run 22 3850000 +7 run 23 3830000 +7 run 24 3830000 +7 run 25 3840000 +7 run 26 3840000 +7 run 27 3830000 +7 run 28 3830000 +7 run 29 3830000 +7 run 30 3840000 +# point pass=7 state=run jobs_per_s=12499748.1 updates_per_s=0.0 clock_hz=99997963 +7 halt 1 3250000 +7 halt 2 3250000 +7 halt 3 3240000 +7 halt 4 3240000 +7 halt 5 3250000 +7 halt 6 3240000 +7 halt 7 3240000 +7 halt 8 3240000 +7 halt 9 3250000 +7 halt 10 3270000 +7 halt 11 3250000 +7 halt 12 3250000 +7 halt 13 3240000 +7 halt 14 3240000 +7 halt 15 3240000 +7 halt 16 3240000 +7 halt 17 3250000 +7 halt 18 3260000 +7 halt 19 3250000 +7 halt 20 3240000 +7 halt 21 3240000 +7 halt 22 3250000 +7 halt 23 3250000 +7 halt 24 3240000 +7 halt 25 3250000 +7 halt 26 3250000 +7 halt 27 3240000 +7 halt 28 3240000 +7 halt 29 3240000 +7 halt 30 3250000 +# point pass=7 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998258 +8 run 1 3840000 +8 run 2 3850000 +8 run 3 3830000 +8 run 4 3840000 +8 run 5 3840000 +8 run 6 3860000 +8 run 7 3850000 +8 run 8 3840000 +8 run 9 3840000 +8 run 10 3850000 +8 run 11 3840000 +8 run 12 3840000 +8 run 13 3840000 +8 run 14 3840000 +8 run 15 3870000 +8 run 16 3840000 +8 run 17 3820000 +8 run 18 3840000 +8 run 19 3840000 +8 run 20 3840000 +8 run 21 3840000 +8 run 22 3850000 +8 run 23 3840000 +8 run 24 3830000 +8 run 25 3840000 +8 run 26 3850000 +8 run 27 3840000 +8 run 28 3840000 +8 run 29 3840000 +8 run 30 3860000 +# point pass=8 state=run jobs_per_s=12499779.7 updates_per_s=0.0 clock_hz=99998216 +8 halt 1 3240000 +8 halt 2 3260000 +8 halt 3 3260000 +8 halt 4 3260000 +8 halt 5 3240000 +8 halt 6 3240000 +8 halt 7 3250000 +8 halt 8 3240000 +8 halt 9 3240000 +8 halt 10 3250000 +8 halt 11 3240000 +8 halt 12 3260000 +8 halt 13 3240000 +8 halt 14 3250000 +8 halt 15 3250000 +8 halt 16 3240000 +8 halt 17 3250000 +8 halt 18 3250000 +8 halt 19 3240000 +8 halt 20 3250000 +8 halt 21 3240000 +8 halt 22 3250000 +8 halt 23 3240000 +8 halt 24 3240000 +8 halt 25 3250000 +8 halt 26 3240000 +8 halt 27 3260000 +8 halt 28 3240000 +8 halt 29 3240000 +8 halt 30 3240000 +# point pass=8 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998181 +9 run 1 3840000 +9 run 2 3840000 +9 run 3 3830000 +9 run 4 3840000 +9 run 5 3830000 +9 run 6 3830000 +9 run 7 3840000 +9 run 8 3840000 +9 run 9 3840000 +9 run 10 3830000 +9 run 11 3830000 +9 run 12 3830000 +9 run 13 3840000 +9 run 14 3830000 +9 run 15 3850000 +9 run 16 3830000 +9 run 17 3830000 +9 run 18 3840000 +9 run 19 3840000 +9 run 20 3850000 +9 run 21 3830000 +9 run 22 3830000 +9 run 23 3850000 +9 run 24 3850000 +9 run 25 3840000 +9 run 26 3840000 +9 run 27 3830000 +9 run 28 3830000 +9 run 29 3840000 +9 run 30 3840000 +# point pass=9 state=run jobs_per_s=12499771.7 updates_per_s=0.0 clock_hz=99998152 +9 halt 1 3250000 +9 halt 2 3260000 +9 halt 3 3260000 +9 halt 4 3270000 +9 halt 5 3250000 +9 halt 6 3250000 +9 halt 7 3250000 +9 halt 8 3250000 +9 halt 9 3250000 +9 halt 10 3250000 +9 halt 11 3260000 +9 halt 12 3270000 +9 halt 13 3250000 +9 halt 14 3250000 +9 halt 15 3260000 +9 halt 16 3250000 +9 halt 17 3260000 +9 halt 18 3260000 +9 halt 19 3260000 +9 halt 20 3280000 +9 halt 21 3280000 +9 halt 22 3250000 +9 halt 23 3250000 +9 halt 24 3260000 +9 halt 25 3260000 +9 halt 26 3250000 +9 halt 27 3250000 +9 halt 28 3250000 +9 halt 29 3280000 +9 halt 30 3260000 +# point pass=9 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998128 +10 run 1 3840000 +10 run 2 3830000 +10 run 3 3840000 +10 run 4 3850000 +10 run 5 3830000 +10 run 6 3840000 +10 run 7 3840000 +10 run 8 3840000 +10 run 9 3860000 +10 run 10 3840000 +10 run 11 3840000 +10 run 12 3830000 +10 run 13 3840000 +10 run 14 3840000 +10 run 15 3840000 +10 run 16 3850000 +10 run 17 3870000 +10 run 18 3840000 +10 run 19 3840000 +10 run 20 3840000 +10 run 21 3840000 +10 run 22 3840000 +10 run 23 3840000 +10 run 24 3840000 +10 run 25 3840000 +10 run 26 3840000 +10 run 27 3840000 +10 run 28 3840000 +10 run 29 3840000 +10 run 30 3850000 +# point pass=10 state=run jobs_per_s=12499766.3 updates_per_s=0.0 clock_hz=99998107 +10 halt 1 3250000 +10 halt 2 3260000 +10 halt 3 3250000 +10 halt 4 3260000 +10 halt 5 3270000 +10 halt 6 3270000 +10 halt 7 3240000 +10 halt 8 3250000 +10 halt 9 3260000 +10 halt 10 3250000 +10 halt 11 3250000 +10 halt 12 3250000 +10 halt 13 3250000 +10 halt 14 3270000 +10 halt 15 3250000 +10 halt 16 3240000 +10 halt 17 3250000 +10 halt 18 3250000 +10 halt 19 3250000 +10 halt 20 3250000 +10 halt 21 3240000 +10 halt 22 3250000 +10 halt 23 3240000 +10 halt 24 3240000 +10 halt 25 3240000 +10 halt 26 3240000 +10 halt 27 3240000 +10 halt 28 3250000 +10 halt 29 3250000 +10 halt 30 3250000 +# point pass=10 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998091 +11 run 1 3850000 +11 run 2 3850000 +11 run 3 3840000 +11 run 4 3840000 +11 run 5 3840000 +11 run 6 3840000 +11 run 7 3830000 +11 run 8 3840000 +11 run 9 3830000 +11 run 10 3830000 +11 run 11 3850000 +11 run 12 3840000 +11 run 13 3830000 +11 run 14 3850000 +11 run 15 3830000 +11 run 16 3840000 +11 run 17 3840000 +11 run 18 3840000 +11 run 19 3840000 +11 run 20 3840000 +11 run 21 3850000 +11 run 22 3830000 +11 run 23 3830000 +11 run 24 3830000 +11 run 25 3840000 +11 run 26 4180000 +11 run 27 3840000 +11 run 28 3820000 +11 run 29 3830000 +11 run 30 3830000 +# point pass=11 state=run jobs_per_s=12499762.5 updates_per_s=0.0 clock_hz=99998076 +11 halt 1 3250000 +11 halt 2 3250000 +11 halt 3 3390000 +11 halt 4 3240000 +11 halt 5 3250000 +11 halt 6 3250000 +11 halt 7 3240000 +11 halt 8 3250000 +11 halt 9 3250000 +11 halt 10 3240000 +11 halt 11 3250000 +11 halt 12 3250000 +11 halt 13 3250000 +11 halt 14 3260000 +11 halt 15 3250000 +11 halt 16 3250000 +11 halt 17 3250000 +11 halt 18 3250000 +11 halt 19 3250000 +11 halt 20 3250000 +11 halt 21 3260000 +11 halt 22 3270000 +11 halt 23 3270000 +11 halt 24 3250000 +11 halt 25 3250000 +11 halt 26 3250000 +11 halt 27 3240000 +11 halt 28 3250000 +11 halt 29 3250000 +11 halt 30 3250000 +# point pass=11 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998063 +12 run 1 3820000 +12 run 2 3820000 +12 run 3 3840000 +12 run 4 3820000 +12 run 5 3830000 +12 run 6 3830000 +12 run 7 3830000 +12 run 8 3830000 +12 run 9 3820000 +12 run 10 3830000 +12 run 11 3840000 +12 run 12 3820000 +12 run 13 3830000 +12 run 14 3820000 +12 run 15 3820000 +12 run 16 3830000 +12 run 17 3830000 +12 run 18 3820000 +12 run 19 3840000 +12 run 20 3830000 +12 run 21 3820000 +12 run 22 3830000 +12 run 23 3830000 +12 run 24 3830000 +12 run 25 3810000 +12 run 26 3810000 +12 run 27 3820000 +12 run 28 3840000 +12 run 29 3820000 +12 run 30 3810000 +# point pass=12 state=run jobs_per_s=12499759.3 updates_per_s=0.0 clock_hz=99998053 +12 halt 1 3250000 +12 halt 2 3250000 +12 halt 3 3250000 +12 halt 4 3250000 +12 halt 5 3250000 +12 halt 6 3250000 +12 halt 7 3250000 +12 halt 8 3270000 +12 halt 9 3250000 +12 halt 10 3240000 +12 halt 11 3240000 +12 halt 12 3240000 +12 halt 13 3250000 +12 halt 14 3240000 +12 halt 15 3250000 +12 halt 16 3260000 +12 halt 17 3250000 +12 halt 18 3250000 +12 halt 19 3240000 +12 halt 20 3240000 +12 halt 21 3250000 +12 halt 22 3240000 +12 halt 23 3250000 +12 halt 24 3250000 +12 halt 25 3240000 +12 halt 26 3250000 +12 halt 27 3240000 +12 halt 28 3240000 +12 halt 29 3250000 +12 halt 30 3240000 +# point pass=12 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998045 +# done SystemTime { tv_sec: 1793922349, tv_nsec: 231452861 } +# passes used 12 of 12 (dropped: []) +# run - halt = 585.8 +/- 1.8 mW (per-pass sd 6.3); 12/12 passes positive; 6 sample excursions beyond 6 MAD +# per-pass differences (mW): 580.0 580.0 590.0 590.0 580.0 580.0 585.0 600.0 585.0 590.0 590.0 580.0 +# board power while running 3835 mW; jobs/s 12499755.9; updates/s 0.0; measured PL clock 99.998 MHz +# pre-registered prediction 488.0 mW: measured/predicted = 1.20, 53.5 sigma from it +# jobs/s and updates/s above are core 0's; all 4 cores run the same job diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/t0-recall-50MHz.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/t0-recall-50MHz.dat new file mode 100644 index 000000000..23565a0f9 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/t0-recall-50MHz.dat @@ -0,0 +1,505 @@ +# class t0-recall +# vqpu-edge meter passes=8 settle=60s samples=30 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793918156, tv_nsec: 433522612 } +# pass state sample power_uW +1 halt 1 3100000 +1 halt 2 3090000 +1 halt 3 3110000 +1 halt 4 3100000 +1 halt 5 3100000 +1 halt 6 3100000 +1 halt 7 3130000 +1 halt 8 3110000 +1 halt 9 3100000 +1 halt 10 3100000 +1 halt 11 3110000 +1 halt 12 3110000 +1 halt 13 3100000 +1 halt 14 3090000 +1 halt 15 3090000 +1 halt 16 3100000 +1 halt 17 3100000 +1 halt 18 3100000 +1 halt 19 3080000 +1 halt 20 3110000 +1 halt 21 3100000 +1 halt 22 3110000 +1 halt 23 3100000 +1 halt 24 3090000 +1 halt 25 3090000 +1 halt 26 3080000 +1 halt 27 3090000 +1 halt 28 3090000 +1 halt 29 3090000 +1 halt 30 3110000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=49999004 +1 run 1 3160000 +1 run 2 3160000 +1 run 3 3160000 +1 run 4 3170000 +1 run 5 3160000 +1 run 6 3160000 +1 run 7 3160000 +1 run 8 3160000 +1 run 9 3160000 +1 run 10 3160000 +1 run 11 3160000 +1 run 12 3160000 +1 run 13 3160000 +1 run 14 3160000 +1 run 15 3160000 +1 run 16 3160000 +1 run 17 3160000 +1 run 18 3160000 +1 run 19 3170000 +1 run 20 3160000 +1 run 21 3160000 +1 run 22 3160000 +1 run 23 3160000 +1 run 24 3160000 +1 run 25 3160000 +1 run 26 3160000 +1 run 27 3160000 +1 run 28 3180000 +1 run 29 3170000 +1 run 30 3160000 +# point pass=1 state=run jobs_per_s=6249876.9 updates_per_s=0.0 clock_hz=49999004 +2 halt 1 3100000 +2 halt 2 3080000 +2 halt 3 3090000 +2 halt 4 3090000 +2 halt 5 3080000 +2 halt 6 3080000 +2 halt 7 3080000 +2 halt 8 3080000 +2 halt 9 3080000 +2 halt 10 3080000 +2 halt 11 3080000 +2 halt 12 3090000 +2 halt 13 3080000 +2 halt 14 3080000 +2 halt 15 3100000 +2 halt 16 3100000 +2 halt 17 3080000 +2 halt 18 3080000 +2 halt 19 3080000 +2 halt 20 3080000 +2 halt 21 3080000 +2 halt 22 3080000 +2 halt 23 3090000 +2 halt 24 3110000 +2 halt 25 3080000 +2 halt 26 3090000 +2 halt 27 3080000 +2 halt 28 3080000 +2 halt 29 3100000 +2 halt 30 3080000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=49999003 +2 run 1 3150000 +2 run 2 3150000 +2 run 3 3150000 +2 run 4 3170000 +2 run 5 3150000 +2 run 6 3150000 +2 run 7 3160000 +2 run 8 3150000 +2 run 9 3160000 +2 run 10 3150000 +2 run 11 3150000 +2 run 12 3180000 +2 run 13 3170000 +2 run 14 3150000 +2 run 15 3160000 +2 run 16 3150000 +2 run 17 3160000 +2 run 18 3150000 +2 run 19 3150000 +2 run 20 3160000 +2 run 21 3180000 +2 run 22 3160000 +2 run 23 3160000 +2 run 24 3160000 +2 run 25 3160000 +2 run 26 3160000 +2 run 27 3160000 +2 run 28 3160000 +2 run 29 3160000 +2 run 30 3160000 +# point pass=2 state=run jobs_per_s=6249876.7 updates_per_s=0.0 clock_hz=49999003 +3 run 1 3180000 +3 run 2 3170000 +3 run 3 3160000 +3 run 4 3160000 +3 run 5 3160000 +3 run 6 3170000 +3 run 7 3170000 +3 run 8 3160000 +3 run 9 3180000 +3 run 10 3200000 +3 run 11 3160000 +3 run 12 3170000 +3 run 13 3170000 +3 run 14 3170000 +3 run 15 3170000 +3 run 16 3160000 +3 run 17 3160000 +3 run 18 3180000 +3 run 19 3160000 +3 run 20 3160000 +3 run 21 3160000 +3 run 22 3160000 +3 run 23 3160000 +3 run 24 3150000 +3 run 25 3160000 +3 run 26 3160000 +3 run 27 3150000 +3 run 28 3160000 +3 run 29 3160000 +3 run 30 3160000 +# point pass=3 state=run jobs_per_s=6249876.7 updates_per_s=0.0 clock_hz=49999002 +3 halt 1 3100000 +3 halt 2 3080000 +3 halt 3 3100000 +3 halt 4 3090000 +3 halt 5 3100000 +3 halt 6 3110000 +3 halt 7 3100000 +3 halt 8 3100000 +3 halt 9 3100000 +3 halt 10 3090000 +3 halt 11 3100000 +3 halt 12 3100000 +3 halt 13 3090000 +3 halt 14 3100000 +3 halt 15 3100000 +3 halt 16 3110000 +3 halt 17 3100000 +3 halt 18 3100000 +3 halt 19 3090000 +3 halt 20 3100000 +3 halt 21 3100000 +3 halt 22 3090000 +3 halt 23 3100000 +3 halt 24 3100000 +3 halt 25 3100000 +3 halt 26 3100000 +3 halt 27 3090000 +3 halt 28 3100000 +3 halt 29 3110000 +3 halt 30 3110000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=49999003 +4 run 1 3170000 +4 run 2 3170000 +4 run 3 3190000 +4 run 4 3170000 +4 run 5 3170000 +4 run 6 3170000 +4 run 7 3170000 +4 run 8 3170000 +4 run 9 3170000 +4 run 10 3170000 +4 run 11 3170000 +4 run 12 3160000 +4 run 13 3170000 +4 run 14 3160000 +4 run 15 3160000 +4 run 16 3170000 +4 run 17 3170000 +4 run 18 3180000 +4 run 19 3160000 +4 run 20 3180000 +4 run 21 3170000 +4 run 22 3170000 +4 run 23 3160000 +4 run 24 3170000 +4 run 25 3170000 +4 run 26 3190000 +4 run 27 3190000 +4 run 28 3160000 +4 run 29 3160000 +4 run 30 3160000 +# point pass=4 state=run jobs_per_s=6249876.6 updates_per_s=0.0 clock_hz=49999001 +4 halt 1 3090000 +4 halt 2 3080000 +4 halt 3 3100000 +4 halt 4 3090000 +4 halt 5 3100000 +4 halt 6 3080000 +4 halt 7 3090000 +4 halt 8 3090000 +4 halt 9 3100000 +4 halt 10 3100000 +4 halt 11 3100000 +4 halt 12 3090000 +4 halt 13 3080000 +4 halt 14 3090000 +4 halt 15 3110000 +4 halt 16 3080000 +4 halt 17 3080000 +4 halt 18 3100000 +4 halt 19 3090000 +4 halt 20 3080000 +4 halt 21 3090000 +4 halt 22 3090000 +4 halt 23 3110000 +4 halt 24 3100000 +4 halt 25 3110000 +4 halt 26 3100000 +4 halt 27 3080000 +4 halt 28 3090000 +4 halt 29 3080000 +4 halt 30 3090000 +# point pass=4 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=49999001 +5 run 1 3170000 +5 run 2 3170000 +5 run 3 3180000 +5 run 4 3180000 +5 run 5 3160000 +5 run 6 3160000 +5 run 7 3180000 +5 run 8 3170000 +5 run 9 3160000 +5 run 10 3170000 +5 run 11 3160000 +5 run 12 3180000 +5 run 13 3190000 +5 run 14 3170000 +5 run 15 3160000 +5 run 16 3170000 +5 run 17 3180000 +5 run 18 3170000 +5 run 19 3170000 +5 run 20 3170000 +5 run 21 3190000 +5 run 22 3200000 +5 run 23 3170000 +5 run 24 3170000 +5 run 25 3170000 +5 run 26 3170000 +5 run 27 3180000 +5 run 28 3170000 +5 run 29 3170000 +5 run 30 3180000 +# point pass=5 state=run jobs_per_s=6249876.4 updates_per_s=0.0 clock_hz=49999001 +5 halt 1 3090000 +5 halt 2 3100000 +5 halt 3 3090000 +5 halt 4 3100000 +5 halt 5 3090000 +5 halt 6 3090000 +5 halt 7 3100000 +5 halt 8 3100000 +5 halt 9 3090000 +5 halt 10 3100000 +5 halt 11 3100000 +5 halt 12 3420000 +5 halt 13 3090000 +5 halt 14 3120000 +5 halt 15 3080000 +5 halt 16 3090000 +5 halt 17 3180000 +5 halt 18 3110000 +5 halt 19 3090000 +5 halt 20 3090000 +5 halt 21 3080000 +5 halt 22 3090000 +5 halt 23 3090000 +5 halt 24 3090000 +5 halt 25 3090000 +5 halt 26 3080000 +5 halt 27 3090000 +5 halt 28 3100000 +5 halt 29 3090000 +5 halt 30 3100000 +# point pass=5 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=49999000 +6 halt 1 3090000 +6 halt 2 3090000 +6 halt 3 3080000 +6 halt 4 3090000 +6 halt 5 3080000 +6 halt 6 3120000 +6 halt 7 3100000 +6 halt 8 3080000 +6 halt 9 3090000 +6 halt 10 3090000 +6 halt 11 3080000 +6 halt 12 3090000 +6 halt 13 3100000 +6 halt 14 3100000 +6 halt 15 3110000 +6 halt 16 3100000 +6 halt 17 3100000 +6 halt 18 3100000 +6 halt 19 3090000 +6 halt 20 3100000 +6 halt 21 3100000 +6 halt 22 3090000 +6 halt 23 3100000 +6 halt 24 3080000 +6 halt 25 3090000 +6 halt 26 3100000 +6 halt 27 3100000 +6 halt 28 3090000 +6 halt 29 3200000 +6 halt 30 3110000 +# point pass=6 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=49999000 +6 run 1 3170000 +6 run 2 3160000 +6 run 3 3190000 +6 run 4 3190000 +6 run 5 3160000 +6 run 6 3160000 +6 run 7 3160000 +6 run 8 3170000 +6 run 9 3170000 +6 run 10 3160000 +6 run 11 3180000 +6 run 12 3190000 +6 run 13 3160000 +6 run 14 3170000 +6 run 15 3160000 +6 run 16 3170000 +6 run 17 3160000 +6 run 18 3170000 +6 run 19 3160000 +6 run 20 3170000 +6 run 21 3170000 +6 run 22 3160000 +6 run 23 3160000 +6 run 24 3160000 +6 run 25 3160000 +6 run 26 3170000 +6 run 27 3170000 +6 run 28 3170000 +6 run 29 3170000 +6 run 30 3170000 +# point pass=6 state=run jobs_per_s=6249876.5 updates_per_s=0.0 clock_hz=49999000 +7 halt 1 3100000 +7 halt 2 3080000 +7 halt 3 3080000 +7 halt 4 3090000 +7 halt 5 3090000 +7 halt 6 3100000 +7 halt 7 3100000 +7 halt 8 3100000 +7 halt 9 3100000 +7 halt 10 3090000 +7 halt 11 3100000 +7 halt 12 3100000 +7 halt 13 3090000 +7 halt 14 3100000 +7 halt 15 3110000 +7 halt 16 3100000 +7 halt 17 3080000 +7 halt 18 3090000 +7 halt 19 3090000 +7 halt 20 3080000 +7 halt 21 3090000 +7 halt 22 3090000 +7 halt 23 3110000 +7 halt 24 3110000 +7 halt 25 3100000 +7 halt 26 3090000 +7 halt 27 3090000 +7 halt 28 3100000 +7 halt 29 3100000 +7 halt 30 3100000 +# point pass=7 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=49999001 +7 run 1 3160000 +7 run 2 3160000 +7 run 3 3160000 +7 run 4 3160000 +7 run 5 3160000 +7 run 6 3160000 +7 run 7 3160000 +7 run 8 3170000 +7 run 9 3160000 +7 run 10 3160000 +7 run 11 3160000 +7 run 12 3180000 +7 run 13 3160000 +7 run 14 3160000 +7 run 15 3170000 +7 run 16 3160000 +7 run 17 3160000 +7 run 18 3160000 +7 run 19 3160000 +7 run 20 3170000 +7 run 21 3190000 +7 run 22 3160000 +7 run 23 3150000 +7 run 24 3160000 +7 run 25 3160000 +7 run 26 3160000 +7 run 27 3160000 +7 run 28 3160000 +7 run 29 3180000 +7 run 30 3160000 +# point pass=7 state=run jobs_per_s=6249864.5 updates_per_s=0.0 clock_hz=49998905 +8 run 1 3170000 +8 run 2 3170000 +8 run 3 3170000 +8 run 4 3170000 +8 run 5 3170000 +8 run 6 3160000 +8 run 7 3170000 +8 run 8 3170000 +8 run 9 3190000 +8 run 10 3160000 +8 run 11 3160000 +8 run 12 3160000 +8 run 13 3170000 +8 run 14 3160000 +8 run 15 3170000 +8 run 16 3160000 +8 run 17 3190000 +8 run 18 3170000 +8 run 19 3160000 +8 run 20 3160000 +8 run 21 3160000 +8 run 22 3170000 +8 run 23 3160000 +8 run 24 3160000 +8 run 25 3160000 +8 run 26 3160000 +8 run 27 3170000 +8 run 28 3170000 +8 run 29 3160000 +8 run 30 3170000 +# point pass=8 state=run jobs_per_s=6249866.0 updates_per_s=0.0 clock_hz=49998917 +8 halt 1 3090000 +8 halt 2 3100000 +8 halt 3 3090000 +8 halt 4 3100000 +8 halt 5 3110000 +8 halt 6 3110000 +8 halt 7 3100000 +8 halt 8 3100000 +8 halt 9 3090000 +8 halt 10 3100000 +8 halt 11 3090000 +8 halt 12 3100000 +8 halt 13 3090000 +8 halt 14 3110000 +8 halt 15 3100000 +8 halt 16 3090000 +8 halt 17 3100000 +8 halt 18 3100000 +8 halt 19 3090000 +8 halt 20 3100000 +8 halt 21 3090000 +8 halt 22 3100000 +8 halt 23 3090000 +8 halt 24 3090000 +8 halt 25 3100000 +8 halt 26 3090000 +8 halt 27 3110000 +8 halt 28 3100000 +8 halt 29 3110000 +8 halt 30 3090000 +# point pass=8 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=49998928 +# done SystemTime { tv_sec: 1793919597, tv_nsec: 315661140 } +# passes used 8 of 8 (dropped: []) +# run - halt = 70.6 +/- 3.3 mW (per-pass sd 9.4); 8/8 passes positive; 4 sample excursions beyond 6 MAD +# per-pass differences (mW): 60.0 80.0 60.0 80.0 80.0 75.0 60.0 70.0 +# board power while running 3165 mW; jobs/s 6249873.8; updates/s 0.0; measured PL clock 49.999 MHz +# pre-registered prediction 61.0 mW: measured/predicted = 1.16, 2.9 sigma from it diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/t0-recall.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/t0-recall.dat new file mode 100644 index 000000000..8c5b8e6af --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-05/t0-recall.dat @@ -0,0 +1,753 @@ +# class t0-recall +# vqpu-edge meter passes=12 settle=60s samples=30 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793910950, tv_nsec: 505668490 } +# pass state sample power_uW +1 run 1 3260000 +1 run 2 3250000 +1 run 3 3270000 +1 run 4 3260000 +1 run 5 3260000 +1 run 6 3260000 +1 run 7 3260000 +1 run 8 3260000 +1 run 9 3250000 +1 run 10 3250000 +1 run 11 3260000 +1 run 12 3250000 +1 run 13 3250000 +1 run 14 3260000 +1 run 15 3260000 +1 run 16 3260000 +1 run 17 3250000 +1 run 18 3260000 +1 run 19 3260000 +1 run 20 3250000 +1 run 21 3250000 +1 run 22 3260000 +1 run 23 3260000 +1 run 24 3250000 +1 run 25 3270000 +1 run 26 3280000 +1 run 27 3250000 +1 run 28 3260000 +1 run 29 3260000 +1 run 30 3260000 +# point pass=1 state=run jobs_per_s=12499750.0 updates_per_s=0.0 clock_hz=99997978 +1 halt 1 3120000 +1 halt 2 3110000 +1 halt 3 3100000 +1 halt 4 3110000 +1 halt 5 3110000 +1 halt 6 3110000 +1 halt 7 3120000 +1 halt 8 3130000 +1 halt 9 3110000 +1 halt 10 3110000 +1 halt 11 3110000 +1 halt 12 3110000 +1 halt 13 3100000 +1 halt 14 3120000 +1 halt 15 3110000 +1 halt 16 3110000 +1 halt 17 3110000 +1 halt 18 3110000 +1 halt 19 3110000 +1 halt 20 3110000 +1 halt 21 3100000 +1 halt 22 3110000 +1 halt 23 3130000 +1 halt 24 3110000 +1 halt 25 3110000 +1 halt 26 3110000 +1 halt 27 3100000 +1 halt 28 3110000 +1 halt 29 3100000 +1 halt 30 3110000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997978 +2 run 1 3260000 +2 run 2 3260000 +2 run 3 3260000 +2 run 4 3260000 +2 run 5 3270000 +2 run 6 3250000 +2 run 7 3250000 +2 run 8 3260000 +2 run 9 3250000 +2 run 10 3250000 +2 run 11 3260000 +2 run 12 3250000 +2 run 13 3260000 +2 run 14 3260000 +2 run 15 3260000 +2 run 16 3260000 +2 run 17 3260000 +2 run 18 3250000 +2 run 19 3260000 +2 run 20 3290000 +2 run 21 3250000 +2 run 22 3250000 +2 run 23 3250000 +2 run 24 3260000 +2 run 25 3260000 +2 run 26 3260000 +2 run 27 3270000 +2 run 28 3280000 +2 run 29 3260000 +2 run 30 3260000 +# point pass=2 state=run jobs_per_s=12499741.8 updates_per_s=0.0 clock_hz=99997912 +2 halt 1 3110000 +2 halt 2 3110000 +2 halt 3 3110000 +2 halt 4 3100000 +2 halt 5 3100000 +2 halt 6 3110000 +2 halt 7 3110000 +2 halt 8 3120000 +2 halt 9 3100000 +2 halt 10 3110000 +2 halt 11 3120000 +2 halt 12 3110000 +2 halt 13 3110000 +2 halt 14 3120000 +2 halt 15 3110000 +2 halt 16 3120000 +2 halt 17 3140000 +2 halt 18 3110000 +2 halt 19 3110000 +2 halt 20 3110000 +2 halt 21 3110000 +2 halt 22 3110000 +2 halt 23 3110000 +2 halt 24 3110000 +2 halt 25 3120000 +2 halt 26 3110000 +2 halt 27 3110000 +2 halt 28 3110000 +2 halt 29 3110000 +2 halt 30 3110000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997921 +3 halt 1 3120000 +3 halt 2 3110000 +3 halt 3 3110000 +3 halt 4 3110000 +3 halt 5 3130000 +3 halt 6 3110000 +3 halt 7 3110000 +3 halt 8 3100000 +3 halt 9 3110000 +3 halt 10 3110000 +3 halt 11 3120000 +3 halt 12 3110000 +3 halt 13 3120000 +3 halt 14 3110000 +3 halt 15 3120000 +3 halt 16 3110000 +3 halt 17 3110000 +3 halt 18 3100000 +3 halt 19 3110000 +3 halt 20 3110000 +3 halt 21 3120000 +3 halt 22 3110000 +3 halt 23 3110000 +3 halt 24 3110000 +3 halt 25 3110000 +3 halt 26 3110000 +3 halt 27 3120000 +3 halt 28 3110000 +3 halt 29 3100000 +3 halt 30 3110000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997928 +3 run 1 3260000 +3 run 2 3280000 +3 run 3 3250000 +3 run 4 3250000 +3 run 5 3250000 +3 run 6 3260000 +3 run 7 3250000 +3 run 8 3260000 +3 run 9 3250000 +3 run 10 3270000 +3 run 11 3250000 +3 run 12 3260000 +3 run 13 3270000 +3 run 14 3260000 +3 run 15 3260000 +3 run 16 3260000 +3 run 17 3260000 +3 run 18 3270000 +3 run 19 3270000 +3 run 20 3260000 +3 run 21 3260000 +3 run 22 3260000 +3 run 23 3270000 +3 run 24 3250000 +3 run 25 3290000 +3 run 26 3270000 +3 run 27 3260000 +3 run 28 3260000 +3 run 29 3260000 +3 run 30 3260000 +# point pass=3 state=run jobs_per_s=12499744.6 updates_per_s=0.0 clock_hz=99997935 +4 run 1 3250000 +4 run 2 3260000 +4 run 3 3260000 +4 run 4 3250000 +4 run 5 3260000 +4 run 6 3250000 +4 run 7 3290000 +4 run 8 3260000 +4 run 9 3250000 +4 run 10 3260000 +4 run 11 3260000 +4 run 12 3250000 +4 run 13 3250000 +4 run 14 3250000 +4 run 15 3250000 +4 run 16 3260000 +4 run 17 3260000 +4 run 18 3260000 +4 run 19 3260000 +4 run 20 3250000 +4 run 21 3270000 +4 run 22 3260000 +4 run 23 3250000 +4 run 24 3260000 +4 run 25 3250000 +4 run 26 3500000 +4 run 27 3260000 +4 run 28 3260000 +4 run 29 3260000 +4 run 30 3270000 +# point pass=4 state=run jobs_per_s=12499745.3 updates_per_s=0.0 clock_hz=99997940 +4 halt 1 3100000 +4 halt 2 3100000 +4 halt 3 3110000 +4 halt 4 3110000 +4 halt 5 3100000 +4 halt 6 3100000 +4 halt 7 3110000 +4 halt 8 3110000 +4 halt 9 3100000 +4 halt 10 3110000 +4 halt 11 3110000 +4 halt 12 3100000 +4 halt 13 3100000 +4 halt 14 3110000 +4 halt 15 3110000 +4 halt 16 3120000 +4 halt 17 3120000 +4 halt 18 3130000 +4 halt 19 3140000 +4 halt 20 3110000 +4 halt 21 3110000 +4 halt 22 3110000 +4 halt 23 3110000 +4 halt 24 3110000 +4 halt 25 3110000 +4 halt 26 3110000 +4 halt 27 3130000 +4 halt 28 3110000 +4 halt 29 3110000 +4 halt 30 3110000 +# point pass=4 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997942 +5 run 1 3260000 +5 run 2 3260000 +5 run 3 3280000 +5 run 4 3260000 +5 run 5 3260000 +5 run 6 3270000 +5 run 7 3290000 +5 run 8 3270000 +5 run 9 3260000 +5 run 10 3270000 +5 run 11 3260000 +5 run 12 3260000 +5 run 13 3270000 +5 run 14 3260000 +5 run 15 3290000 +5 run 16 3290000 +5 run 17 3270000 +5 run 18 3260000 +5 run 19 3260000 +5 run 20 3270000 +5 run 21 3270000 +5 run 22 3260000 +5 run 23 3270000 +5 run 24 3280000 +5 run 25 3260000 +5 run 26 3260000 +5 run 27 3270000 +5 run 28 3270000 +5 run 29 3260000 +5 run 30 3270000 +# point pass=5 state=run jobs_per_s=12499746.0 updates_per_s=0.0 clock_hz=99997946 +5 halt 1 3120000 +5 halt 2 3120000 +5 halt 3 3120000 +5 halt 4 3140000 +5 halt 5 3120000 +5 halt 6 3110000 +5 halt 7 3130000 +5 halt 8 3120000 +5 halt 9 3110000 +5 halt 10 3130000 +5 halt 11 3130000 +5 halt 12 3140000 +5 halt 13 3120000 +5 halt 14 3110000 +5 halt 15 3130000 +5 halt 16 3110000 +5 halt 17 3110000 +5 halt 18 3110000 +5 halt 19 3110000 +5 halt 20 3120000 +5 halt 21 3110000 +5 halt 22 3120000 +5 halt 23 3110000 +5 halt 24 3110000 +5 halt 25 3100000 +5 halt 26 3110000 +5 halt 27 3120000 +5 halt 28 3100000 +5 halt 29 3100000 +5 halt 30 3110000 +# point pass=5 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997949 +6 halt 1 3140000 +6 halt 2 3500000 +6 halt 3 3100000 +6 halt 4 3110000 +6 halt 5 3120000 +6 halt 6 3120000 +6 halt 7 3110000 +6 halt 8 3120000 +6 halt 9 3130000 +6 halt 10 3110000 +6 halt 11 3110000 +6 halt 12 3110000 +6 halt 13 3120000 +6 halt 14 3110000 +6 halt 15 3120000 +6 halt 16 3120000 +6 halt 17 3110000 +6 halt 18 3120000 +6 halt 19 3120000 +6 halt 20 3110000 +6 halt 21 3110000 +6 halt 22 3110000 +6 halt 23 3120000 +6 halt 24 3130000 +6 halt 25 3120000 +6 halt 26 3110000 +6 halt 27 3120000 +6 halt 28 3120000 +6 halt 29 3110000 +6 halt 30 3110000 +# point pass=6 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997951 +6 run 1 3250000 +6 run 2 3260000 +6 run 3 3250000 +6 run 4 3260000 +6 run 5 3250000 +6 run 6 3280000 +6 run 7 3250000 +6 run 8 3250000 +6 run 9 3260000 +6 run 10 3260000 +6 run 11 3250000 +6 run 12 3250000 +6 run 13 3250000 +6 run 14 3260000 +6 run 15 3250000 +6 run 16 3250000 +6 run 17 3250000 +6 run 18 3250000 +6 run 19 3250000 +6 run 20 3260000 +6 run 21 3270000 +6 run 22 3250000 +6 run 23 3260000 +6 run 24 3260000 +6 run 25 3260000 +6 run 26 3260000 +6 run 27 3270000 +6 run 28 3260000 +6 run 29 3290000 +6 run 30 3260000 +# point pass=6 state=run jobs_per_s=12499746.9 updates_per_s=0.0 clock_hz=99997953 +7 halt 1 3100000 +7 halt 2 3110000 +7 halt 3 3100000 +7 halt 4 3110000 +7 halt 5 3100000 +7 halt 6 3100000 +7 halt 7 3090000 +7 halt 8 3110000 +7 halt 9 3110000 +7 halt 10 3100000 +7 halt 11 3100000 +7 halt 12 3110000 +7 halt 13 3100000 +7 halt 14 3110000 +7 halt 15 3110000 +7 halt 16 3110000 +7 halt 17 3120000 +7 halt 18 3120000 +7 halt 19 3100000 +7 halt 20 3100000 +7 halt 21 3090000 +7 halt 22 3100000 +7 halt 23 3110000 +7 halt 24 3110000 +7 halt 25 3110000 +7 halt 26 3120000 +7 halt 27 3100000 +7 halt 28 3100000 +7 halt 29 3100000 +7 halt 30 3110000 +# point pass=7 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997955 +7 run 1 3240000 +7 run 2 3250000 +7 run 3 3250000 +7 run 4 3270000 +7 run 5 3250000 +7 run 6 3270000 +7 run 7 3250000 +7 run 8 3260000 +7 run 9 3240000 +7 run 10 3250000 +7 run 11 3250000 +7 run 12 3240000 +7 run 13 3250000 +7 run 14 3270000 +7 run 15 3270000 +7 run 16 3250000 +7 run 17 3260000 +7 run 18 3250000 +7 run 19 3240000 +7 run 20 3250000 +7 run 21 3240000 +7 run 22 3250000 +7 run 23 3270000 +7 run 24 3250000 +7 run 25 3250000 +7 run 26 3250000 +7 run 27 3250000 +7 run 28 3250000 +7 run 29 3250000 +7 run 30 3250000 +# point pass=7 state=run jobs_per_s=12499747.3 updates_per_s=0.0 clock_hz=99997956 +8 halt 1 3110000 +8 halt 2 3110000 +8 halt 3 3120000 +8 halt 4 3110000 +8 halt 5 3110000 +8 halt 6 3110000 +8 halt 7 3110000 +8 halt 8 3110000 +8 halt 9 3130000 +8 halt 10 3100000 +8 halt 11 3120000 +8 halt 12 3110000 +8 halt 13 3110000 +8 halt 14 3100000 +8 halt 15 3100000 +8 halt 16 3100000 +8 halt 17 3110000 +8 halt 18 3100000 +8 halt 19 3110000 +8 halt 20 3120000 +8 halt 21 3110000 +8 halt 22 3110000 +8 halt 23 3110000 +8 halt 24 3110000 +8 halt 25 3110000 +8 halt 26 3120000 +8 halt 27 3110000 +8 halt 28 3120000 +8 halt 29 3120000 +8 halt 30 3120000 +# point pass=8 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997958 +8 run 1 3250000 +8 run 2 3250000 +8 run 3 3250000 +8 run 4 3260000 +8 run 5 3250000 +8 run 6 3250000 +8 run 7 3250000 +8 run 8 3260000 +8 run 9 3250000 +8 run 10 3250000 +8 run 11 3250000 +8 run 12 3250000 +8 run 13 3250000 +8 run 14 3250000 +8 run 15 3250000 +8 run 16 3250000 +8 run 17 3240000 +8 run 18 3250000 +8 run 19 3250000 +8 run 20 3250000 +8 run 21 3250000 +8 run 22 3260000 +8 run 23 3270000 +8 run 24 3250000 +8 run 25 3250000 +8 run 26 3250000 +8 run 27 3250000 +8 run 28 3240000 +8 run 29 3250000 +8 run 30 3260000 +# point pass=8 state=run jobs_per_s=12499747.6 updates_per_s=0.0 clock_hz=99997959 +9 halt 1 3110000 +9 halt 2 3100000 +9 halt 3 3100000 +9 halt 4 3100000 +9 halt 5 3120000 +9 halt 6 3110000 +9 halt 7 3110000 +9 halt 8 3100000 +9 halt 9 3100000 +9 halt 10 3100000 +9 halt 11 3100000 +9 halt 12 3100000 +9 halt 13 3100000 +9 halt 14 3110000 +9 halt 15 3100000 +9 halt 16 3100000 +9 halt 17 3110000 +9 halt 18 3100000 +9 halt 19 3090000 +9 halt 20 3110000 +9 halt 21 3100000 +9 halt 22 3100000 +9 halt 23 3100000 +9 halt 24 3100000 +9 halt 25 3100000 +9 halt 26 3090000 +9 halt 27 3100000 +9 halt 28 3120000 +9 halt 29 3100000 +9 halt 30 3100000 +# point pass=9 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997960 +9 run 1 3260000 +9 run 2 3250000 +9 run 3 3260000 +9 run 4 3260000 +9 run 5 3260000 +9 run 6 3260000 +9 run 7 3260000 +9 run 8 3280000 +9 run 9 3260000 +9 run 10 3250000 +9 run 11 3260000 +9 run 12 3270000 +9 run 13 3260000 +9 run 14 3270000 +9 run 15 3260000 +9 run 16 3280000 +9 run 17 3280000 +9 run 18 3260000 +9 run 19 3260000 +9 run 20 3260000 +9 run 21 3260000 +9 run 22 3260000 +9 run 23 3260000 +9 run 24 3260000 +9 run 25 3280000 +9 run 26 3260000 +9 run 27 3270000 +9 run 28 3260000 +9 run 29 3260000 +9 run 30 3260000 +# point pass=9 state=run jobs_per_s=12499747.8 updates_per_s=0.0 clock_hz=99997960 +10 run 1 3260000 +10 run 2 3260000 +10 run 3 3260000 +10 run 4 3260000 +10 run 5 3270000 +10 run 6 3260000 +10 run 7 3260000 +10 run 8 3260000 +10 run 9 3260000 +10 run 10 3270000 +10 run 11 3260000 +10 run 12 3260000 +10 run 13 3290000 +10 run 14 3280000 +10 run 15 3260000 +10 run 16 3260000 +10 run 17 3260000 +10 run 18 3260000 +10 run 19 3260000 +10 run 20 3270000 +10 run 21 3270000 +10 run 22 3270000 +10 run 23 3260000 +10 run 24 3270000 +10 run 25 3270000 +10 run 26 3260000 +10 run 27 3270000 +10 run 28 3270000 +10 run 29 3260000 +10 run 30 3260000 +# point pass=10 state=run jobs_per_s=12499747.9 updates_per_s=0.0 clock_hz=99997961 +10 halt 1 3140000 +10 halt 2 3140000 +10 halt 3 3120000 +10 halt 4 3120000 +10 halt 5 3120000 +10 halt 6 3120000 +10 halt 7 3120000 +10 halt 8 3120000 +10 halt 9 3120000 +10 halt 10 3130000 +10 halt 11 3120000 +10 halt 12 3120000 +10 halt 13 3110000 +10 halt 14 3110000 +10 halt 15 3110000 +10 halt 16 3110000 +10 halt 17 3110000 +10 halt 18 3110000 +10 halt 19 3120000 +10 halt 20 3110000 +10 halt 21 3110000 +10 halt 22 3110000 +10 halt 23 3110000 +10 halt 24 3110000 +10 halt 25 3140000 +10 halt 26 3110000 +10 halt 27 3110000 +10 halt 28 3120000 +10 halt 29 3120000 +10 halt 30 3110000 +# point pass=10 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997961 +11 halt 1 3120000 +11 halt 2 3120000 +11 halt 3 3120000 +11 halt 4 3120000 +11 halt 5 3110000 +11 halt 6 3120000 +11 halt 7 3130000 +11 halt 8 3110000 +11 halt 9 3120000 +11 halt 10 3110000 +11 halt 11 3110000 +11 halt 12 3120000 +11 halt 13 3120000 +11 halt 14 3120000 +11 halt 15 3130000 +11 halt 16 3120000 +11 halt 17 3120000 +11 halt 18 3120000 +11 halt 19 3120000 +11 halt 20 3120000 +11 halt 21 3120000 +11 halt 22 3140000 +11 halt 23 3110000 +11 halt 24 3130000 +11 halt 25 3130000 +11 halt 26 3110000 +11 halt 27 3120000 +11 halt 28 3130000 +11 halt 29 3120000 +11 halt 30 3140000 +# point pass=11 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997961 +11 run 1 3250000 +11 run 2 3260000 +11 run 3 3260000 +11 run 4 3260000 +11 run 5 3260000 +11 run 6 3260000 +11 run 7 3250000 +11 run 8 3250000 +11 run 9 3260000 +11 run 10 3290000 +11 run 11 3270000 +11 run 12 3260000 +11 run 13 3260000 +11 run 14 3260000 +11 run 15 3590000 +11 run 16 3260000 +11 run 17 3260000 +11 run 18 3280000 +11 run 19 3280000 +11 run 20 3270000 +11 run 21 3260000 +11 run 22 3260000 +11 run 23 3250000 +11 run 24 3250000 +11 run 25 3260000 +11 run 26 3270000 +11 run 27 3280000 +11 run 28 3250000 +11 run 29 3260000 +11 run 30 3260000 +# point pass=11 state=run jobs_per_s=12499748.2 updates_per_s=0.0 clock_hz=99997964 +12 run 1 3250000 +12 run 2 3260000 +12 run 3 3260000 +12 run 4 3260000 +12 run 5 3260000 +12 run 6 3280000 +12 run 7 3260000 +12 run 8 3260000 +12 run 9 3250000 +12 run 10 3260000 +12 run 11 3260000 +12 run 12 3260000 +12 run 13 3300000 +12 run 14 3260000 +12 run 15 3250000 +12 run 16 3260000 +12 run 17 3260000 +12 run 18 3270000 +12 run 19 3260000 +12 run 20 3270000 +12 run 21 3270000 +12 run 22 3280000 +12 run 23 3260000 +12 run 24 3280000 +12 run 25 3270000 +12 run 26 3260000 +12 run 27 3290000 +12 run 28 3270000 +12 run 29 3260000 +12 run 30 3260000 +# point pass=12 state=run jobs_per_s=12499748.3 updates_per_s=0.0 clock_hz=99997964 +12 halt 1 3130000 +12 halt 2 3130000 +12 halt 3 3110000 +12 halt 4 3110000 +12 halt 5 3130000 +12 halt 6 3120000 +12 halt 7 3130000 +12 halt 8 3120000 +12 halt 9 3110000 +12 halt 10 3110000 +12 halt 11 3120000 +12 halt 12 3120000 +12 halt 13 3120000 +12 halt 14 3110000 +12 halt 15 3140000 +12 halt 16 3140000 +12 halt 17 3110000 +12 halt 18 3120000 +12 halt 19 3120000 +12 halt 20 3120000 +12 halt 21 3110000 +12 halt 22 3110000 +12 halt 23 3120000 +12 halt 24 3120000 +12 halt 25 3110000 +12 halt 26 3130000 +12 halt 27 3110000 +12 halt 28 3110000 +12 halt 29 3110000 +12 halt 30 3130000 +# point pass=12 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997964 +# done SystemTime { tv_sec: 1793913111, tv_nsec: 884855982 } +# passes used 12 of 12 (dropped: []) +# run - halt = 146.7 +/- 2.0 mW (per-pass sd 6.9); 12/12 passes positive; 4 sample excursions beyond 6 MAD +# per-pass differences (mW): 150.0 150.0 150.0 150.0 155.0 140.0 145.0 140.0 160.0 140.0 140.0 140.0 +# board power while running 3259 mW; jobs/s 12499746.8; updates/s 0.0; measured PL clock 99.998 MHz +# pre-registered prediction 122.0 mW: measured/predicted = 1.20, 12.5 sigma from it diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/AXI-FINAL-PREDICTION.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/AXI-FINAL-PREDICTION.txt new file mode 100644 index 000000000..097afead7 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/AXI-FINAL-PREDICTION.txt @@ -0,0 +1,9 @@ +Written 2026-11-06, before the build with the result write-back was metered, and committed before +the measurement. Not edited after the data. + +The AXI build metered first (sha256 3d84dbd3..., AXI-PREDICTION.txt) read a batch's results by +register reads. The final build adds a write master that sends them to DDR. The engine is the same, +and the write master is idle while the meter reads. + +PREDICTION: t0-recall run minus halt on the final build, 3 passes, 60 s settle, 30 samples, equals +the EMIO build's class result, 162.0 +/- 3.3 mW, within 2 combined standard errors. diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/AXI-PREDICTION.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/AXI-PREDICTION.txt new file mode 100644 index 000000000..5993b17f4 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/AXI-PREDICTION.txt @@ -0,0 +1,10 @@ +Written 2026-11-06, before the AXI-link build was metered, and committed before the measurement. +Not edited after the data. + +The AXI-link build (rtl/landscape_axi.v) carries the same engine (rtl/landscape_core.v, rtl version 2) +as the EMIO build the class campaign measured (measurements/2026-11-06/PREDICTION.txt). The link is +idle while the meter reads: the run state is the engine in repeat mode with no processor access. + +PREDICTION: t0-recall run minus halt on the AXI build, 3 passes, 60 s settle, 30 samples, equals the +EMIO build's t0-recall class result within 2 combined standard errors. If it does not, the power +figures quoted for the design are the AXI build's, and the class campaign is repeated on it. diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/JOINT-PREREG.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/JOINT-PREREG.txt new file mode 100644 index 000000000..9f6c49914 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/JOINT-PREREG.txt @@ -0,0 +1,38 @@ +Written 2026-11-06, before any board run of the joint test, and committed before it. Not edited +after the data. + +WHAT IS TESTED. The sample kernel's joint law, not only its per-cell frequencies: a sampler that drew +each cell from its right marginal, independently, would pass every per-cell test. Four cases, each a +workload small enough that the exact law of a chain's final state can be enumerated over all 3^n +states (src/exact.rs, `exact::cases`): + + ring 8, fixed T = 1.5, 4 sweeps 200,000 chains 6,561 states + ring 8, the job's anneal from T = 2.5, 10 sweeps 200,000 chains 6,561 states + dense 6, fixed T = 4, 2 sweeps 200,000 chains 729 states + sparse 10, the job's anneal from T = 1.5, 8 sweeps 400,000 chains 59,049 states + +Chain r of a case has the seed chain_seed(2027, r). (Seed 2026 was used while writing the test, on +the model; 2027 has not been run anywhere before this file was committed.) Every chain runs on the +board through the AXI link's sequencer, and on the CPU reference. + +THE EXACT LAW. A probability vector over every state, pushed through each cell update of each sweep +with the three probabilities a/2^53, (b-a)/2^53 and 1 - b/2^53 from the reference's cut points +(a, b) = cuts(h, cost, beta), then through the synchronous sweep at temperature 0 where the job's +anneal ends with one. It assumes ideal uniform 53-bit draws; nothing is sampled. + +STATISTICS AND THE RULE, per case: + 1. Pearson chi-square and the G-test over every state expected at least 5 times, the rest pooled + into one bin: p >= 0.001 for both. + 2. Every cell's three marginal frequencies (z scores) and every pair of cells' nine joint + frequencies: Bonferroni p >= 0.001 for each family. + 3. Every chain's final state on the board equals the CPU reference's. + 4. Control: the same histogram against the law with the exact marginals and independent cells + must be rejected, chi-square p < 1e-6, while its cell family still passes. This shows the test + sees the joint structure that per-cell statistics cannot. +A case passes if 1-4 hold. Sixteen p values are taken at 0.001 each; the chance that a correct +kernel fails one by chance is about 1.6%. + +WHAT IT DOES NOT SHOW. Because the board is bit-exact (rule 3), its histogram is the reference's: +the test holds the shared kernel (the reference's algorithm and its counter-based draws) to exact +enumeration on the board's own outputs; it is not an independent sample of a different machine. +Board-level, one board. diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/NULL-REPEAT.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/NULL-REPEAT.txt new file mode 100644 index 000000000..c63c0fd9a --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/NULL-REPEAT.txt @@ -0,0 +1,15 @@ +Written 2026-11-06 after the class campaign's data were read, and committed before the repeat +below runs. Not edited after its data. + +The class campaign's null (EMIO build, 12:49 to 13:13 UTC) came to 8.1 +/- 1.9 mW, and so failed its +pre-registered rule, |delta| < 2 SE. The two slots of a null are the same state (halted), so no job +explains it, and it does not follow the order of the slots: 3 of the 8 passes put the slot labelled +halt first and 5 the slot labelled run, and the differences are alike in both. + +WHAT IS DONE. The null runs once more, on the AXI build, by the same protocol: 8 passes, 60 s settle, +30 samples, nothing else on the board, the same rule. Both nulls are reported, whichever way the +second comes out. This is not a second chance for the first: its failure stands in the README. + +WHAT FOLLOWS. If the repeat also fails, nothing below about 10 mW is claimed above the instrument's +floor, which covers gibbs-recall and t0-idle. If it passes, those two are still reported with the +first null beside them, since one failure in two says the floor is not known to be under 8 mW. diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/PREDICTION.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/PREDICTION.txt new file mode 100644 index 000000000..4a5259fdd --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/PREDICTION.txt @@ -0,0 +1,25 @@ +Written 2026-11-06, before this design (rtl version 2) was metered on the board, and committed +before the measurement began. Not edited after the data. + +WHAT IS MEASURED. Run minus halt on one bitstream, whole-board power sensor, 100 MHz, by the +protocol in scripts/power_campaign.sh: no reload between the two states, run/halt order randomised +in each pass, 60 s settle and 30 samples at 1 Hz read in the measuring process with nothing else +running, every point checked for a reload (the engine's uptime counter, its ID, the kernel log's +count of FPGA writes), statistic the mean of per-pass differences of medians, error the standard +error across passes. Label: board-level, one board, one meter, this design. + +WHAT CHANGED SINCE THE LAST MEASUREMENT (rtl version 1, 2026-11-05, measurements/2026-11-05): +fields and the cost widen from 11 and 10 bits to 20; a cell update takes four clocks, not three; +the sampler's draw is a SplitMix64 pipeline (two 64-bit products, 20 DSP slices) instead of a +128-bit xoroshiro register; the table entry is 108 bits, not 34. + +PREDICTIONS, point and range: + t0-recall 160 mW (130..200) version 1 measured 146.7 +/- 2.0; the wider field adders and + comparators add switching when a field changes sign + gibbs-recall 12 mW (4..30) version 1 measured 6.7 +/- 1.8 (one core), 10.5 +/- 0.5 a core + (four-core build); fewer updates a second (25 M, not 33 M) but + the multipliers and a wider table read on each + t0-idle 4 mW (0..12) control and counters only, as version 1 (3.8 +/- 1.6) + null 0 mW, pass if |delta| < 2 SE + t0-recall at 50 MHz: half the 100 MHz value, pass if the ratio is within 2 SE of 0.5 + known answer (the 2026-09 vehicle, where present): 61.7 mW, pass if within 2 combined sigma diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/README.md b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/README.md new file mode 100644 index 000000000..b21b7b719 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/README.md @@ -0,0 +1,20 @@ +# 2026-11-06: rtl version 2, on the EMIO link and on the AXI link + +Raw output as the board wrote it. Board-level, one board, one meter. The `*.txt` files at the top +are the predictions and pre-registrations, each committed before the measurement it covers. + +| file | what | +|---|---| +| `PREDICTION.txt` | the class predictions for rtl version 2 | +| `first-attempt/` | 08:01 UTC on the EMIO build: the run/halt step and the known-answer vehicle; then the reload refused (the session check matched its own parent process, since fixed) | +| `emio-classes/` | 12:39 to 14:55 UTC on the EMIO build (sha256 `feea5015...`): step, null, settle, sampling, idle, the settle job at 50 MHz | +| `emio-checks/` | the same build afterwards: conformance, agreement, latency, throughput, the processor's port widths | +| `AXI-PREDICTION.txt` | committed at 13:06 UTC, during the class campaign and before its null had finished, and before the AXI build was metered | +| `NULL-REPEAT.txt` | committed at 15:03 UTC, after the class campaign ended and its null had failed, before the AXI build was metered | +| `axi-first/` | the first AXI build (sha256 `3d84dbd3...`, results read back by register reads): checks, then `power/` (the settle check and the repeated null) | +| `JOINT-PREREG.txt` | the joint-statistics test, registered before its first board run (`axi-first/joint.txt`) | +| `AXI-FINAL-PREDICTION.txt`, `axi-final/` | the final AXI build (sha256 `bb825055...`, results written back by DMA): checks, then `power/` (the settle check) | +| `build.txt` | the builds: tool and block versions, sizes, timing, each bitstream's sha256, and the testbenches' results | + +Summarise a meter log with `wai-quantum-landscape-fpga analyze ` or +`python3 scripts/power_tables.py `. diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/agree-axi.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/agree-axi.txt new file mode 100644 index 000000000..0153ebac5 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/agree-axi.txt @@ -0,0 +1,31 @@ +certified by the host on the conformance set: settle bit-exact, sample bit-exact +parity earned on this board: settle bit-exact, sample bit-exact +the worked examples on the board and on the CPU reference, 200 seeds each + [PASS] talks at its own temperature: 200/200 answers identical + [PASS] talks at temperature 0: 200/200 answers identical + [PASS] clusters at its own temperature: 200/200 answers identical + [PASS] clusters at temperature 0: 200/200 answers identical + [PASS] selection at its own temperature: 200/200 answers identical + [PASS] selection at temperature 0: 200/200 answers identical + [PASS] chain at its own temperature: 200/200 answers identical + [PASS] chain at temperature 0: 200/200 answers identical + [PASS] assign-2x2 at its own temperature: 200/200 answers identical + [PASS] assign-2x2 at temperature 0: 200/200 answers identical + [PASS] blocks at its own temperature: 200/200 answers identical + [PASS] blocks at temperature 0: 200/200 answers identical + [PASS] assign-3x3 at its own temperature: 200/200 answers identical + [PASS] assign-3x3 at temperature 0: 200/200 answers identical + [PASS] colour-six at its own temperature: 200/200 answers identical + [PASS] colour-six at temperature 0: 200/200 answers identical + [PASS] colour-four at its own temperature: 200/200 answers identical + [PASS] colour-four at temperature 0: 200/200 answers identical + [PASS] piles at its own temperature: 200/200 answers identical + [PASS] piles at temperature 0: 200/200 answers identical + [PASS] cold-constraint at its own temperature: 200/200 answers identical + [PASS] cold-constraint at temperature 0: 200/200 answers identical + [PASS] cold-start at its own temperature: 200/200 answers identical + [PASS] cold-start at temperature 0: 200/200 answers identical + [PASS] too-costly at its own temperature: 200/200 answers identical + [PASS] too-costly at temperature 0: 200/200 answers identical + [PASS] typo: refused by the reader before any member runs: Line 6: `oppos` is not a statement epuML knows. Did you mean `oppose`? +27 checks, 0 failed diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/conform-axi.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/conform-axi.txt new file mode 100644 index 000000000..e7903e3ca --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/conform-axi.txt @@ -0,0 +1,48 @@ +wai.quantum.landscape/1 member tests (quantum-conformance/landscape/vectors.json) +settle cases 13/13 bit for bit; chains 42/42 bit for bit + [PASS] settle kernel: the settle cases, bit for bit (state, sweeps, ending, accumulates), each held to the job + [PASS] sample kernel: the chain vectors, bit for bit (state, sweeps, ending, accumulates, draws), each held to the job + [PASS] cells: 650/650 cut points the host computes for the engine equal the set's, bit for bit + [PASS] cell h=-40 c=0 T=0.25: 100000 draws, counts [100000, 0, 0], z +0.00 +0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-40 c=2 T=1: 100000 draws, counts [100000, 0, 0], z +0.00 +0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-40 c=8 T=2.9: 100000 draws, counts [100000, 0, 0], z +1.27 -1.27 -0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-17 c=1 T=25: 100000 draws, counts [55805, 29689, 14506], z -1.59 +0.91 +1.07 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-17 c=8 T=0.7: 100000 draws, counts [99999, 1, 0], z -1.45 +1.45 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-5 c=1 T=1.8708286933869707: 100000 draws, counts [89058, 10527, 415], z -0.17 +0.28 -0.48 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-5 c=3 T=13.7: 100000 draws, counts [42641, 36802, 20557], z +0.11 -0.21 +0.12 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-3 c=1 T=0.3: 100000 draws, counts [99874, 126, 0], z +0.10 -0.10 -0.01 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-3 c=3 T=1.3: 100000 draws, counts [50015, 49537, 448], z +1.65 -1.37 -2.01 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-1 c=0 T=7.1: 100000 draws, counts [38122, 33245, 28633], z -0.00 +0.88 -0.91 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-1 c=3 T=0.25: 100000 draws, counts [32, 99968, 0], z -0.27 +0.27 -0.11 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=0 c=0 T=1: 100000 draws, counts [33342, 33254, 33404], z +0.06 -0.53 +0.47 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=0 c=2 T=2.9: 100000 draws, counts [24786, 50120, 25094], z -1.88 +1.31 +0.37 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=0 c=8 T=25: 100000 draws, counts [29353, 41113, 29534], z -1.79 +2.16 -0.53 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=1 c=2 T=0.7: 100000 draws, counts [1130, 79767, 19103], z +0.97 -0.12 -0.14 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=1 c=8 T=1.8708286933869707: 100000 draws, counts [801, 96844, 2355], z +0.43 -1.26 +1.20 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=2 c=1 T=13.7: 100000 draws, counts [27835, 34700, 37465], z -0.48 -0.22 +0.66 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=2 c=8 T=0.3: 100000 draws, counts [0, 100000, 0], z -0.00 +0.01 -0.01 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=3 c=1 T=1.3: 100000 draws, counts [835, 17462, 81703], z +0.94 -0.59 +0.36 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=3 c=3 T=7.1: 100000 draws, counts [17600, 41216, 41184], z -0.66 +0.36 +0.15 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=5 c=1 T=0.25: 100000 draws, counts [0, 0, 100000], z +0.00 -0.11 +0.11 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=5 c=3 T=1: 100000 draws, counts [9, 12006, 87985], z +2.50 +0.84 -0.89 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=9 c=0 T=2.9: 100000 draws, counts [204, 4140, 95656], z +0.83 -2.31 +2.09 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=9 c=2 T=25: 100000 draws, counts [21552, 33829, 44619], z -1.18 +0.85 +0.17 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=17 c=0 T=0.7: 100000 draws, counts [0, 0, 100000], z +0.00 -0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=17 c=2 T=1.8708286933869707: 100000 draws, counts [0, 36, 99964], z -0.04 +0.53 -0.53 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=17 c=8 T=13.7: 100000 draws, counts [5263, 32393, 62344], z +0.64 +0.21 -0.50 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=40 c=2 T=0.3: 100000 draws, counts [0, 0, 100000], z +0.00 +0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=40 c=8 T=1.3: 100000 draws, counts [0, 0, 100000], z +0.00 -0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] battery one-pair: chi-square 10.7 on 8 degrees of freedom (critical 28.0) + [PASS] battery a-pair-apart: chi-square 45.3 on 26 degrees of freedom (critical 62.1) + [PASS] battery a-pair-far-apart: chi-square 75.3 on 79 degrees of freedom (critical 141.8) + [PASS] battery a-triangle: chi-square 31.0 on 26 degrees of freedom (critical 62.1) + [PASS] battery wide-fields-and-cost: chi-square 18.3 on 22 degrees of freedom (critical 55.2) + [PASS] battery a-small-field-cold: chi-square 6.9 on 4 degrees of freedom (critical 18.1) + [PASS] battery ending-at-zero: chi-square 17.1 on 11 degrees of freedom (critical 34.5) + [PASS] battery cooling: chi-square 16.8 on 23 degrees of freedom (critical 56.9) + [PASS] the all-at-once control (every cell moved together) fails the battery on ["one-pair", "a-pair-apart", "a-pair-far-apart", "a-triangle", "a-small-field-cold", "ending-at-zero", "cooling"] + [PASS] jobs: 31/31 requests answer as the set says (state, energy, verdict, mode, restarts, sweeps, accumulates, draws, replay digest, or the refusal) + [PASS] 2000/2000 random workloads (2-64 cells, fields -5..5, cost 0-3) settle exactly as the reference does + [PASS] 4096/4096 fields read back equal W s + b (dense W, fields across the engine's ±524287) + [PASS] the engine still answers with its ID at the end: no other session replaced it +44 checks, 0 failed diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/joint.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/joint.txt new file mode 100644 index 000000000..f217931d4 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/joint.txt @@ -0,0 +1,23 @@ +joint statistics against exact enumeration (chains scaled by 1, seed 2027) + ring 8, fixed T = 1.5, 4 sweeps: 200000 chains, 2930 bins; exact law: chi2 3030.0 (p 0.095), G 3066.8 (p 0.037), TV 0.0436, cell |z| 1.91 (p 1.000), pair |z| 2.61 (p 1.000); same as the reference 200000/200000; 3.3 s + control, the same marginals with independent cells: chi2 244079.4 on 3247 bins (p 0.00e0), cell |z| 1.91 (p 1.000), pair |z| 86.9 (p 0.00e0) + [PASS] ring 8, fixed T = 1.5, 4 sweeps: the joint law is the exact law (every p at least 0.001) + [PASS] ring 8, fixed T = 1.5, 4 sweeps: every chain's final state is the reference's + [PASS] ring 8, fixed T = 1.5, 4 sweeps: the independent-cells control is rejected (chi-square p below 1e-6) + ring 8, the job's anneal from T = 2.5, 10 sweeps: 200000 chains, 45 bins; exact law: chi2 38.5 (p 0.708), G 38.6 (p 0.702), TV 0.0022, cell |z| 1.20 (p 1.000), pair |z| 2.35 (p 1.000); same as the reference 200000/200000; 5.7 s + control, the same marginals with independent cells: chi2 1933336.3 on 181 bins (p 0.00e0), cell |z| 1.20 (p 1.000), pair |z| 390.3 (p 0.00e0) + [PASS] ring 8, the job's anneal from T = 2.5, 10 sweeps: the joint law is the exact law (every p at least 0.001) + [PASS] ring 8, the job's anneal from T = 2.5, 10 sweeps: every chain's final state is the reference's + [PASS] ring 8, the job's anneal from T = 2.5, 10 sweeps: the independent-cells control is rejected (chi-square p below 1e-6) + dense 6, fixed T = 4, 2 sweeps: 200000 chains, 729 bins; exact law: chi2 682.6 (p 0.884), G 685.3 (p 0.870), TV 0.0219, cell |z| 1.73 (p 1.000), pair |z| 3.58 (p 0.047); same as the reference 200000/200000; 1.7 s + control, the same marginals with independent cells: chi2 91995.4 on 729 bins (p 0.00e0), cell |z| 1.73 (p 1.000), pair |z| 54.5 (p 0.00e0) + [PASS] dense 6, fixed T = 4, 2 sweeps: the joint law is the exact law (every p at least 0.001) + [PASS] dense 6, fixed T = 4, 2 sweeps: every chain's final state is the reference's + [PASS] dense 6, fixed T = 4, 2 sweeps: the independent-cells control is rejected (chi-square p below 1e-6) + sparse 10, the job's anneal from T = 1.5, 8 sweeps: 400000 chains, 190 bins; exact law: chi2 196.1 (p 0.346), G 207.7 (p 0.167), TV 0.0048, cell |z| 1.45 (p 1.000), pair |z| 3.04 (p 0.773); same as the reference 400000/400000; 11.4 s + control, the same marginals with independent cells: chi2 14139391.3 on 1531 bins (p 0.00e0), cell |z| 1.45 (p 1.000), pair |z| 373.6 (p 0.00e0) + [PASS] sparse 10, the job's anneal from T = 1.5, 8 sweeps: the joint law is the exact law (every p at least 0.001) + [PASS] sparse 10, the job's anneal from T = 1.5, 8 sweeps: every chain's final state is the reference's + [PASS] sparse 10, the job's anneal from T = 1.5, 8 sweeps: the independent-cells control is rejected (chi-square p below 1e-6) + [PASS] the engine still answers with its ID at the end: no other session replaced it +13 checks, 0 failed diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/latency-axi.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/latency-axi.txt new file mode 100644 index 000000000..9fa077542 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/latency-axi.txt @@ -0,0 +1,22 @@ +processor-to-logic latency, AXI link: one board, the engine at its measured clock + timer: CNTVCT_EL0 at 99.999 MHz, one tick 10.0 ns + the timer alone (two reads, an ISB each) median 10 ns p10 10 p90 20 p99 20 max 20 mean 11 (n 20000) + EMIO signature read (a processor GPIO register) median 230 ns p10 230 p90 240 p99 240 max 89851 mean 237 (n 100000) + AXI-Lite read, a link register median 230 ns p10 230 p90 230 p99 230 max 19920 mean 233 (n 100000) + AXI-Lite read, an engine register median 240 ns p10 240 p90 240 p99 240 max 25680 mean 242 (n 100000) + a DSB alone median 10 ns p10 10 p90 110 p99 150 max 10470 mean 28 (n 100000) + AXI-Lite write and its response (DSB), a link register median 250 ns p10 250 p90 350 p99 380 max 22460 mean 269 (n 100000) + AXI-Lite write and its response (DSB), an engine register median 250 ns p10 250 p90 350 p99 380 max 56791 mean 269 (n 100000) + AXI-Lite writes back to back, no DSB between: 51 ns each over 100000 + AXI-Lite write then read (select a cell, read its field) median 460 ns p10 460 p90 580 p99 600 max 53021 mean 481 (n 100000) + guarded read, as every job access goes (signature, then read) median 470 ns p10 460 p90 470 p99 470 max 21530 mean 470 (n 100000) + a 1-entry write list by DMA, kick to done (4 writes, polls) median 7640 ns p10 7570 p90 7790 p99 9340 max 25820 mean 7775 (n 5000) + a 512-entry write list by DMA (one page), kick to done median 20310 ns p10 20010 p90 20480 p99 23510 max 54711 mean 20433 (n 2000) + = 39.7 ns an entry, 25.2 M register writes/s + 128 chains' results written back (one page), kick to read median 37550 ns p10 37240 p90 37990 p99 47880 max 49670 mean 37825 (n 2000) + = 293 ns a chain + AXI, DMA and sequencer: a full table (64 levels x 128 fields, 32835 register writes): median 3.81 ms of 6, 116 ns a write + AXI, DMA and sequencer: 65536 chains of 8 cells x 4 sweeps: 0.285 s, 4.34 us a chain, 230153 chains/s + AXI, plain register accesses: a full table (64 levels x 128 fields, 32835 register writes): median 17.46 ms of 6, 532 ns a write + AXI, plain register accesses: 16384 chains of 8 cells x 4 sweeps: 0.154 s, 9.42 us a chain, 106113 chains/s + AXI accesses 1174977, DMA lists 8862, sequencer batches 257, write-backs 2714 diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/log.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/log.txt new file mode 100644 index 000000000..5c200e7fd --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/log.txt @@ -0,0 +1,7 @@ +2026-11-06T18:43:55Z start: engine answers: ID and version 0x00404002; measured clock 99.997 MHz +2026-11-06T18:44:09Z conform exit=0 +2026-11-06T18:44:20Z agree exit=0 +2026-11-06T18:44:42Z joint exit=0 +2026-11-06T18:44:44Z latency exit=0 +2026-11-06T18:44:48Z throughput exit=0 +2026-11-06T18:44:48Z end: engine answers: ID and version 0x00404002; measured clock 99.998 MHz diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/power/campaign.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/power/campaign.txt new file mode 100644 index 000000000..51583a7d5 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/power/campaign.txt @@ -0,0 +1,3 @@ +2026-11-06T18:45:00Z start: engine answers: ID and version 0x00404002; measured clock 99.998 MHz +2026-11-06T18:54:01Z t0-recall done exit=0 +2026-11-06T18:54:01Z end diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/power/t0-recall.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/power/t0-recall.dat new file mode 100644 index 000000000..db3c2ee6a --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/power/t0-recall.dat @@ -0,0 +1,195 @@ +# class t0-recall cores 1 link AXI +# wai-quantum-landscape-fpga meter passes=3 settle=60s samples=30 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793990700, tv_nsec: 679432036 } +# pass state sample power_uW +1 halt 1 3150000 +1 halt 2 3140000 +1 halt 3 3140000 +1 halt 4 3150000 +1 halt 5 3140000 +1 halt 6 3140000 +1 halt 7 3150000 +1 halt 8 3140000 +1 halt 9 3140000 +1 halt 10 3150000 +1 halt 11 3150000 +1 halt 12 3140000 +1 halt 13 3140000 +1 halt 14 3140000 +1 halt 15 3150000 +1 halt 16 3150000 +1 halt 17 3150000 +1 halt 18 3140000 +1 halt 19 3140000 +1 halt 20 3140000 +1 halt 21 3150000 +1 halt 22 3150000 +1 halt 23 3140000 +1 halt 24 3140000 +1 halt 25 3140000 +1 halt 26 3140000 +1 halt 27 3150000 +1 halt 28 3180000 +1 halt 29 3140000 +1 halt 30 3140000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997965 +1 run 1 3310000 +1 run 2 3320000 +1 run 3 3310000 +1 run 4 3300000 +1 run 5 3300000 +1 run 6 3300000 +1 run 7 3320000 +1 run 8 3300000 +1 run 9 3300000 +1 run 10 3330000 +1 run 11 3300000 +1 run 12 3310000 +1 run 13 3300000 +1 run 14 3300000 +1 run 15 3300000 +1 run 16 3300000 +1 run 17 3300000 +1 run 18 3300000 +1 run 19 3300000 +1 run 20 3310000 +1 run 21 3310000 +1 run 22 3300000 +1 run 23 3300000 +1 run 24 3300000 +1 run 25 3330000 +1 run 26 3300000 +1 run 27 3300000 +1 run 28 3300000 +1 run 29 3300000 +1 run 30 3300000 +# point pass=1 state=run jobs_per_s=12499746.7 updates_per_s=0.0 clock_hz=99997964 +2 run 1 3330000 +2 run 2 3310000 +2 run 3 3310000 +2 run 4 3320000 +2 run 5 3310000 +2 run 6 3320000 +2 run 7 3310000 +2 run 8 3320000 +2 run 9 3330000 +2 run 10 3330000 +2 run 11 3310000 +2 run 12 3320000 +2 run 13 3350000 +2 run 14 3310000 +2 run 15 3310000 +2 run 16 3300000 +2 run 17 3310000 +2 run 18 3330000 +2 run 19 3300000 +2 run 20 3320000 +2 run 21 3320000 +2 run 22 3310000 +2 run 23 3310000 +2 run 24 3300000 +2 run 25 3320000 +2 run 26 3320000 +2 run 27 3320000 +2 run 28 3590000 +2 run 29 3610000 +2 run 30 3310000 +# point pass=2 state=run jobs_per_s=12499746.9 updates_per_s=0.0 clock_hz=99997966 +2 halt 1 3420000 +2 halt 2 3420000 +2 halt 3 3130000 +2 halt 4 3140000 +2 halt 5 3130000 +2 halt 6 3160000 +2 halt 7 3150000 +2 halt 8 3140000 +2 halt 9 3130000 +2 halt 10 3140000 +2 halt 11 3140000 +2 halt 12 3140000 +2 halt 13 3130000 +2 halt 14 3130000 +2 halt 15 3150000 +2 halt 16 3140000 +2 halt 17 3150000 +2 halt 18 3140000 +2 halt 19 3130000 +2 halt 20 3150000 +2 halt 21 3140000 +2 halt 22 3140000 +2 halt 23 3460000 +2 halt 24 3140000 +2 halt 25 3140000 +2 halt 26 3130000 +2 halt 27 3140000 +2 halt 28 3140000 +2 halt 29 3130000 +2 halt 30 3140000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997939 +3 halt 1 3150000 +3 halt 2 3140000 +3 halt 3 3140000 +3 halt 4 3160000 +3 halt 5 3160000 +3 halt 6 3140000 +3 halt 7 3160000 +3 halt 8 3130000 +3 halt 9 3150000 +3 halt 10 3140000 +3 halt 11 3140000 +3 halt 12 3140000 +3 halt 13 3150000 +3 halt 14 3140000 +3 halt 15 3140000 +3 halt 16 3140000 +3 halt 17 3140000 +3 halt 18 3140000 +3 halt 19 3140000 +3 halt 20 3140000 +3 halt 21 3140000 +3 halt 22 3140000 +3 halt 23 3150000 +3 halt 24 3140000 +3 halt 25 3140000 +3 halt 26 3140000 +3 halt 27 3150000 +3 halt 28 3140000 +3 halt 29 3140000 +3 halt 30 3140000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997771 +3 run 1 3320000 +3 run 2 3300000 +3 run 3 3290000 +3 run 4 3290000 +3 run 5 3300000 +3 run 6 3290000 +3 run 7 3290000 +3 run 8 3310000 +3 run 9 3310000 +3 run 10 3620000 +3 run 11 3560000 +3 run 12 3300000 +3 run 13 3310000 +3 run 14 3300000 +3 run 15 3300000 +3 run 16 3310000 +3 run 17 3320000 +3 run 18 3300000 +3 run 19 3300000 +3 run 20 3310000 +3 run 21 3300000 +3 run 22 3310000 +3 run 23 3300000 +3 run 24 3300000 +3 run 25 3300000 +3 run 26 3330000 +3 run 27 3320000 +3 run 28 3290000 +3 run 29 3300000 +3 run 30 3310000 +# point pass=3 state=run jobs_per_s=12499726.1 updates_per_s=0.0 clock_hz=99997799 +# done SystemTime { tv_sec: 1793991241, tv_nsec: 34183769 } +# passes used 3 of 3 (dropped: []) +# run - halt = 166.7 +/- 6.7 mW (per-pass sd 11.5); 3/3 passes positive; 8 sample excursions beyond 6 MAD +# per-pass differences (mW): 160.0 180.0 160.0 +# board power while running 3307 mW; jobs/s 12499739.9; updates/s 0.0; measured PL clock 99.998 MHz +# pre-registered prediction 162.0 mW: measured/predicted = 1.03, 0.7 sigma from it diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/throughput-axi.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/throughput-axi.txt new file mode 100644 index 000000000..cf9a5dc7d --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-final/throughput-axi.txt @@ -0,0 +1,2 @@ +settle, dense 64 (recall cue): clock 99.998 MHz, 8.0 clocks a job, 12499745 jobs/s, 0.000e0 cell updates/s, 1.831e11 accumulates/s +sample, sequential, 64 cells, 8 sweeps at T = 0.25: clock 99.998 MHz, 2059.0 clocks a job, 48566 jobs/s, 2.487e7 cell updates/s, 1.138e9 accumulates/s diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/agree-axi.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/agree-axi.txt new file mode 100644 index 000000000..0153ebac5 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/agree-axi.txt @@ -0,0 +1,31 @@ +certified by the host on the conformance set: settle bit-exact, sample bit-exact +parity earned on this board: settle bit-exact, sample bit-exact +the worked examples on the board and on the CPU reference, 200 seeds each + [PASS] talks at its own temperature: 200/200 answers identical + [PASS] talks at temperature 0: 200/200 answers identical + [PASS] clusters at its own temperature: 200/200 answers identical + [PASS] clusters at temperature 0: 200/200 answers identical + [PASS] selection at its own temperature: 200/200 answers identical + [PASS] selection at temperature 0: 200/200 answers identical + [PASS] chain at its own temperature: 200/200 answers identical + [PASS] chain at temperature 0: 200/200 answers identical + [PASS] assign-2x2 at its own temperature: 200/200 answers identical + [PASS] assign-2x2 at temperature 0: 200/200 answers identical + [PASS] blocks at its own temperature: 200/200 answers identical + [PASS] blocks at temperature 0: 200/200 answers identical + [PASS] assign-3x3 at its own temperature: 200/200 answers identical + [PASS] assign-3x3 at temperature 0: 200/200 answers identical + [PASS] colour-six at its own temperature: 200/200 answers identical + [PASS] colour-six at temperature 0: 200/200 answers identical + [PASS] colour-four at its own temperature: 200/200 answers identical + [PASS] colour-four at temperature 0: 200/200 answers identical + [PASS] piles at its own temperature: 200/200 answers identical + [PASS] piles at temperature 0: 200/200 answers identical + [PASS] cold-constraint at its own temperature: 200/200 answers identical + [PASS] cold-constraint at temperature 0: 200/200 answers identical + [PASS] cold-start at its own temperature: 200/200 answers identical + [PASS] cold-start at temperature 0: 200/200 answers identical + [PASS] too-costly at its own temperature: 200/200 answers identical + [PASS] too-costly at temperature 0: 200/200 answers identical + [PASS] typo: refused by the reader before any member runs: Line 6: `oppos` is not a statement epuML knows. Did you mean `oppose`? +27 checks, 0 failed diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/conform-axi.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/conform-axi.txt new file mode 100644 index 000000000..e7903e3ca --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/conform-axi.txt @@ -0,0 +1,48 @@ +wai.quantum.landscape/1 member tests (quantum-conformance/landscape/vectors.json) +settle cases 13/13 bit for bit; chains 42/42 bit for bit + [PASS] settle kernel: the settle cases, bit for bit (state, sweeps, ending, accumulates), each held to the job + [PASS] sample kernel: the chain vectors, bit for bit (state, sweeps, ending, accumulates, draws), each held to the job + [PASS] cells: 650/650 cut points the host computes for the engine equal the set's, bit for bit + [PASS] cell h=-40 c=0 T=0.25: 100000 draws, counts [100000, 0, 0], z +0.00 +0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-40 c=2 T=1: 100000 draws, counts [100000, 0, 0], z +0.00 +0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-40 c=8 T=2.9: 100000 draws, counts [100000, 0, 0], z +1.27 -1.27 -0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-17 c=1 T=25: 100000 draws, counts [55805, 29689, 14506], z -1.59 +0.91 +1.07 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-17 c=8 T=0.7: 100000 draws, counts [99999, 1, 0], z -1.45 +1.45 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-5 c=1 T=1.8708286933869707: 100000 draws, counts [89058, 10527, 415], z -0.17 +0.28 -0.48 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-5 c=3 T=13.7: 100000 draws, counts [42641, 36802, 20557], z +0.11 -0.21 +0.12 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-3 c=1 T=0.3: 100000 draws, counts [99874, 126, 0], z +0.10 -0.10 -0.01 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-3 c=3 T=1.3: 100000 draws, counts [50015, 49537, 448], z +1.65 -1.37 -2.01 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-1 c=0 T=7.1: 100000 draws, counts [38122, 33245, 28633], z -0.00 +0.88 -0.91 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-1 c=3 T=0.25: 100000 draws, counts [32, 99968, 0], z -0.27 +0.27 -0.11 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=0 c=0 T=1: 100000 draws, counts [33342, 33254, 33404], z +0.06 -0.53 +0.47 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=0 c=2 T=2.9: 100000 draws, counts [24786, 50120, 25094], z -1.88 +1.31 +0.37 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=0 c=8 T=25: 100000 draws, counts [29353, 41113, 29534], z -1.79 +2.16 -0.53 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=1 c=2 T=0.7: 100000 draws, counts [1130, 79767, 19103], z +0.97 -0.12 -0.14 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=1 c=8 T=1.8708286933869707: 100000 draws, counts [801, 96844, 2355], z +0.43 -1.26 +1.20 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=2 c=1 T=13.7: 100000 draws, counts [27835, 34700, 37465], z -0.48 -0.22 +0.66 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=2 c=8 T=0.3: 100000 draws, counts [0, 100000, 0], z -0.00 +0.01 -0.01 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=3 c=1 T=1.3: 100000 draws, counts [835, 17462, 81703], z +0.94 -0.59 +0.36 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=3 c=3 T=7.1: 100000 draws, counts [17600, 41216, 41184], z -0.66 +0.36 +0.15 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=5 c=1 T=0.25: 100000 draws, counts [0, 0, 100000], z +0.00 -0.11 +0.11 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=5 c=3 T=1: 100000 draws, counts [9, 12006, 87985], z +2.50 +0.84 -0.89 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=9 c=0 T=2.9: 100000 draws, counts [204, 4140, 95656], z +0.83 -2.31 +2.09 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=9 c=2 T=25: 100000 draws, counts [21552, 33829, 44619], z -1.18 +0.85 +0.17 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=17 c=0 T=0.7: 100000 draws, counts [0, 0, 100000], z +0.00 -0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=17 c=2 T=1.8708286933869707: 100000 draws, counts [0, 36, 99964], z -0.04 +0.53 -0.53 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=17 c=8 T=13.7: 100000 draws, counts [5263, 32393, 62344], z +0.64 +0.21 -0.50 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=40 c=2 T=0.3: 100000 draws, counts [0, 0, 100000], z +0.00 +0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=40 c=8 T=1.3: 100000 draws, counts [0, 0, 100000], z +0.00 -0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] battery one-pair: chi-square 10.7 on 8 degrees of freedom (critical 28.0) + [PASS] battery a-pair-apart: chi-square 45.3 on 26 degrees of freedom (critical 62.1) + [PASS] battery a-pair-far-apart: chi-square 75.3 on 79 degrees of freedom (critical 141.8) + [PASS] battery a-triangle: chi-square 31.0 on 26 degrees of freedom (critical 62.1) + [PASS] battery wide-fields-and-cost: chi-square 18.3 on 22 degrees of freedom (critical 55.2) + [PASS] battery a-small-field-cold: chi-square 6.9 on 4 degrees of freedom (critical 18.1) + [PASS] battery ending-at-zero: chi-square 17.1 on 11 degrees of freedom (critical 34.5) + [PASS] battery cooling: chi-square 16.8 on 23 degrees of freedom (critical 56.9) + [PASS] the all-at-once control (every cell moved together) fails the battery on ["one-pair", "a-pair-apart", "a-pair-far-apart", "a-triangle", "a-small-field-cold", "ending-at-zero", "cooling"] + [PASS] jobs: 31/31 requests answer as the set says (state, energy, verdict, mode, restarts, sweeps, accumulates, draws, replay digest, or the refusal) + [PASS] 2000/2000 random workloads (2-64 cells, fields -5..5, cost 0-3) settle exactly as the reference does + [PASS] 4096/4096 fields read back equal W s + b (dense W, fields across the engine's ±524287) + [PASS] the engine still answers with its ID at the end: no other session replaced it +44 checks, 0 failed diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/joint.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/joint.txt new file mode 100644 index 000000000..9751b5fef --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/joint.txt @@ -0,0 +1,23 @@ +joint statistics against exact enumeration (chains scaled by 1, seed 2027) + ring 8, fixed T = 1.5, 4 sweeps: 200000 chains, 2930 bins; exact law: chi2 3030.0 (p 0.095), G 3066.8 (p 0.037), TV 0.0436, cell |z| 1.91 (p 1.000), pair |z| 2.61 (p 1.000); same as the reference 200000/200000; 3.7 s + control, the same marginals with independent cells: chi2 244079.4 on 3247 bins (p 0.00e0), cell |z| 1.91 (p 1.000), pair |z| 86.9 (p 0.00e0) + [PASS] ring 8, fixed T = 1.5, 4 sweeps: the joint law is the exact law (every p at least 0.001) + [PASS] ring 8, fixed T = 1.5, 4 sweeps: every chain's final state is the reference's + [PASS] ring 8, fixed T = 1.5, 4 sweeps: the independent-cells control is rejected (chi-square p below 1e-6) + ring 8, the job's anneal from T = 2.5, 10 sweeps: 200000 chains, 45 bins; exact law: chi2 38.5 (p 0.708), G 38.6 (p 0.702), TV 0.0022, cell |z| 1.20 (p 1.000), pair |z| 2.35 (p 1.000); same as the reference 200000/200000; 6.2 s + control, the same marginals with independent cells: chi2 1933336.3 on 181 bins (p 0.00e0), cell |z| 1.20 (p 1.000), pair |z| 390.3 (p 0.00e0) + [PASS] ring 8, the job's anneal from T = 2.5, 10 sweeps: the joint law is the exact law (every p at least 0.001) + [PASS] ring 8, the job's anneal from T = 2.5, 10 sweeps: every chain's final state is the reference's + [PASS] ring 8, the job's anneal from T = 2.5, 10 sweeps: the independent-cells control is rejected (chi-square p below 1e-6) + dense 6, fixed T = 4, 2 sweeps: 200000 chains, 729 bins; exact law: chi2 682.6 (p 0.884), G 685.3 (p 0.870), TV 0.0219, cell |z| 1.73 (p 1.000), pair |z| 3.58 (p 0.047); same as the reference 200000/200000; 2.1 s + control, the same marginals with independent cells: chi2 91995.4 on 729 bins (p 0.00e0), cell |z| 1.73 (p 1.000), pair |z| 54.5 (p 0.00e0) + [PASS] dense 6, fixed T = 4, 2 sweeps: the joint law is the exact law (every p at least 0.001) + [PASS] dense 6, fixed T = 4, 2 sweeps: every chain's final state is the reference's + [PASS] dense 6, fixed T = 4, 2 sweeps: the independent-cells control is rejected (chi-square p below 1e-6) + sparse 10, the job's anneal from T = 1.5, 8 sweeps: 400000 chains, 190 bins; exact law: chi2 196.1 (p 0.346), G 207.7 (p 0.167), TV 0.0048, cell |z| 1.45 (p 1.000), pair |z| 3.04 (p 0.773); same as the reference 400000/400000; 12.4 s + control, the same marginals with independent cells: chi2 14139391.3 on 1531 bins (p 0.00e0), cell |z| 1.45 (p 1.000), pair |z| 373.6 (p 0.00e0) + [PASS] sparse 10, the job's anneal from T = 1.5, 8 sweeps: the joint law is the exact law (every p at least 0.001) + [PASS] sparse 10, the job's anneal from T = 1.5, 8 sweeps: every chain's final state is the reference's + [PASS] sparse 10, the job's anneal from T = 1.5, 8 sweeps: the independent-cells control is rejected (chi-square p below 1e-6) + [PASS] the engine still answers with its ID at the end: no other session replaced it +13 checks, 0 failed diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/latency-axi.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/latency-axi.txt new file mode 100644 index 000000000..fc5f76b6c --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/latency-axi.txt @@ -0,0 +1,18 @@ +processor-to-logic latency, AXI link: one board, the engine at its measured clock + timer: CNTVCT_EL0 at 99.999 MHz, one tick 10.0 ns + the timer alone (two reads, an ISB each) median 10 ns p10 10 p90 20 p99 20 max 18810 mean 12 (n 20000) + EMIO signature read (a processor GPIO register) median 230 ns p10 230 p90 240 p99 240 max 28140 mean 236 (n 100000) + AXI-Lite read, a link register median 230 ns p10 230 p90 230 p99 230 max 22360 mean 233 (n 100000) + AXI-Lite read, an engine register median 240 ns p10 240 p90 240 p99 240 max 21600 mean 242 (n 100000) + AXI-Lite write, a link register median 10 ns p10 10 p90 20 p99 20 max 10370 mean 14 (n 100000) + AXI-Lite write, an engine register median 10 ns p10 10 p90 20 p99 20 max 38470 mean 14 (n 100000) + AXI-Lite write then read (select a cell, read its field) median 460 ns p10 460 p90 580 p99 600 max 47820 mean 481 (n 100000) + guarded read, as every job access goes (signature, then read) median 470 ns p10 460 p90 470 p99 470 max 19920 mean 469 (n 100000) + a 1-entry write list by DMA, kick to done (4 writes, polls) median 7460 ns p10 7340 p90 7790 p99 9400 max 28330 mean 7645 (n 5000) + a 512-entry write list by DMA (one page), kick to done median 20020 ns p10 19740 p90 20260 p99 29510 max 53911 mean 20197 (n 2000) + = 39.1 ns an entry, 25.6 M register writes/s + AXI, DMA and sequencer: a full table (64 levels x 128 fields, 32835 register writes): median 3.82 ms of 6, 116 ns a write + AXI, DMA and sequencer: 65536 chains of 8 cells x 4 sweeps: 0.436 s, 6.65 us a chain, 150472 chains/s + AXI, plain register accesses: a full table (64 levels x 128 fields, 32835 register writes): median 17.48 ms of 6, 532 ns a write + AXI, plain register accesses: 16384 chains of 8 cells x 4 sweeps: 0.154 s, 9.43 us a chain, 106053 chains/s + AXI accesses 1387388, DMA lists 8862, sequencer batches 257 diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/log.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/log.txt new file mode 100644 index 000000000..bc6e86a56 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/log.txt @@ -0,0 +1,7 @@ +2026-11-06T15:24:07Z start: engine answers: ID and version 0x00404002; measured clock 99.998 MHz +2026-11-06T15:24:28Z conform exit=0 +2026-11-06T15:24:39Z agree exit=0 +2026-11-06T15:25:03Z joint exit=0 +2026-11-06T15:25:05Z latency exit=0 +2026-11-06T15:25:09Z throughput exit=0 +2026-11-06T15:25:10Z end: engine answers: ID and version 0x00404002; measured clock 99.998 MHz diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/power/campaign.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/power/campaign.txt new file mode 100644 index 000000000..3e0edd6f1 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/power/campaign.txt @@ -0,0 +1,4 @@ +2026-11-06T15:25:28Z start: engine answers: ID and version 0x00404002; measured clock 99.998 MHz +2026-11-06T15:34:28Z t0-recall done exit=0 +2026-11-06T15:58:29Z null done exit=0 +2026-11-06T15:58:29Z end diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/power/null.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/power/null.dat new file mode 100644 index 000000000..bfb582c85 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/power/null.dat @@ -0,0 +1,505 @@ +# class t0-recall cores 1 link AXI +# wai-quantum-landscape-fpga meter passes=8 settle=60s samples=30 null=true sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793979268, tv_nsec: 870353142 } +# pass state sample power_uW +1 run 1 3140000 +1 run 2 3130000 +1 run 3 3130000 +1 run 4 3130000 +1 run 5 3130000 +1 run 6 3140000 +1 run 7 3120000 +1 run 8 3140000 +1 run 9 3130000 +1 run 10 3120000 +1 run 11 3130000 +1 run 12 3130000 +1 run 13 3140000 +1 run 14 3140000 +1 run 15 3150000 +1 run 16 3130000 +1 run 17 3140000 +1 run 18 3140000 +1 run 19 3130000 +1 run 20 3140000 +1 run 21 3130000 +1 run 22 3130000 +1 run 23 3150000 +1 run 24 3130000 +1 run 25 3140000 +1 run 26 3120000 +1 run 27 3130000 +1 run 28 3140000 +1 run 29 3130000 +1 run 30 3110000 +# point pass=1 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997489 +1 halt 1 3130000 +1 halt 2 3130000 +1 halt 3 3150000 +1 halt 4 3130000 +1 halt 5 3130000 +1 halt 6 3120000 +1 halt 7 3170000 +1 halt 8 3140000 +1 halt 9 3140000 +1 halt 10 3140000 +1 halt 11 3160000 +1 halt 12 3160000 +1 halt 13 3140000 +1 halt 14 3140000 +1 halt 15 3140000 +1 halt 16 3140000 +1 halt 17 3150000 +1 halt 18 3140000 +1 halt 19 3150000 +1 halt 20 3150000 +1 halt 21 3140000 +1 halt 22 3140000 +1 halt 23 3140000 +1 halt 24 3140000 +1 halt 25 3140000 +1 halt 26 3140000 +1 halt 27 3270000 +1 halt 28 3140000 +1 halt 29 3130000 +1 halt 30 3130000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997556 +2 halt 1 3140000 +2 halt 2 3140000 +2 halt 3 3140000 +2 halt 4 3130000 +2 halt 5 3150000 +2 halt 6 3140000 +2 halt 7 3140000 +2 halt 8 3160000 +2 halt 9 3150000 +2 halt 10 3140000 +2 halt 11 3140000 +2 halt 12 3140000 +2 halt 13 3150000 +2 halt 14 3140000 +2 halt 15 3140000 +2 halt 16 3140000 +2 halt 17 3150000 +2 halt 18 3140000 +2 halt 19 3140000 +2 halt 20 3150000 +2 halt 21 3150000 +2 halt 22 3150000 +2 halt 23 3140000 +2 halt 24 3150000 +2 halt 25 3140000 +2 halt 26 3140000 +2 halt 27 3140000 +2 halt 28 3140000 +2 halt 29 3140000 +2 halt 30 3140000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997613 +2 run 1 3130000 +2 run 2 3140000 +2 run 3 3140000 +2 run 4 3130000 +2 run 5 3150000 +2 run 6 3140000 +2 run 7 3130000 +2 run 8 3140000 +2 run 9 3130000 +2 run 10 3140000 +2 run 11 3140000 +2 run 12 3140000 +2 run 13 3140000 +2 run 14 3130000 +2 run 15 3140000 +2 run 16 3140000 +2 run 17 3130000 +2 run 18 3140000 +2 run 19 3140000 +2 run 20 3140000 +2 run 21 3130000 +2 run 22 3130000 +2 run 23 3130000 +2 run 24 3140000 +2 run 25 3140000 +2 run 26 3140000 +2 run 27 3120000 +2 run 28 3150000 +2 run 29 3160000 +2 run 30 3140000 +# point pass=2 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997660 +3 halt 1 3140000 +3 halt 2 3150000 +3 halt 3 3130000 +3 halt 4 3140000 +3 halt 5 3140000 +3 halt 6 3130000 +3 halt 7 3140000 +3 halt 8 3150000 +3 halt 9 3140000 +3 halt 10 3140000 +3 halt 11 3140000 +3 halt 12 3140000 +3 halt 13 3140000 +3 halt 14 3140000 +3 halt 15 3130000 +3 halt 16 3140000 +3 halt 17 3150000 +3 halt 18 3140000 +3 halt 19 3140000 +3 halt 20 3140000 +3 halt 21 3140000 +3 halt 22 3130000 +3 halt 23 3140000 +3 halt 24 3140000 +3 halt 25 3150000 +3 halt 26 3150000 +3 halt 27 3140000 +3 halt 28 3140000 +3 halt 29 3130000 +3 halt 30 3130000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997700 +3 run 1 3140000 +3 run 2 3140000 +3 run 3 3140000 +3 run 4 3160000 +3 run 5 3140000 +3 run 6 3130000 +3 run 7 3140000 +3 run 8 3130000 +3 run 9 3140000 +3 run 10 3140000 +3 run 11 3140000 +3 run 12 3150000 +3 run 13 3170000 +3 run 14 3140000 +3 run 15 3130000 +3 run 16 3130000 +3 run 17 3150000 +3 run 18 3130000 +3 run 19 3140000 +3 run 20 3140000 +3 run 21 3150000 +3 run 22 3130000 +3 run 23 3140000 +3 run 24 3130000 +3 run 25 3140000 +3 run 26 3140000 +3 run 27 3140000 +3 run 28 3140000 +3 run 29 3130000 +3 run 30 3140000 +# point pass=3 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997734 +4 halt 1 3150000 +4 halt 2 3140000 +4 halt 3 3140000 +4 halt 4 3140000 +4 halt 5 3140000 +4 halt 6 3140000 +4 halt 7 3140000 +4 halt 8 3140000 +4 halt 9 3160000 +4 halt 10 3140000 +4 halt 11 3140000 +4 halt 12 3140000 +4 halt 13 3140000 +4 halt 14 3140000 +4 halt 15 3140000 +4 halt 16 3130000 +4 halt 17 3130000 +4 halt 18 3140000 +4 halt 19 3140000 +4 halt 20 3130000 +4 halt 21 3160000 +4 halt 22 3140000 +4 halt 23 3140000 +4 halt 24 3150000 +4 halt 25 3140000 +4 halt 26 3140000 +4 halt 27 3140000 +4 halt 28 3140000 +4 halt 29 3140000 +4 halt 30 3130000 +# point pass=4 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997763 +4 run 1 3140000 +4 run 2 3140000 +4 run 3 3140000 +4 run 4 3140000 +4 run 5 3150000 +4 run 6 3150000 +4 run 7 3140000 +4 run 8 3140000 +4 run 9 3140000 +4 run 10 3140000 +4 run 11 3140000 +4 run 12 3140000 +4 run 13 3140000 +4 run 14 3140000 +4 run 15 3140000 +4 run 16 3130000 +4 run 17 3140000 +4 run 18 3150000 +4 run 19 3140000 +4 run 20 3140000 +4 run 21 3170000 +4 run 22 3120000 +4 run 23 3140000 +4 run 24 3140000 +4 run 25 3140000 +4 run 26 3150000 +4 run 27 3140000 +4 run 28 3140000 +4 run 29 3150000 +4 run 30 3140000 +# point pass=4 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997789 +5 halt 1 3150000 +5 halt 2 3150000 +5 halt 3 3140000 +5 halt 4 3140000 +5 halt 5 3150000 +5 halt 6 3150000 +5 halt 7 3150000 +5 halt 8 3140000 +5 halt 9 3150000 +5 halt 10 3150000 +5 halt 11 3140000 +5 halt 12 3140000 +5 halt 13 3140000 +5 halt 14 3140000 +5 halt 15 3140000 +5 halt 16 3150000 +5 halt 17 3150000 +5 halt 18 3160000 +5 halt 19 3140000 +5 halt 20 3140000 +5 halt 21 3150000 +5 halt 22 3150000 +5 halt 23 3150000 +5 halt 24 3150000 +5 halt 25 3150000 +5 halt 26 3160000 +5 halt 27 3140000 +5 halt 28 3150000 +5 halt 29 3150000 +5 halt 30 3150000 +# point pass=5 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997804 +5 run 1 3140000 +5 run 2 3160000 +5 run 3 3140000 +5 run 4 3140000 +5 run 5 3140000 +5 run 6 3160000 +5 run 7 3140000 +5 run 8 3140000 +5 run 9 3150000 +5 run 10 3140000 +5 run 11 3140000 +5 run 12 3210000 +5 run 13 3140000 +5 run 14 3160000 +5 run 15 3160000 +5 run 16 3150000 +5 run 17 3140000 +5 run 18 3140000 +5 run 19 3150000 +5 run 20 3150000 +5 run 21 3150000 +5 run 22 3150000 +5 run 23 3180000 +5 run 24 3140000 +5 run 25 3150000 +5 run 26 3140000 +5 run 27 3150000 +5 run 28 3140000 +5 run 29 3130000 +5 run 30 3140000 +# point pass=5 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997821 +6 halt 1 3150000 +6 halt 2 3160000 +6 halt 3 3150000 +6 halt 4 3140000 +6 halt 5 3150000 +6 halt 6 3140000 +6 halt 7 3140000 +6 halt 8 3140000 +6 halt 9 3140000 +6 halt 10 3140000 +6 halt 11 3150000 +6 halt 12 3140000 +6 halt 13 3140000 +6 halt 14 3140000 +6 halt 15 3140000 +6 halt 16 3140000 +6 halt 17 3140000 +6 halt 18 3130000 +6 halt 19 3140000 +6 halt 20 3140000 +6 halt 21 3140000 +6 halt 22 3140000 +6 halt 23 3160000 +6 halt 24 3150000 +6 halt 25 3150000 +6 halt 26 3150000 +6 halt 27 3140000 +6 halt 28 3140000 +6 halt 29 3150000 +6 halt 30 3140000 +# point pass=6 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997835 +6 run 1 3150000 +6 run 2 3170000 +6 run 3 3140000 +6 run 4 3150000 +6 run 5 3150000 +6 run 6 3150000 +6 run 7 3410000 +6 run 8 3160000 +6 run 9 3150000 +6 run 10 3150000 +6 run 11 3150000 +6 run 12 3280000 +6 run 13 3140000 +6 run 14 3140000 +6 run 15 3150000 +6 run 16 3150000 +6 run 17 3150000 +6 run 18 3140000 +6 run 19 3150000 +6 run 20 3150000 +6 run 21 3140000 +6 run 22 3150000 +6 run 23 3150000 +6 run 24 3140000 +6 run 25 3150000 +6 run 26 3140000 +6 run 27 3140000 +6 run 28 3150000 +6 run 29 3140000 +6 run 30 3140000 +# point pass=6 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997847 +7 run 1 3140000 +7 run 2 3140000 +7 run 3 3150000 +7 run 4 3140000 +7 run 5 3140000 +7 run 6 3140000 +7 run 7 3140000 +7 run 8 3140000 +7 run 9 3140000 +7 run 10 3140000 +7 run 11 3140000 +7 run 12 3140000 +7 run 13 3130000 +7 run 14 3140000 +7 run 15 3140000 +7 run 16 3140000 +7 run 17 3140000 +7 run 18 3140000 +7 run 19 3140000 +7 run 20 3160000 +7 run 21 3140000 +7 run 22 3130000 +7 run 23 3140000 +7 run 24 3140000 +7 run 25 3140000 +7 run 26 3140000 +7 run 27 3140000 +7 run 28 3150000 +7 run 29 3130000 +7 run 30 3140000 +# point pass=7 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997856 +7 halt 1 3140000 +7 halt 2 3140000 +7 halt 3 3230000 +7 halt 4 3140000 +7 halt 5 3130000 +7 halt 6 3130000 +7 halt 7 3140000 +7 halt 8 3150000 +7 halt 9 3140000 +7 halt 10 3140000 +7 halt 11 3130000 +7 halt 12 3130000 +7 halt 13 3140000 +7 halt 14 3130000 +7 halt 15 3140000 +7 halt 16 3150000 +7 halt 17 3150000 +7 halt 18 3130000 +7 halt 19 3140000 +7 halt 20 3140000 +7 halt 21 3130000 +7 halt 22 3130000 +7 halt 23 3120000 +7 halt 24 3130000 +7 halt 25 3160000 +7 halt 26 3130000 +7 halt 27 3130000 +7 halt 28 3130000 +7 halt 29 3130000 +7 halt 30 3130000 +# point pass=7 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997864 +8 halt 1 3140000 +8 halt 2 3130000 +8 halt 3 3140000 +8 halt 4 3140000 +8 halt 5 3150000 +8 halt 6 3140000 +8 halt 7 3140000 +8 halt 8 3140000 +8 halt 9 3140000 +8 halt 10 3130000 +8 halt 11 3140000 +8 halt 12 3140000 +8 halt 13 3160000 +8 halt 14 3150000 +8 halt 15 3140000 +8 halt 16 3150000 +8 halt 17 3140000 +8 halt 18 3150000 +8 halt 19 3140000 +8 halt 20 3150000 +8 halt 21 3140000 +8 halt 22 3150000 +8 halt 23 3140000 +8 halt 24 3140000 +8 halt 25 3130000 +8 halt 26 3130000 +8 halt 27 3140000 +8 halt 28 3140000 +8 halt 29 3140000 +8 halt 30 3140000 +# point pass=8 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997871 +8 run 1 3140000 +8 run 2 3140000 +8 run 3 3130000 +8 run 4 3130000 +8 run 5 3140000 +8 run 6 3140000 +8 run 7 3130000 +8 run 8 3120000 +8 run 9 3120000 +8 run 10 3150000 +8 run 11 3120000 +8 run 12 3140000 +8 run 13 3120000 +8 run 14 3140000 +8 run 15 3130000 +8 run 16 3130000 +8 run 17 3130000 +8 run 18 3130000 +8 run 19 3130000 +8 run 20 3130000 +8 run 21 3140000 +8 run 22 3130000 +8 run 23 3130000 +8 run 24 3120000 +8 run 25 3140000 +8 run 26 3140000 +8 run 27 3140000 +8 run 28 3130000 +8 run 29 3120000 +8 run 30 3150000 +# point pass=8 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997878 +# done SystemTime { tv_sec: 1793980709, tv_nsec: 798912421 } +# passes used 8 of 8 (dropped: []) +# run - halt = -1.9 +/- 2.7 mW (per-pass sd 7.5); 2/8 passes positive; 6 sample excursions beyond 6 MAD +# per-pass differences (mW): -10.0 0.0 0.0 0.0 -10.0 10.0 5.0 -10.0 +# board power while running 3139 mW; jobs/s 0.0; updates/s 0.0; measured PL clock 99.998 MHz +# pre-registered prediction 0.0 mW: measured/predicted = -inf, -0.7 sigma from it diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/power/t0-recall.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/power/t0-recall.dat new file mode 100644 index 000000000..3a53545fd --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/power/t0-recall.dat @@ -0,0 +1,195 @@ +# class t0-recall cores 1 link AXI +# wai-quantum-landscape-fpga meter passes=3 settle=60s samples=30 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793978728, tv_nsec: 458975042 } +# pass state sample power_uW +1 halt 1 3150000 +1 halt 2 3160000 +1 halt 3 3140000 +1 halt 4 3150000 +1 halt 5 3150000 +1 halt 6 3150000 +1 halt 7 3140000 +1 halt 8 3140000 +1 halt 9 3150000 +1 halt 10 3150000 +1 halt 11 3140000 +1 halt 12 3150000 +1 halt 13 3170000 +1 halt 14 3160000 +1 halt 15 3150000 +1 halt 16 3140000 +1 halt 17 3150000 +1 halt 18 3150000 +1 halt 19 3150000 +1 halt 20 3170000 +1 halt 21 3150000 +1 halt 22 3150000 +1 halt 23 3140000 +1 halt 24 3140000 +1 halt 25 3140000 +1 halt 26 3140000 +1 halt 27 3140000 +1 halt 28 3150000 +1 halt 29 3140000 +1 halt 30 3150000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99996704 +1 run 1 3330000 +1 run 2 3320000 +1 run 3 3300000 +1 run 4 3300000 +1 run 5 3300000 +1 run 6 3310000 +1 run 7 3300000 +1 run 8 3290000 +1 run 9 3290000 +1 run 10 3330000 +1 run 11 3300000 +1 run 12 3300000 +1 run 13 3300000 +1 run 14 3300000 +1 run 15 3310000 +1 run 16 3300000 +1 run 17 3300000 +1 run 18 3300000 +1 run 19 3290000 +1 run 20 3300000 +1 run 21 3320000 +1 run 22 3290000 +1 run 23 3300000 +1 run 24 3300000 +1 run 25 3320000 +1 run 26 3300000 +1 run 27 3310000 +1 run 28 3300000 +1 run 29 3300000 +1 run 30 3300000 +# point pass=1 state=run jobs_per_s=12499613.3 updates_per_s=0.0 clock_hz=99996898 +2 run 1 3300000 +2 run 2 3300000 +2 run 3 3420000 +2 run 4 3310000 +2 run 5 3310000 +2 run 6 3300000 +2 run 7 3330000 +2 run 8 3300000 +2 run 9 3300000 +2 run 10 3300000 +2 run 11 3310000 +2 run 12 3300000 +2 run 13 3320000 +2 run 14 3310000 +2 run 15 3310000 +2 run 16 3300000 +2 run 17 3300000 +2 run 18 3290000 +2 run 19 3300000 +2 run 20 3300000 +2 run 21 3310000 +2 run 22 3320000 +2 run 23 3300000 +2 run 24 3300000 +2 run 25 3310000 +2 run 26 3300000 +2 run 27 3320000 +2 run 28 3310000 +2 run 29 3310000 +2 run 30 3330000 +# point pass=2 state=run jobs_per_s=12499633.8 updates_per_s=0.0 clock_hz=99997061 +2 halt 1 3140000 +2 halt 2 3130000 +2 halt 3 3140000 +2 halt 4 3150000 +2 halt 5 3140000 +2 halt 6 3140000 +2 halt 7 3140000 +2 halt 8 3140000 +2 halt 9 3140000 +2 halt 10 3130000 +2 halt 11 3140000 +2 halt 12 3130000 +2 halt 13 3140000 +2 halt 14 3140000 +2 halt 15 3130000 +2 halt 16 3140000 +2 halt 17 3140000 +2 halt 18 3150000 +2 halt 19 3150000 +2 halt 20 3130000 +2 halt 21 3140000 +2 halt 22 3140000 +2 halt 23 3130000 +2 halt 24 3140000 +2 halt 25 3140000 +2 halt 26 3140000 +2 halt 27 3150000 +2 halt 28 3140000 +2 halt 29 3140000 +2 halt 30 3130000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997197 +3 run 1 3290000 +3 run 2 3300000 +3 run 3 3300000 +3 run 4 3290000 +3 run 5 3300000 +3 run 6 3300000 +3 run 7 3310000 +3 run 8 3300000 +3 run 9 3300000 +3 run 10 3300000 +3 run 11 3300000 +3 run 12 3300000 +3 run 13 3300000 +3 run 14 3300000 +3 run 15 3310000 +3 run 16 3320000 +3 run 17 3290000 +3 run 18 3300000 +3 run 19 3300000 +3 run 20 3290000 +3 run 21 3310000 +3 run 22 3290000 +3 run 23 3300000 +3 run 24 3310000 +3 run 25 3300000 +3 run 26 3300000 +3 run 27 3290000 +3 run 28 3290000 +3 run 29 3310000 +3 run 30 3300000 +# point pass=3 state=run jobs_per_s=12499665.2 updates_per_s=0.0 clock_hz=99997312 +3 halt 1 3130000 +3 halt 2 3170000 +3 halt 3 3140000 +3 halt 4 3160000 +3 halt 5 3140000 +3 halt 6 3150000 +3 halt 7 3140000 +3 halt 8 3140000 +3 halt 9 3140000 +3 halt 10 3150000 +3 halt 11 3150000 +3 halt 12 3150000 +3 halt 13 3140000 +3 halt 14 3140000 +3 halt 15 3140000 +3 halt 16 3140000 +3 halt 17 3140000 +3 halt 18 3140000 +3 halt 19 3140000 +3 halt 20 3140000 +3 halt 21 3150000 +3 halt 22 3140000 +3 halt 23 3150000 +3 halt 24 3140000 +3 halt 25 3140000 +3 halt 26 3150000 +3 halt 27 3150000 +3 halt 28 3140000 +3 halt 29 3160000 +3 halt 30 3150000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997408 +# done SystemTime { tv_sec: 1793979268, tv_nsec: 808725935 } +# passes used 3 of 3 (dropped: []) +# run - halt = 158.3 +/- 4.4 mW (per-pass sd 7.6); 3/3 passes positive; 1 sample excursions beyond 6 MAD +# per-pass differences (mW): 150.0 165.0 160.0 +# board power while running 3302 mW; jobs/s 12499637.5; updates/s 0.0; measured PL clock 99.997 MHz +# pre-registered prediction 162.0 mW: measured/predicted = 0.98, -0.8 sigma from it diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/throughput-axi.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/throughput-axi.txt new file mode 100644 index 000000000..3356f2af1 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/axi-first/throughput-axi.txt @@ -0,0 +1,2 @@ +settle, dense 64 (recall cue): clock 99.998 MHz, 8.0 clocks a job, 12499763 jobs/s, 0.000e0 cell updates/s, 1.831e11 accumulates/s +sample, sequential, 64 cells, 8 sweeps at T = 0.25: clock 99.998 MHz, 2059.0 clocks a job, 48567 jobs/s, 2.487e7 cell updates/s, 1.138e9 accumulates/s diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/build.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/build.txt new file mode 100644 index 000000000..d7a5c06b2 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/build.txt @@ -0,0 +1,33 @@ +The builds measured on 2026-11-06, and the testbenches' results. Copied from the tool's reports and +logs (its utilisation and timing reports, its build log, sha256sum), the lines that bear on the +README, without the reports' headers. + +TOOL + Vivado v2026.1 (lin64), build 6511674. Blocks: zynq_ultra_ps_e 3.5; in the AXI builds also + axi_dwidth_converter 2.1 (twice) and axi_protocol_converter 2.1. + The AXI builds ran with JOBS 1, general.maxThreads 2, under a 10 GB memory cap; the tool's own + peak, as its log reports it, was 5,140 MB. An earlier attempt with JOBS 2 and no cap, on a 15 GB + machine shared with other builds, ran the machine out of memory. + +BUILDS (part xck26-sfvc784-2LV-c, 100 MHz) + build sha256 of the .bit.bin LUTs registers BRAM tiles URAM DSP WNS WHS + AXI, final (write-back) bb82505526e33403073924373a64d3519394344e9bf6d0193634c157e42b6dfb 28145 (24.03%) 13773 4 4 20 0.993 ns 0.012 ns + AXI, first (no write-back) 3d84dbd355c9552c7593d3d5aa823284a4941acd25e5f3b7c92d5c0bc36ee441 27666 (23.62%) 13220 4 4 20 0.698 ns 0.012 ns + EMIO, one engine feea5015b2f8d85049fd48bcc66493a411d551326365f67b1db2ae65ec00074c 25539 (21.81%) 11121 0 4 20 0.294 ns 0.069 ns + EMIO, four engines 2a73f02b5a6097bd251962b7d91f5ca368180db162941465aa32129130b06b09 80927 (69.10%) 44355 0 16 80 0.441 ns 0.010 ns + (four engines: 13,925 of 14,640 slices, 95.12%; not loaded on the board this day) + All four: 0 failing endpoints, setup and hold. The AXI builds report one critical warning, a + false-path constraint for the EMIO port's synchroniser that finds no cell in them. + +TESTBENCHES, on the scripts gen-tb records from this commit's model (sha256 of each script) + EMIO landscape_tb.script 4fb49e25f794849db750d688755ef452f05fb9146fd0cb016ad0b533dee5205e + Icarus Verilog 13.0: TB DONE: 174345 lines, 2668 checked reads, 0 mismatches, sim time 26571197000 + xsim v2026.1: TB DONE: 174345 lines, 2668 checked reads, 0 mismatches, sim time 26571197000 + AXI landscape_axi_tb.script 927b463dd40b9a3535fe77a770656415b58ce2dae33a93bf3299b3ab5252fc5c + 171 write lists, 50 batches, 50 write-backs + Icarus Verilog 13.0: TB DONE: 175830 lines, 4464 checked reads, 0 mismatches, sim time 6878426000 + xsim v2026.1: TB DONE: 175830 lines, 4464 checked reads, 0 mismatches, sim time 6878426000 + A flipped expected word in a write-back's results (xsim, the earlier script): + MISMATCH line 1231: written back chain 0 word 2 got 00000000 want f0000000 + The RTL the scripts ran against is the final AXI build's: no file under rtl/ that it is built + from has changed since that build but for comments. diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/agree-emio.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/agree-emio.txt new file mode 100644 index 000000000..0153ebac5 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/agree-emio.txt @@ -0,0 +1,31 @@ +certified by the host on the conformance set: settle bit-exact, sample bit-exact +parity earned on this board: settle bit-exact, sample bit-exact +the worked examples on the board and on the CPU reference, 200 seeds each + [PASS] talks at its own temperature: 200/200 answers identical + [PASS] talks at temperature 0: 200/200 answers identical + [PASS] clusters at its own temperature: 200/200 answers identical + [PASS] clusters at temperature 0: 200/200 answers identical + [PASS] selection at its own temperature: 200/200 answers identical + [PASS] selection at temperature 0: 200/200 answers identical + [PASS] chain at its own temperature: 200/200 answers identical + [PASS] chain at temperature 0: 200/200 answers identical + [PASS] assign-2x2 at its own temperature: 200/200 answers identical + [PASS] assign-2x2 at temperature 0: 200/200 answers identical + [PASS] blocks at its own temperature: 200/200 answers identical + [PASS] blocks at temperature 0: 200/200 answers identical + [PASS] assign-3x3 at its own temperature: 200/200 answers identical + [PASS] assign-3x3 at temperature 0: 200/200 answers identical + [PASS] colour-six at its own temperature: 200/200 answers identical + [PASS] colour-six at temperature 0: 200/200 answers identical + [PASS] colour-four at its own temperature: 200/200 answers identical + [PASS] colour-four at temperature 0: 200/200 answers identical + [PASS] piles at its own temperature: 200/200 answers identical + [PASS] piles at temperature 0: 200/200 answers identical + [PASS] cold-constraint at its own temperature: 200/200 answers identical + [PASS] cold-constraint at temperature 0: 200/200 answers identical + [PASS] cold-start at its own temperature: 200/200 answers identical + [PASS] cold-start at temperature 0: 200/200 answers identical + [PASS] too-costly at its own temperature: 200/200 answers identical + [PASS] too-costly at temperature 0: 200/200 answers identical + [PASS] typo: refused by the reader before any member runs: Line 6: `oppos` is not a statement epuML knows. Did you mean `oppose`? +27 checks, 0 failed diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/conform-emio.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/conform-emio.txt new file mode 100644 index 000000000..e7903e3ca --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/conform-emio.txt @@ -0,0 +1,48 @@ +wai.quantum.landscape/1 member tests (quantum-conformance/landscape/vectors.json) +settle cases 13/13 bit for bit; chains 42/42 bit for bit + [PASS] settle kernel: the settle cases, bit for bit (state, sweeps, ending, accumulates), each held to the job + [PASS] sample kernel: the chain vectors, bit for bit (state, sweeps, ending, accumulates, draws), each held to the job + [PASS] cells: 650/650 cut points the host computes for the engine equal the set's, bit for bit + [PASS] cell h=-40 c=0 T=0.25: 100000 draws, counts [100000, 0, 0], z +0.00 +0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-40 c=2 T=1: 100000 draws, counts [100000, 0, 0], z +0.00 +0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-40 c=8 T=2.9: 100000 draws, counts [100000, 0, 0], z +1.27 -1.27 -0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-17 c=1 T=25: 100000 draws, counts [55805, 29689, 14506], z -1.59 +0.91 +1.07 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-17 c=8 T=0.7: 100000 draws, counts [99999, 1, 0], z -1.45 +1.45 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-5 c=1 T=1.8708286933869707: 100000 draws, counts [89058, 10527, 415], z -0.17 +0.28 -0.48 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-5 c=3 T=13.7: 100000 draws, counts [42641, 36802, 20557], z +0.11 -0.21 +0.12 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-3 c=1 T=0.3: 100000 draws, counts [99874, 126, 0], z +0.10 -0.10 -0.01 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-3 c=3 T=1.3: 100000 draws, counts [50015, 49537, 448], z +1.65 -1.37 -2.01 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-1 c=0 T=7.1: 100000 draws, counts [38122, 33245, 28633], z -0.00 +0.88 -0.91 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=-1 c=3 T=0.25: 100000 draws, counts [32, 99968, 0], z -0.27 +0.27 -0.11 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=0 c=0 T=1: 100000 draws, counts [33342, 33254, 33404], z +0.06 -0.53 +0.47 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=0 c=2 T=2.9: 100000 draws, counts [24786, 50120, 25094], z -1.88 +1.31 +0.37 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=0 c=8 T=25: 100000 draws, counts [29353, 41113, 29534], z -1.79 +2.16 -0.53 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=1 c=2 T=0.7: 100000 draws, counts [1130, 79767, 19103], z +0.97 -0.12 -0.14 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=1 c=8 T=1.8708286933869707: 100000 draws, counts [801, 96844, 2355], z +0.43 -1.26 +1.20 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=2 c=1 T=13.7: 100000 draws, counts [27835, 34700, 37465], z -0.48 -0.22 +0.66 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=2 c=8 T=0.3: 100000 draws, counts [0, 100000, 0], z -0.00 +0.01 -0.01 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=3 c=1 T=1.3: 100000 draws, counts [835, 17462, 81703], z +0.94 -0.59 +0.36 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=3 c=3 T=7.1: 100000 draws, counts [17600, 41216, 41184], z -0.66 +0.36 +0.15 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=5 c=1 T=0.25: 100000 draws, counts [0, 0, 100000], z +0.00 -0.11 +0.11 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=5 c=3 T=1: 100000 draws, counts [9, 12006, 87985], z +2.50 +0.84 -0.89 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=9 c=0 T=2.9: 100000 draws, counts [204, 4140, 95656], z +0.83 -2.31 +2.09 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=9 c=2 T=25: 100000 draws, counts [21552, 33829, 44619], z -1.18 +0.85 +0.17 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=17 c=0 T=0.7: 100000 draws, counts [0, 0, 100000], z +0.00 -0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=17 c=2 T=1.8708286933869707: 100000 draws, counts [0, 36, 99964], z -0.04 +0.53 -0.53 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=17 c=8 T=13.7: 100000 draws, counts [5263, 32393, 62344], z +0.64 +0.21 -0.50 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=40 c=2 T=0.3: 100000 draws, counts [0, 0, 100000], z +0.00 +0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] cell h=40 c=8 T=1.3: 100000 draws, counts [0, 0, 100000], z +0.00 -0.00 +0.00 (limit 4); 100000/100000 equal to the reference's draw + [PASS] battery one-pair: chi-square 10.7 on 8 degrees of freedom (critical 28.0) + [PASS] battery a-pair-apart: chi-square 45.3 on 26 degrees of freedom (critical 62.1) + [PASS] battery a-pair-far-apart: chi-square 75.3 on 79 degrees of freedom (critical 141.8) + [PASS] battery a-triangle: chi-square 31.0 on 26 degrees of freedom (critical 62.1) + [PASS] battery wide-fields-and-cost: chi-square 18.3 on 22 degrees of freedom (critical 55.2) + [PASS] battery a-small-field-cold: chi-square 6.9 on 4 degrees of freedom (critical 18.1) + [PASS] battery ending-at-zero: chi-square 17.1 on 11 degrees of freedom (critical 34.5) + [PASS] battery cooling: chi-square 16.8 on 23 degrees of freedom (critical 56.9) + [PASS] the all-at-once control (every cell moved together) fails the battery on ["one-pair", "a-pair-apart", "a-pair-far-apart", "a-triangle", "a-small-field-cold", "ending-at-zero", "cooling"] + [PASS] jobs: 31/31 requests answer as the set says (state, energy, verdict, mode, restarts, sweeps, accumulates, draws, replay digest, or the refusal) + [PASS] 2000/2000 random workloads (2-64 cells, fields -5..5, cost 0-3) settle exactly as the reference does + [PASS] 4096/4096 fields read back equal W s + b (dense W, fields across the engine's ±524287) + [PASS] the engine still answers with its ID at the end: no other session replaced it +44 checks, 0 failed diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/latency-emio.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/latency-emio.txt new file mode 100644 index 000000000..a7a6036a3 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/latency-emio.txt @@ -0,0 +1,7 @@ +processor-to-logic latency, EMIO link: one board, the engine at its measured clock + timer: CNTVCT_EL0 at 99.999 MHz, one tick 10.0 ns + the timer alone (two reads, an ISB each) median 10 ns p10 10 p90 20 p99 20 max 12120 mean 12 (n 20000) + EMIO register read (handshake over GPIO) median 930 ns p10 920 p90 930 p99 940 max 104301 mean 954 (n 5000) + EMIO register write (handshake over GPIO) median 790 ns p10 780 p90 800 p99 800 max 30540 mean 808 (n 5000) + EMIO, plain register accesses: a full table (64 levels x 128 fields, 32835 register writes): median 29.00 ms of 6, 883 ns a write + EMIO, plain register accesses: 4096 chains of 8 cells x 4 sweeps: 0.060 s, 14.61 us a chain, 68443 chains/s diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/ps-ports.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/ps-ports.txt new file mode 100644 index 000000000..aa89c808f --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/ps-ports.txt @@ -0,0 +1 @@ +FPD_SLCR AFI_FS 0x00000a00: M_AXI_HPM0_FPD 128 bits; AFIFM2 RDCTRL 0x000003b0 WRCTRL 0x000003b0: S_AXI_HP0_FPD reads 128 bits, writes 128 bits (the AXI build is made for 128 on the master and for reads): they match diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/throughput-emio.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/throughput-emio.txt new file mode 100644 index 000000000..b5da71218 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-checks/throughput-emio.txt @@ -0,0 +1,2 @@ +settle, dense 64 (recall cue): clock 99.998 MHz, 8.0 clocks a job, 12499778 jobs/s, 0.000e0 cell updates/s, 1.831e11 accumulates/s +sample, sequential, 64 cells, 8 sweeps at T = 0.25: clock 99.998 MHz, 2059.0 clocks a job, 48566 jobs/s, 2.487e7 cell updates/s, 1.138e9 accumulates/s diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/campaign.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/campaign.txt new file mode 100644 index 000000000..924a2294e --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/campaign.txt @@ -0,0 +1,11 @@ +2026-11-06T12:38:56Z start; engine answers: ID and version 0x00404002; measured clock 99.997 MHz +2026-11-06T12:48:56Z step done +2026-11-06T12:48:56Z known answer skipped: KNOWN_ANSWER and KNOWN_BITSTREAM not set +2026-11-06T13:12:57Z null done exit=0 +2026-11-06T13:42:58Z t0-recall done exit=0 +2026-11-06T14:13:00Z gibbs-recall done exit=0 +2026-11-06T14:37:01Z t0-idle done exit=0 +PL0_REF_CTRL was 0x1010f00; nominal 50.00 MHz; measured 49.9989 MHz +2026-11-06T14:55:03Z 50 MHz done exit=0 +PL0_REF_CTRL was 0x1011e00; nominal 100.00 MHz; measured 99.9981 MHz +2026-11-06T14:55:04Z end diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/gibbs-recall.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/gibbs-recall.dat new file mode 100644 index 000000000..3f84f135f --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/gibbs-recall.dat @@ -0,0 +1,629 @@ +# class gibbs-recall cores 1 +# wai-quantum-fpga meter passes=10 settle=60s samples=30 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793972579, tv_nsec: 29912947 } +# pass state sample power_uW +1 run 1 3150000 +1 run 2 3150000 +1 run 3 3140000 +1 run 4 3150000 +1 run 5 3150000 +1 run 6 3150000 +1 run 7 3150000 +1 run 8 3150000 +1 run 9 3160000 +1 run 10 3150000 +1 run 11 3150000 +1 run 12 3160000 +1 run 13 3150000 +1 run 14 3150000 +1 run 15 3150000 +1 run 16 3150000 +1 run 17 3160000 +1 run 18 3170000 +1 run 19 3150000 +1 run 20 3160000 +1 run 21 3150000 +1 run 22 3150000 +1 run 23 3150000 +1 run 24 3150000 +1 run 25 3140000 +1 run 26 3150000 +1 run 27 3150000 +1 run 28 3150000 +1 run 29 3150000 +1 run 30 3150000 +# point pass=1 state=run jobs_per_s=48542.7 updates_per_s=24853863.3 clock_hz=99997947 +1 halt 1 3140000 +1 halt 2 3140000 +1 halt 3 3130000 +1 halt 4 3130000 +1 halt 5 3140000 +1 halt 6 3160000 +1 halt 7 3130000 +1 halt 8 3120000 +1 halt 9 3120000 +1 halt 10 3130000 +1 halt 11 3140000 +1 halt 12 3140000 +1 halt 13 3140000 +1 halt 14 3140000 +1 halt 15 3150000 +1 halt 16 3140000 +1 halt 17 3130000 +1 halt 18 3140000 +1 halt 19 3130000 +1 halt 20 3130000 +1 halt 21 3140000 +1 halt 22 3140000 +1 halt 23 3150000 +1 halt 24 3130000 +1 halt 25 3140000 +1 halt 26 3140000 +1 halt 27 3120000 +1 halt 28 3140000 +1 halt 29 3130000 +1 halt 30 3130000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997947 +2 run 1 3130000 +2 run 2 3140000 +2 run 3 3160000 +2 run 4 3140000 +2 run 5 3140000 +2 run 6 3140000 +2 run 7 3140000 +2 run 8 3140000 +2 run 9 3140000 +2 run 10 3140000 +2 run 11 3150000 +2 run 12 3150000 +2 run 13 3140000 +2 run 14 3160000 +2 run 15 3140000 +2 run 16 3140000 +2 run 17 3140000 +2 run 18 3190000 +2 run 19 3150000 +2 run 20 3140000 +2 run 21 3140000 +2 run 22 3150000 +2 run 23 3140000 +2 run 24 3140000 +2 run 25 3140000 +2 run 26 3160000 +2 run 27 3140000 +2 run 28 3140000 +2 run 29 3140000 +2 run 30 3140000 +# point pass=2 state=run jobs_per_s=48542.7 updates_per_s=24853863.2 clock_hz=99997947 +2 halt 1 3120000 +2 halt 2 3120000 +2 halt 3 3130000 +2 halt 4 3130000 +2 halt 5 3130000 +2 halt 6 3140000 +2 halt 7 3130000 +2 halt 8 3140000 +2 halt 9 3130000 +2 halt 10 3130000 +2 halt 11 3140000 +2 halt 12 3130000 +2 halt 13 3130000 +2 halt 14 3120000 +2 halt 15 3140000 +2 halt 16 3140000 +2 halt 17 3130000 +2 halt 18 3140000 +2 halt 19 3140000 +2 halt 20 3140000 +2 halt 21 3130000 +2 halt 22 3130000 +2 halt 23 3140000 +2 halt 24 3140000 +2 halt 25 3120000 +2 halt 26 3140000 +2 halt 27 3130000 +2 halt 28 3120000 +2 halt 29 3120000 +2 halt 30 3130000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997947 +3 run 1 3140000 +3 run 2 3130000 +3 run 3 3140000 +3 run 4 3140000 +3 run 5 3150000 +3 run 6 3140000 +3 run 7 3140000 +3 run 8 3140000 +3 run 9 3140000 +3 run 10 3140000 +3 run 11 3140000 +3 run 12 3150000 +3 run 13 3140000 +3 run 14 3140000 +3 run 15 3140000 +3 run 16 3140000 +3 run 17 3140000 +3 run 18 3140000 +3 run 19 3150000 +3 run 20 3160000 +3 run 21 3140000 +3 run 22 3140000 +3 run 23 3130000 +3 run 24 3140000 +3 run 25 3130000 +3 run 26 3140000 +3 run 27 3140000 +3 run 28 3150000 +3 run 29 3140000 +3 run 30 3130000 +# point pass=3 state=run jobs_per_s=48542.7 updates_per_s=24853863.4 clock_hz=99997947 +3 halt 1 3120000 +3 halt 2 3130000 +3 halt 3 3130000 +3 halt 4 3120000 +3 halt 5 3120000 +3 halt 6 3120000 +3 halt 7 3130000 +3 halt 8 3140000 +3 halt 9 3120000 +3 halt 10 3130000 +3 halt 11 3120000 +3 halt 12 3110000 +3 halt 13 3120000 +3 halt 14 3130000 +3 halt 15 3120000 +3 halt 16 3140000 +3 halt 17 3140000 +3 halt 18 3120000 +3 halt 19 3120000 +3 halt 20 3120000 +3 halt 21 3130000 +3 halt 22 3120000 +3 halt 23 3120000 +3 halt 24 3110000 +3 halt 25 3140000 +3 halt 26 3120000 +3 halt 27 3110000 +3 halt 28 3120000 +3 halt 29 3110000 +3 halt 30 3120000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997947 +4 run 1 3140000 +4 run 2 3150000 +4 run 3 3140000 +4 run 4 3150000 +4 run 5 3150000 +4 run 6 3130000 +4 run 7 3130000 +4 run 8 3140000 +4 run 9 3140000 +4 run 10 3140000 +4 run 11 3150000 +4 run 12 3140000 +4 run 13 3160000 +4 run 14 3150000 +4 run 15 3140000 +4 run 16 3140000 +4 run 17 3140000 +4 run 18 3150000 +4 run 19 3150000 +4 run 20 3140000 +4 run 21 3150000 +4 run 22 3140000 +4 run 23 3140000 +4 run 24 3140000 +4 run 25 3140000 +4 run 26 3150000 +4 run 27 3140000 +4 run 28 3150000 +4 run 29 3150000 +4 run 30 3140000 +# point pass=4 state=run jobs_per_s=48542.7 updates_per_s=24853863.2 clock_hz=99997946 +4 halt 1 3120000 +4 halt 2 3160000 +4 halt 3 3140000 +4 halt 4 3120000 +4 halt 5 3110000 +4 halt 6 3130000 +4 halt 7 3140000 +4 halt 8 3130000 +4 halt 9 3110000 +4 halt 10 3150000 +4 halt 11 3120000 +4 halt 12 3140000 +4 halt 13 3130000 +4 halt 14 3130000 +4 halt 15 3130000 +4 halt 16 3130000 +4 halt 17 3140000 +4 halt 18 3130000 +4 halt 19 3130000 +4 halt 20 3130000 +4 halt 21 3140000 +4 halt 22 3130000 +4 halt 23 3130000 +4 halt 24 3130000 +4 halt 25 3140000 +4 halt 26 3130000 +4 halt 27 3130000 +4 halt 28 3130000 +4 halt 29 3120000 +4 halt 30 3130000 +# point pass=4 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997946 +5 run 1 3140000 +5 run 2 3140000 +5 run 3 3140000 +5 run 4 3140000 +5 run 5 3140000 +5 run 6 3140000 +5 run 7 3170000 +5 run 8 3130000 +5 run 9 3150000 +5 run 10 3150000 +5 run 11 3140000 +5 run 12 3150000 +5 run 13 3140000 +5 run 14 3140000 +5 run 15 3150000 +5 run 16 3140000 +5 run 17 3140000 +5 run 18 3140000 +5 run 19 3150000 +5 run 20 3150000 +5 run 21 3150000 +5 run 22 3160000 +5 run 23 3140000 +5 run 24 3160000 +5 run 25 3150000 +5 run 26 3140000 +5 run 27 3140000 +5 run 28 3150000 +5 run 29 3140000 +5 run 30 3160000 +# point pass=5 state=run jobs_per_s=48542.7 updates_per_s=24853863.1 clock_hz=99997946 +5 halt 1 3140000 +5 halt 2 3120000 +5 halt 3 3130000 +5 halt 4 3120000 +5 halt 5 3120000 +5 halt 6 3120000 +5 halt 7 3150000 +5 halt 8 3120000 +5 halt 9 3130000 +5 halt 10 3140000 +5 halt 11 3120000 +5 halt 12 3510000 +5 halt 13 3130000 +5 halt 14 3130000 +5 halt 15 3130000 +5 halt 16 3130000 +5 halt 17 3140000 +5 halt 18 3150000 +5 halt 19 3140000 +5 halt 20 3140000 +5 halt 21 3130000 +5 halt 22 3140000 +5 halt 23 3130000 +5 halt 24 3130000 +5 halt 25 3190000 +5 halt 26 3140000 +5 halt 27 3150000 +5 halt 28 3130000 +5 halt 29 3140000 +5 halt 30 3150000 +# point pass=5 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997946 +6 halt 1 3130000 +6 halt 2 3140000 +6 halt 3 3140000 +6 halt 4 3150000 +6 halt 5 3140000 +6 halt 6 3140000 +6 halt 7 3150000 +6 halt 8 3140000 +6 halt 9 3140000 +6 halt 10 3140000 +6 halt 11 3130000 +6 halt 12 3140000 +6 halt 13 3130000 +6 halt 14 3140000 +6 halt 15 3160000 +6 halt 16 3150000 +6 halt 17 3140000 +6 halt 18 3140000 +6 halt 19 3140000 +6 halt 20 3140000 +6 halt 21 3140000 +6 halt 22 3140000 +6 halt 23 3140000 +6 halt 24 3150000 +6 halt 25 3140000 +6 halt 26 3120000 +6 halt 27 3130000 +6 halt 28 3140000 +6 halt 29 3130000 +6 halt 30 3130000 +# point pass=6 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997946 +6 run 1 3140000 +6 run 2 3140000 +6 run 3 3150000 +6 run 4 3150000 +6 run 5 3140000 +6 run 6 3140000 +6 run 7 3150000 +6 run 8 3140000 +6 run 9 3140000 +6 run 10 3140000 +6 run 11 3140000 +6 run 12 3150000 +6 run 13 3140000 +6 run 14 3150000 +6 run 15 3140000 +6 run 16 3140000 +6 run 17 3150000 +6 run 18 3140000 +6 run 19 3140000 +6 run 20 3140000 +6 run 21 3140000 +6 run 22 3140000 +6 run 23 3150000 +6 run 24 3140000 +6 run 25 3140000 +6 run 26 3140000 +6 run 27 3150000 +6 run 28 3140000 +6 run 29 3130000 +6 run 30 3140000 +# point pass=6 state=run jobs_per_s=48542.7 updates_per_s=24853862.9 clock_hz=99997946 +7 halt 1 3150000 +7 halt 2 3120000 +7 halt 3 3130000 +7 halt 4 3130000 +7 halt 5 3140000 +7 halt 6 3130000 +7 halt 7 3130000 +7 halt 8 3140000 +7 halt 9 3150000 +7 halt 10 3130000 +7 halt 11 3130000 +7 halt 12 3140000 +7 halt 13 3120000 +7 halt 14 3130000 +7 halt 15 3130000 +7 halt 16 3130000 +7 halt 17 3130000 +7 halt 18 3140000 +7 halt 19 3130000 +7 halt 20 3120000 +7 halt 21 3140000 +7 halt 22 3120000 +7 halt 23 3130000 +7 halt 24 3140000 +7 halt 25 3140000 +7 halt 26 3130000 +7 halt 27 3130000 +7 halt 28 3140000 +7 halt 29 3130000 +7 halt 30 3120000 +# point pass=7 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997946 +7 run 1 3150000 +7 run 2 3150000 +7 run 3 3150000 +7 run 4 3140000 +7 run 5 3150000 +7 run 6 3140000 +7 run 7 3140000 +7 run 8 3140000 +7 run 9 3150000 +7 run 10 3150000 +7 run 11 3150000 +7 run 12 3160000 +7 run 13 3160000 +7 run 14 3150000 +7 run 15 3150000 +7 run 16 3150000 +7 run 17 3150000 +7 run 18 3150000 +7 run 19 3150000 +7 run 20 3160000 +7 run 21 3160000 +7 run 22 3150000 +7 run 23 3140000 +7 run 24 3150000 +7 run 25 3150000 +7 run 26 3140000 +7 run 27 3150000 +7 run 28 3150000 +7 run 29 3160000 +7 run 30 3140000 +# point pass=7 state=run jobs_per_s=48542.7 updates_per_s=24853862.9 clock_hz=99997946 +8 run 1 3140000 +8 run 2 3140000 +8 run 3 3140000 +8 run 4 3140000 +8 run 5 3140000 +8 run 6 3140000 +8 run 7 3150000 +8 run 8 3140000 +8 run 9 3130000 +8 run 10 3160000 +8 run 11 3140000 +8 run 12 3140000 +8 run 13 3140000 +8 run 14 3140000 +8 run 15 3140000 +8 run 16 3140000 +8 run 17 3140000 +8 run 18 3140000 +8 run 19 3140000 +8 run 20 3160000 +8 run 21 3150000 +8 run 22 3140000 +8 run 23 3140000 +8 run 24 3150000 +8 run 25 3140000 +8 run 26 3140000 +8 run 27 3150000 +8 run 28 3140000 +8 run 29 3140000 +8 run 30 3140000 +# point pass=8 state=run jobs_per_s=48542.7 updates_per_s=24853862.9 clock_hz=99997946 +8 halt 1 3130000 +8 halt 2 3140000 +8 halt 3 3140000 +8 halt 4 3140000 +8 halt 5 3130000 +8 halt 6 3130000 +8 halt 7 3130000 +8 halt 8 3140000 +8 halt 9 3150000 +8 halt 10 3130000 +8 halt 11 3120000 +8 halt 12 3130000 +8 halt 13 3130000 +8 halt 14 3130000 +8 halt 15 3140000 +8 halt 16 3140000 +8 halt 17 3140000 +8 halt 18 3150000 +8 halt 19 3140000 +8 halt 20 3120000 +8 halt 21 3120000 +8 halt 22 3130000 +8 halt 23 3130000 +8 halt 24 3140000 +8 halt 25 3120000 +8 halt 26 3130000 +8 halt 27 3120000 +8 halt 28 3130000 +8 halt 29 3140000 +8 halt 30 3140000 +# point pass=8 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997946 +9 run 1 3150000 +9 run 2 3150000 +9 run 3 3150000 +9 run 4 3150000 +9 run 5 3150000 +9 run 6 3160000 +9 run 7 3150000 +9 run 8 3150000 +9 run 9 3150000 +9 run 10 3150000 +9 run 11 3150000 +9 run 12 3150000 +9 run 13 3150000 +9 run 14 3160000 +9 run 15 3140000 +9 run 16 3150000 +9 run 17 3150000 +9 run 18 3140000 +9 run 19 3150000 +9 run 20 3150000 +9 run 21 3150000 +9 run 22 3150000 +9 run 23 3150000 +9 run 24 3140000 +9 run 25 3150000 +9 run 26 3150000 +9 run 27 3150000 +9 run 28 3150000 +9 run 29 3160000 +9 run 30 3150000 +# point pass=9 state=run jobs_per_s=48542.7 updates_per_s=24853862.8 clock_hz=99997945 +9 halt 1 3140000 +9 halt 2 3150000 +9 halt 3 3150000 +9 halt 4 3140000 +9 halt 5 3140000 +9 halt 6 3140000 +9 halt 7 3150000 +9 halt 8 3140000 +9 halt 9 3150000 +9 halt 10 3140000 +9 halt 11 3160000 +9 halt 12 3130000 +9 halt 13 3140000 +9 halt 14 3140000 +9 halt 15 3130000 +9 halt 16 3140000 +9 halt 17 3140000 +9 halt 18 3140000 +9 halt 19 3140000 +9 halt 20 3140000 +9 halt 21 3140000 +9 halt 22 3140000 +9 halt 23 3140000 +9 halt 24 3140000 +9 halt 25 3140000 +9 halt 26 3150000 +9 halt 27 3140000 +9 halt 28 3150000 +9 halt 29 3140000 +9 halt 30 3150000 +# point pass=9 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997946 +10 halt 1 3140000 +10 halt 2 3140000 +10 halt 3 3140000 +10 halt 4 3140000 +10 halt 5 3140000 +10 halt 6 3130000 +10 halt 7 3140000 +10 halt 8 3140000 +10 halt 9 3140000 +10 halt 10 3140000 +10 halt 11 3140000 +10 halt 12 3140000 +10 halt 13 3140000 +10 halt 14 3150000 +10 halt 15 3140000 +10 halt 16 3140000 +10 halt 17 3130000 +10 halt 18 3140000 +10 halt 19 3140000 +10 halt 20 3140000 +10 halt 21 3140000 +10 halt 22 3140000 +10 halt 23 3150000 +10 halt 24 3130000 +10 halt 25 3140000 +10 halt 26 3130000 +10 halt 27 3140000 +10 halt 28 3140000 +10 halt 29 3130000 +10 halt 30 3140000 +# point pass=10 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997947 +10 run 1 3150000 +10 run 2 3150000 +10 run 3 3150000 +10 run 4 3150000 +10 run 5 3150000 +10 run 6 3160000 +10 run 7 3140000 +10 run 8 3150000 +10 run 9 3150000 +10 run 10 3150000 +10 run 11 3160000 +10 run 12 3150000 +10 run 13 3150000 +10 run 14 3150000 +10 run 15 3180000 +10 run 16 3150000 +10 run 17 3140000 +10 run 18 3140000 +10 run 19 3170000 +10 run 20 3160000 +10 run 21 3150000 +10 run 22 3150000 +10 run 23 3150000 +10 run 24 3160000 +10 run 25 3150000 +10 run 26 3140000 +10 run 27 3150000 +10 run 28 3160000 +10 run 29 3150000 +10 run 30 3150000 +# point pass=10 state=run jobs_per_s=48542.7 updates_per_s=24853862.9 clock_hz=99997945 +# done SystemTime { tv_sec: 1793974380, tv_nsec: 187856982 } +# passes used 10 of 10 (dropped: []) +# run - halt = 11.0 +/- 1.8 mW (per-pass sd 5.7); 9/10 passes positive; 2 sample excursions beyond 6 MAD +# per-pass differences (mW): 10.0 10.0 20.0 10.0 10.0 0.0 20.0 10.0 10.0 10.0 +# board power while running 3144 mW; jobs/s 48542.7; updates/s 24853863.1; measured PL clock 99.998 MHz +# pre-registered prediction 12.0 mW: measured/predicted = 0.92, -0.6 sigma from it diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/null.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/null.dat new file mode 100644 index 000000000..3d3ea0f4a --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/null.dat @@ -0,0 +1,505 @@ +# class t0-recall cores 1 +# wai-quantum-fpga meter passes=8 settle=60s samples=30 null=true sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793969336, tv_nsec: 827384277 } +# pass state sample power_uW +1 halt 1 3130000 +1 halt 2 3120000 +1 halt 3 3130000 +1 halt 4 3140000 +1 halt 5 3530000 +1 halt 6 3150000 +1 halt 7 3130000 +1 halt 8 3130000 +1 halt 9 3130000 +1 halt 10 3130000 +1 halt 11 3140000 +1 halt 12 3140000 +1 halt 13 3130000 +1 halt 14 3150000 +1 halt 15 3710000 +1 halt 16 3130000 +1 halt 17 3130000 +1 halt 18 3130000 +1 halt 19 3130000 +1 halt 20 3120000 +1 halt 21 3140000 +1 halt 22 3150000 +1 halt 23 3120000 +1 halt 24 3130000 +1 halt 25 3130000 +1 halt 26 3120000 +1 halt 27 3130000 +1 halt 28 3120000 +1 halt 29 3140000 +1 halt 30 3120000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998017 +1 run 1 3130000 +1 run 2 3140000 +1 run 3 3140000 +1 run 4 3120000 +1 run 5 3140000 +1 run 6 3140000 +1 run 7 3120000 +1 run 8 3120000 +1 run 9 3120000 +1 run 10 3120000 +1 run 11 3150000 +1 run 12 3120000 +1 run 13 3130000 +1 run 14 3120000 +1 run 15 3130000 +1 run 16 3140000 +1 run 17 3120000 +1 run 18 3130000 +1 run 19 3130000 +1 run 20 3130000 +1 run 21 3130000 +1 run 22 3140000 +1 run 23 3120000 +1 run 24 3130000 +1 run 25 3120000 +1 run 26 3140000 +1 run 27 3120000 +1 run 28 3130000 +1 run 29 3130000 +1 run 30 3130000 +# point pass=1 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998017 +2 run 1 3150000 +2 run 2 3140000 +2 run 3 3140000 +2 run 4 3130000 +2 run 5 3140000 +2 run 6 3140000 +2 run 7 3140000 +2 run 8 3120000 +2 run 9 3150000 +2 run 10 3140000 +2 run 11 3130000 +2 run 12 3120000 +2 run 13 3130000 +2 run 14 3130000 +2 run 15 3140000 +2 run 16 3140000 +2 run 17 3120000 +2 run 18 3140000 +2 run 19 3140000 +2 run 20 3130000 +2 run 21 3140000 +2 run 22 3140000 +2 run 23 3140000 +2 run 24 3150000 +2 run 25 3140000 +2 run 26 3140000 +2 run 27 3140000 +2 run 28 3130000 +2 run 29 3120000 +2 run 30 3140000 +# point pass=2 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998017 +2 halt 1 3140000 +2 halt 2 3140000 +2 halt 3 3140000 +2 halt 4 3130000 +2 halt 5 3130000 +2 halt 6 3150000 +2 halt 7 3120000 +2 halt 8 3130000 +2 halt 9 3120000 +2 halt 10 3130000 +2 halt 11 3140000 +2 halt 12 3130000 +2 halt 13 3140000 +2 halt 14 3140000 +2 halt 15 3130000 +2 halt 16 3120000 +2 halt 17 3120000 +2 halt 18 3130000 +2 halt 19 3120000 +2 halt 20 3140000 +2 halt 21 3150000 +2 halt 22 3140000 +2 halt 23 3130000 +2 halt 24 3130000 +2 halt 25 3140000 +2 halt 26 3130000 +2 halt 27 3120000 +2 halt 28 3130000 +2 halt 29 3450000 +2 halt 30 3120000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998017 +3 run 1 3130000 +3 run 2 3130000 +3 run 3 3130000 +3 run 4 3120000 +3 run 5 3130000 +3 run 6 3120000 +3 run 7 3130000 +3 run 8 3130000 +3 run 9 3120000 +3 run 10 3140000 +3 run 11 3150000 +3 run 12 3120000 +3 run 13 3140000 +3 run 14 3130000 +3 run 15 3120000 +3 run 16 3130000 +3 run 17 3140000 +3 run 18 3110000 +3 run 19 3140000 +3 run 20 3130000 +3 run 21 3120000 +3 run 22 3140000 +3 run 23 3140000 +3 run 24 3130000 +3 run 25 3130000 +3 run 26 3130000 +3 run 27 3150000 +3 run 28 3120000 +3 run 29 3130000 +3 run 30 3120000 +# point pass=3 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998016 +3 halt 1 3120000 +3 halt 2 3120000 +3 halt 3 3120000 +3 halt 4 3120000 +3 halt 5 3110000 +3 halt 6 3110000 +3 halt 7 3140000 +3 halt 8 3120000 +3 halt 9 3110000 +3 halt 10 3130000 +3 halt 11 3110000 +3 halt 12 3120000 +3 halt 13 3120000 +3 halt 14 3120000 +3 halt 15 3140000 +3 halt 16 3140000 +3 halt 17 3110000 +3 halt 18 3130000 +3 halt 19 3120000 +3 halt 20 3120000 +3 halt 21 3120000 +3 halt 22 3120000 +3 halt 23 3120000 +3 halt 24 3140000 +3 halt 25 3110000 +3 halt 26 3120000 +3 halt 27 3120000 +3 halt 28 3120000 +3 halt 29 3110000 +3 halt 30 3110000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998016 +4 halt 1 3120000 +4 halt 2 3130000 +4 halt 3 3130000 +4 halt 4 3140000 +4 halt 5 3130000 +4 halt 6 3130000 +4 halt 7 3110000 +4 halt 8 3130000 +4 halt 9 3120000 +4 halt 10 3120000 +4 halt 11 3140000 +4 halt 12 3140000 +4 halt 13 3140000 +4 halt 14 3130000 +4 halt 15 3120000 +4 halt 16 3120000 +4 halt 17 3120000 +4 halt 18 3130000 +4 halt 19 3120000 +4 halt 20 3120000 +4 halt 21 3120000 +4 halt 22 3120000 +4 halt 23 3130000 +4 halt 24 3130000 +4 halt 25 3120000 +4 halt 26 3120000 +4 halt 27 3110000 +4 halt 28 3120000 +4 halt 29 3120000 +4 halt 30 3120000 +# point pass=4 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998016 +4 run 1 3150000 +4 run 2 3130000 +4 run 3 3130000 +4 run 4 3130000 +4 run 5 3140000 +4 run 6 3130000 +4 run 7 3130000 +4 run 8 3140000 +4 run 9 3150000 +4 run 10 3140000 +4 run 11 3140000 +4 run 12 3130000 +4 run 13 3140000 +4 run 14 3140000 +4 run 15 3140000 +4 run 16 3140000 +4 run 17 3130000 +4 run 18 3130000 +4 run 19 3130000 +4 run 20 3140000 +4 run 21 3150000 +4 run 22 3130000 +4 run 23 3130000 +4 run 24 3150000 +4 run 25 3140000 +4 run 26 3130000 +4 run 27 3140000 +4 run 28 3130000 +4 run 29 3130000 +4 run 30 3130000 +# point pass=4 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998016 +5 run 1 3140000 +5 run 2 3140000 +5 run 3 3140000 +5 run 4 3140000 +5 run 5 3140000 +5 run 6 3150000 +5 run 7 3140000 +5 run 8 3140000 +5 run 9 3140000 +5 run 10 3140000 +5 run 11 3140000 +5 run 12 3130000 +5 run 13 3140000 +5 run 14 3140000 +5 run 15 3130000 +5 run 16 3140000 +5 run 17 3130000 +5 run 18 3130000 +5 run 19 3140000 +5 run 20 3140000 +5 run 21 3150000 +5 run 22 3140000 +5 run 23 3140000 +5 run 24 3140000 +5 run 25 3130000 +5 run 26 3130000 +5 run 27 3150000 +5 run 28 3130000 +5 run 29 3150000 +5 run 30 3140000 +# point pass=5 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998015 +5 halt 1 3120000 +5 halt 2 3130000 +5 halt 3 3140000 +5 halt 4 3140000 +5 halt 5 3130000 +5 halt 6 3130000 +5 halt 7 3120000 +5 halt 8 3130000 +5 halt 9 3130000 +5 halt 10 3120000 +5 halt 11 3130000 +5 halt 12 3140000 +5 halt 13 3140000 +5 halt 14 3140000 +5 halt 15 3120000 +5 halt 16 3130000 +5 halt 17 3140000 +5 halt 18 3140000 +5 halt 19 3130000 +5 halt 20 3130000 +5 halt 21 3120000 +5 halt 22 3140000 +5 halt 23 3120000 +5 halt 24 3120000 +5 halt 25 3130000 +5 halt 26 3140000 +5 halt 27 3120000 +5 halt 28 3120000 +5 halt 29 3120000 +5 halt 30 3130000 +# point pass=5 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998015 +6 halt 1 3130000 +6 halt 2 3140000 +6 halt 3 3120000 +6 halt 4 3120000 +6 halt 5 3130000 +6 halt 6 3140000 +6 halt 7 3140000 +6 halt 8 3130000 +6 halt 9 3120000 +6 halt 10 3140000 +6 halt 11 3120000 +6 halt 12 3130000 +6 halt 13 3120000 +6 halt 14 3120000 +6 halt 15 3120000 +6 halt 16 3130000 +6 halt 17 3120000 +6 halt 18 3120000 +6 halt 19 3140000 +6 halt 20 3140000 +6 halt 21 3150000 +6 halt 22 3130000 +6 halt 23 3140000 +6 halt 24 3130000 +6 halt 25 3140000 +6 halt 26 3120000 +6 halt 27 3140000 +6 halt 28 3140000 +6 halt 29 3120000 +6 halt 30 3130000 +# point pass=6 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998016 +6 run 1 3110000 +6 run 2 3120000 +6 run 3 3130000 +6 run 4 3140000 +6 run 5 3150000 +6 run 6 3140000 +6 run 7 3140000 +6 run 8 3140000 +6 run 9 3140000 +6 run 10 3130000 +6 run 11 3130000 +6 run 12 3140000 +6 run 13 3180000 +6 run 14 3140000 +6 run 15 3140000 +6 run 16 3140000 +6 run 17 3140000 +6 run 18 3550000 +6 run 19 3130000 +6 run 20 3130000 +6 run 21 3140000 +6 run 22 3140000 +6 run 23 3140000 +6 run 24 3140000 +6 run 25 3140000 +6 run 26 3140000 +6 run 27 3150000 +6 run 28 3150000 +6 run 29 3140000 +6 run 30 3130000 +# point pass=6 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998017 +7 run 1 3140000 +7 run 2 3140000 +7 run 3 3140000 +7 run 4 3140000 +7 run 5 3130000 +7 run 6 3140000 +7 run 7 3130000 +7 run 8 3140000 +7 run 9 3140000 +7 run 10 3130000 +7 run 11 3140000 +7 run 12 3140000 +7 run 13 3140000 +7 run 14 3140000 +7 run 15 3150000 +7 run 16 3150000 +7 run 17 3140000 +7 run 18 3140000 +7 run 19 3130000 +7 run 20 3140000 +7 run 21 3140000 +7 run 22 3140000 +7 run 23 3160000 +7 run 24 3150000 +7 run 25 3130000 +7 run 26 3140000 +7 run 27 3140000 +7 run 28 3140000 +7 run 29 3140000 +7 run 30 3140000 +# point pass=7 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998016 +7 halt 1 3130000 +7 halt 2 3140000 +7 halt 3 3140000 +7 halt 4 3140000 +7 halt 5 3140000 +7 halt 6 3140000 +7 halt 7 3140000 +7 halt 8 3140000 +7 halt 9 3140000 +7 halt 10 3130000 +7 halt 11 3140000 +7 halt 12 3150000 +7 halt 13 3130000 +7 halt 14 3140000 +7 halt 15 3140000 +7 halt 16 3140000 +7 halt 17 3140000 +7 halt 18 3130000 +7 halt 19 3140000 +7 halt 20 3160000 +7 halt 21 3140000 +7 halt 22 3140000 +7 halt 23 3140000 +7 halt 24 3140000 +7 halt 25 3140000 +7 halt 26 3130000 +7 halt 27 3140000 +7 halt 28 3140000 +7 halt 29 3130000 +7 halt 30 3140000 +# point pass=7 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997626 +8 run 1 3140000 +8 run 2 3140000 +8 run 3 3140000 +8 run 4 3140000 +8 run 5 3140000 +8 run 6 3140000 +8 run 7 3130000 +8 run 8 3150000 +8 run 9 3150000 +8 run 10 3120000 +8 run 11 3140000 +8 run 12 3140000 +8 run 13 3140000 +8 run 14 3130000 +8 run 15 3140000 +8 run 16 3140000 +8 run 17 3150000 +8 run 18 3130000 +8 run 19 3140000 +8 run 20 3130000 +8 run 21 3140000 +8 run 22 3140000 +8 run 23 3130000 +8 run 24 3140000 +8 run 25 3140000 +8 run 26 3140000 +8 run 27 3140000 +8 run 28 3130000 +8 run 29 3140000 +8 run 30 3140000 +# point pass=8 state=run jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997571 +8 halt 1 3120000 +8 halt 2 3130000 +8 halt 3 3140000 +8 halt 4 3130000 +8 halt 5 3140000 +8 halt 6 3140000 +8 halt 7 3130000 +8 halt 8 3130000 +8 halt 9 3120000 +8 halt 10 3140000 +8 halt 11 3130000 +8 halt 12 3120000 +8 halt 13 3140000 +8 halt 14 3150000 +8 halt 15 3140000 +8 halt 16 3130000 +8 halt 17 3130000 +8 halt 18 3130000 +8 halt 19 3130000 +8 halt 20 3120000 +8 halt 21 3120000 +8 halt 22 3120000 +8 halt 23 3140000 +8 halt 24 3130000 +8 halt 25 3130000 +8 halt 26 3120000 +8 halt 27 3140000 +8 halt 28 3140000 +8 halt 29 3140000 +8 halt 30 3140000 +# point pass=8 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997630 +# done SystemTime { tv_sec: 1793970777, tv_nsec: 754326175 } +# passes used 8 of 8 (dropped: []) +# run - halt = 8.1 +/- 1.9 mW (per-pass sd 5.3); 6/8 passes positive; 5 sample excursions beyond 6 MAD +# per-pass differences (mW): 0.0 10.0 10.0 15.0 10.0 10.0 0.0 10.0 +# board power while running 3137 mW; jobs/s 0.0; updates/s 0.0; measured PL clock 99.998 MHz +# pre-registered prediction 0.0 mW: measured/predicted = inf, 4.3 sigma from it diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/step.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/step.dat new file mode 100644 index 000000000..72f5094c1 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/step.dat @@ -0,0 +1,610 @@ +# class t0-recall cores 1 +# wai-quantum-fpga meter passes=1 settle=0s samples=300 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793968736, tv_nsec: 357321553 } +# pass state sample power_uW +1 run 1 3530000 +1 run 2 3300000 +1 run 3 3290000 +1 run 4 3300000 +1 run 5 3310000 +1 run 6 3300000 +1 run 7 3300000 +1 run 8 3300000 +1 run 9 3300000 +1 run 10 3320000 +1 run 11 3300000 +1 run 12 3300000 +1 run 13 3300000 +1 run 14 3310000 +1 run 15 3290000 +1 run 16 3300000 +1 run 17 3320000 +1 run 18 3290000 +1 run 19 3300000 +1 run 20 3320000 +1 run 21 3300000 +1 run 22 3300000 +1 run 23 3300000 +1 run 24 3300000 +1 run 25 3300000 +1 run 26 3310000 +1 run 27 3320000 +1 run 28 3300000 +1 run 29 3300000 +1 run 30 3290000 +1 run 31 3290000 +1 run 32 3310000 +1 run 33 3300000 +1 run 34 3320000 +1 run 35 3300000 +1 run 36 3310000 +1 run 37 3300000 +1 run 38 3320000 +1 run 39 3320000 +1 run 40 3300000 +1 run 41 3300000 +1 run 42 3310000 +1 run 43 3300000 +1 run 44 3300000 +1 run 45 3300000 +1 run 46 3300000 +1 run 47 3320000 +1 run 48 3300000 +1 run 49 3300000 +1 run 50 3300000 +1 run 51 3300000 +1 run 52 3300000 +1 run 53 3300000 +1 run 54 3300000 +1 run 55 3310000 +1 run 56 3300000 +1 run 57 3300000 +1 run 58 3300000 +1 run 59 3310000 +1 run 60 3300000 +1 run 61 3290000 +1 run 62 3360000 +1 run 63 3300000 +1 run 64 3300000 +1 run 65 3290000 +1 run 66 3300000 +1 run 67 3300000 +1 run 68 3290000 +1 run 69 3300000 +1 run 70 3320000 +1 run 71 3330000 +1 run 72 3300000 +1 run 73 3320000 +1 run 74 3310000 +1 run 75 3310000 +1 run 76 3340000 +1 run 77 3300000 +1 run 78 3310000 +1 run 79 3320000 +1 run 80 3300000 +1 run 81 3300000 +1 run 82 3300000 +1 run 83 3310000 +1 run 84 3300000 +1 run 85 3290000 +1 run 86 3290000 +1 run 87 3300000 +1 run 88 3300000 +1 run 89 3300000 +1 run 90 3290000 +1 run 91 3300000 +1 run 92 3320000 +1 run 93 3300000 +1 run 94 3320000 +1 run 95 3300000 +1 run 96 3300000 +1 run 97 3300000 +1 run 98 3300000 +1 run 99 3300000 +1 run 100 3310000 +1 run 101 3300000 +1 run 102 3600000 +1 run 103 3300000 +1 run 104 3300000 +1 run 105 3310000 +1 run 106 3310000 +1 run 107 3300000 +1 run 108 3310000 +1 run 109 3300000 +1 run 110 3290000 +1 run 111 3300000 +1 run 112 3300000 +1 run 113 3310000 +1 run 114 3310000 +1 run 115 3300000 +1 run 116 3300000 +1 run 117 3320000 +1 run 118 3300000 +1 run 119 3300000 +1 run 120 3300000 +1 run 121 3330000 +1 run 122 3290000 +1 run 123 3290000 +1 run 124 3290000 +1 run 125 3320000 +1 run 126 3310000 +1 run 127 3280000 +1 run 128 3300000 +1 run 129 3300000 +1 run 130 3300000 +1 run 131 3290000 +1 run 132 3290000 +1 run 133 3290000 +1 run 134 3300000 +1 run 135 3290000 +1 run 136 3300000 +1 run 137 3290000 +1 run 138 3300000 +1 run 139 3300000 +1 run 140 3290000 +1 run 141 3290000 +1 run 142 3290000 +1 run 143 3290000 +1 run 144 3300000 +1 run 145 3290000 +1 run 146 3290000 +1 run 147 3300000 +1 run 148 3290000 +1 run 149 3320000 +1 run 150 3300000 +1 run 151 3290000 +1 run 152 3300000 +1 run 153 3290000 +1 run 154 3290000 +1 run 155 3310000 +1 run 156 3300000 +1 run 157 3320000 +1 run 158 3300000 +1 run 159 3310000 +1 run 160 3330000 +1 run 161 3290000 +1 run 162 3290000 +1 run 163 3310000 +1 run 164 3300000 +1 run 165 3290000 +1 run 166 3300000 +1 run 167 3300000 +1 run 168 3300000 +1 run 169 3290000 +1 run 170 3300000 +1 run 171 3290000 +1 run 172 3290000 +1 run 173 3290000 +1 run 174 3310000 +1 run 175 3300000 +1 run 176 3290000 +1 run 177 3290000 +1 run 178 3290000 +1 run 179 3300000 +1 run 180 3300000 +1 run 181 3320000 +1 run 182 3300000 +1 run 183 3300000 +1 run 184 3310000 +1 run 185 3300000 +1 run 186 3310000 +1 run 187 3300000 +1 run 188 3320000 +1 run 189 3320000 +1 run 190 3300000 +1 run 191 3310000 +1 run 192 3300000 +1 run 193 3300000 +1 run 194 3300000 +1 run 195 3300000 +1 run 196 3300000 +1 run 197 3300000 +1 run 198 3310000 +1 run 199 3310000 +1 run 200 3290000 +1 run 201 3300000 +1 run 202 3320000 +1 run 203 3300000 +1 run 204 3320000 +1 run 205 3310000 +1 run 206 3310000 +1 run 207 3300000 +1 run 208 3310000 +1 run 209 3300000 +1 run 210 3310000 +1 run 211 3300000 +1 run 212 3320000 +1 run 213 3330000 +1 run 214 3310000 +1 run 215 3310000 +1 run 216 3310000 +1 run 217 3300000 +1 run 218 3310000 +1 run 219 3300000 +1 run 220 3290000 +1 run 221 3320000 +1 run 222 3300000 +1 run 223 3300000 +1 run 224 3290000 +1 run 225 3300000 +1 run 226 3300000 +1 run 227 3300000 +1 run 228 3300000 +1 run 229 3310000 +1 run 230 3310000 +1 run 231 3300000 +1 run 232 3300000 +1 run 233 3300000 +1 run 234 3300000 +1 run 235 3300000 +1 run 236 3320000 +1 run 237 3290000 +1 run 238 3300000 +1 run 239 3310000 +1 run 240 3300000 +1 run 241 3310000 +1 run 242 3320000 +1 run 243 3300000 +1 run 244 3320000 +1 run 245 3310000 +1 run 246 3300000 +1 run 247 3300000 +1 run 248 3300000 +1 run 249 3310000 +1 run 250 3300000 +1 run 251 3310000 +1 run 252 3300000 +1 run 253 3320000 +1 run 254 3310000 +1 run 255 3290000 +1 run 256 3300000 +1 run 257 3310000 +1 run 258 3300000 +1 run 259 3310000 +1 run 260 3310000 +1 run 261 3310000 +1 run 262 3300000 +1 run 263 3300000 +1 run 264 3300000 +1 run 265 3300000 +1 run 266 3300000 +1 run 267 3320000 +1 run 268 3320000 +1 run 269 3300000 +1 run 270 3300000 +1 run 271 3310000 +1 run 272 3300000 +1 run 273 3300000 +1 run 274 3300000 +1 run 275 3300000 +1 run 276 3330000 +1 run 277 3310000 +1 run 278 3310000 +1 run 279 3300000 +1 run 280 3300000 +1 run 281 3300000 +1 run 282 3300000 +1 run 283 3310000 +1 run 284 3310000 +1 run 285 3310000 +1 run 286 3310000 +1 run 287 3290000 +1 run 288 3310000 +1 run 289 3310000 +1 run 290 3300000 +1 run 291 3320000 +1 run 292 3300000 +1 run 293 3300000 +1 run 294 3320000 +1 run 295 3310000 +1 run 296 3300000 +1 run 297 3300000 +1 run 298 3300000 +1 run 299 3660000 +1 run 300 3330000 +# point pass=1 state=run jobs_per_s=12499751.7 updates_per_s=0.0 clock_hz=99998011 +1 halt 1 3370000 +1 halt 2 3140000 +1 halt 3 3140000 +1 halt 4 3140000 +1 halt 5 3130000 +1 halt 6 3130000 +1 halt 7 3140000 +1 halt 8 3150000 +1 halt 9 3160000 +1 halt 10 3140000 +1 halt 11 3140000 +1 halt 12 3140000 +1 halt 13 3140000 +1 halt 14 3550000 +1 halt 15 3130000 +1 halt 16 3140000 +1 halt 17 3140000 +1 halt 18 3140000 +1 halt 19 3130000 +1 halt 20 3140000 +1 halt 21 3140000 +1 halt 22 3160000 +1 halt 23 3150000 +1 halt 24 3140000 +1 halt 25 3140000 +1 halt 26 3150000 +1 halt 27 3140000 +1 halt 28 3140000 +1 halt 29 3140000 +1 halt 30 3140000 +1 halt 31 3140000 +1 halt 32 3140000 +1 halt 33 3150000 +1 halt 34 3140000 +1 halt 35 3150000 +1 halt 36 3150000 +1 halt 37 3140000 +1 halt 38 3140000 +1 halt 39 3140000 +1 halt 40 3140000 +1 halt 41 3150000 +1 halt 42 3140000 +1 halt 43 3140000 +1 halt 44 3150000 +1 halt 45 3150000 +1 halt 46 3160000 +1 halt 47 3130000 +1 halt 48 3140000 +1 halt 49 3140000 +1 halt 50 3140000 +1 halt 51 3140000 +1 halt 52 3140000 +1 halt 53 3140000 +1 halt 54 3150000 +1 halt 55 3130000 +1 halt 56 3130000 +1 halt 57 3140000 +1 halt 58 3130000 +1 halt 59 3140000 +1 halt 60 3140000 +1 halt 61 3140000 +1 halt 62 3140000 +1 halt 63 3140000 +1 halt 64 3140000 +1 halt 65 3140000 +1 halt 66 3140000 +1 halt 67 3140000 +1 halt 68 3140000 +1 halt 69 3150000 +1 halt 70 3140000 +1 halt 71 3140000 +1 halt 72 3150000 +1 halt 73 3140000 +1 halt 74 3140000 +1 halt 75 3140000 +1 halt 76 3140000 +1 halt 77 3150000 +1 halt 78 3150000 +1 halt 79 3140000 +1 halt 80 3140000 +1 halt 81 3140000 +1 halt 82 3130000 +1 halt 83 3130000 +1 halt 84 3140000 +1 halt 85 3140000 +1 halt 86 3150000 +1 halt 87 3140000 +1 halt 88 3150000 +1 halt 89 3150000 +1 halt 90 3140000 +1 halt 91 3130000 +1 halt 92 3140000 +1 halt 93 3130000 +1 halt 94 3140000 +1 halt 95 3140000 +1 halt 96 3140000 +1 halt 97 3140000 +1 halt 98 3140000 +1 halt 99 3140000 +1 halt 100 3140000 +1 halt 101 3150000 +1 halt 102 3140000 +1 halt 103 3140000 +1 halt 104 3140000 +1 halt 105 3140000 +1 halt 106 3140000 +1 halt 107 3140000 +1 halt 108 3140000 +1 halt 109 3150000 +1 halt 110 3140000 +1 halt 111 3130000 +1 halt 112 3140000 +1 halt 113 3140000 +1 halt 114 3140000 +1 halt 115 3140000 +1 halt 116 3140000 +1 halt 117 3150000 +1 halt 118 3140000 +1 halt 119 3140000 +1 halt 120 3130000 +1 halt 121 3140000 +1 halt 122 3140000 +1 halt 123 3140000 +1 halt 124 3150000 +1 halt 125 3140000 +1 halt 126 3140000 +1 halt 127 3140000 +1 halt 128 3140000 +1 halt 129 3140000 +1 halt 130 3150000 +1 halt 131 3140000 +1 halt 132 3150000 +1 halt 133 3150000 +1 halt 134 3140000 +1 halt 135 3130000 +1 halt 136 3140000 +1 halt 137 3140000 +1 halt 138 3140000 +1 halt 139 3140000 +1 halt 140 3140000 +1 halt 141 3150000 +1 halt 142 3140000 +1 halt 143 3140000 +1 halt 144 3140000 +1 halt 145 3130000 +1 halt 146 3150000 +1 halt 147 3140000 +1 halt 148 3140000 +1 halt 149 3140000 +1 halt 150 3130000 +1 halt 151 3140000 +1 halt 152 3130000 +1 halt 153 3140000 +1 halt 154 3140000 +1 halt 155 3130000 +1 halt 156 3150000 +1 halt 157 3140000 +1 halt 158 3130000 +1 halt 159 3140000 +1 halt 160 3140000 +1 halt 161 3140000 +1 halt 162 3150000 +1 halt 163 3140000 +1 halt 164 3160000 +1 halt 165 3150000 +1 halt 166 3130000 +1 halt 167 3140000 +1 halt 168 3140000 +1 halt 169 3130000 +1 halt 170 3140000 +1 halt 171 3140000 +1 halt 172 3140000 +1 halt 173 3140000 +1 halt 174 3140000 +1 halt 175 3160000 +1 halt 176 3140000 +1 halt 177 3130000 +1 halt 178 3130000 +1 halt 179 3150000 +1 halt 180 3150000 +1 halt 181 3140000 +1 halt 182 3140000 +1 halt 183 3140000 +1 halt 184 3140000 +1 halt 185 3140000 +1 halt 186 3140000 +1 halt 187 3150000 +1 halt 188 3150000 +1 halt 189 3130000 +1 halt 190 3130000 +1 halt 191 3140000 +1 halt 192 3140000 +1 halt 193 3130000 +1 halt 194 3140000 +1 halt 195 3150000 +1 halt 196 3150000 +1 halt 197 3140000 +1 halt 198 3130000 +1 halt 199 3140000 +1 halt 200 3140000 +1 halt 201 3140000 +1 halt 202 3140000 +1 halt 203 3140000 +1 halt 204 3150000 +1 halt 205 3140000 +1 halt 206 3140000 +1 halt 207 3130000 +1 halt 208 3140000 +1 halt 209 3140000 +1 halt 210 3140000 +1 halt 211 3160000 +1 halt 212 3140000 +1 halt 213 3130000 +1 halt 214 3140000 +1 halt 215 3140000 +1 halt 216 3130000 +1 halt 217 3140000 +1 halt 218 3140000 +1 halt 219 3160000 +1 halt 220 3150000 +1 halt 221 3140000 +1 halt 222 3140000 +1 halt 223 3140000 +1 halt 224 3130000 +1 halt 225 3140000 +1 halt 226 3140000 +1 halt 227 3130000 +1 halt 228 3150000 +1 halt 229 3140000 +1 halt 230 3140000 +1 halt 231 3130000 +1 halt 232 3130000 +1 halt 233 3150000 +1 halt 234 3140000 +1 halt 235 3140000 +1 halt 236 3130000 +1 halt 237 3140000 +1 halt 238 3130000 +1 halt 239 3130000 +1 halt 240 3140000 +1 halt 241 3140000 +1 halt 242 3140000 +1 halt 243 3150000 +1 halt 244 3130000 +1 halt 245 3140000 +1 halt 246 3140000 +1 halt 247 3140000 +1 halt 248 3140000 +1 halt 249 3140000 +1 halt 250 3140000 +1 halt 251 3140000 +1 halt 252 3130000 +1 halt 253 3120000 +1 halt 254 3130000 +1 halt 255 3130000 +1 halt 256 3120000 +1 halt 257 3140000 +1 halt 258 3120000 +1 halt 259 3140000 +1 halt 260 3130000 +1 halt 261 3130000 +1 halt 262 3120000 +1 halt 263 3120000 +1 halt 264 3130000 +1 halt 265 3130000 +1 halt 266 3140000 +1 halt 267 3130000 +1 halt 268 3140000 +1 halt 269 3140000 +1 halt 270 3130000 +1 halt 271 3130000 +1 halt 272 3130000 +1 halt 273 3130000 +1 halt 274 3150000 +1 halt 275 3150000 +1 halt 276 3120000 +1 halt 277 3130000 +1 halt 278 3130000 +1 halt 279 3130000 +1 halt 280 3130000 +1 halt 281 3120000 +1 halt 282 3140000 +1 halt 283 3150000 +1 halt 284 3130000 +1 halt 285 3130000 +1 halt 286 3120000 +1 halt 287 3130000 +1 halt 288 3120000 +1 halt 289 3130000 +1 halt 290 3120000 +1 halt 291 3150000 +1 halt 292 3120000 +1 halt 293 3130000 +1 halt 294 3120000 +1 halt 295 3130000 +1 halt 296 3130000 +1 halt 297 3120000 +1 halt 298 3140000 +1 halt 299 3140000 +1 halt 300 3130000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998009 +# done SystemTime { tv_sec: 1793969336, tv_nsec: 762934283 } +# passes used 1 of 1 (dropped: []) +# run - halt = 160.0 +/- NaN mW (per-pass sd NaN); 1/1 passes positive; 7 sample excursions beyond 6 MAD +# per-pass differences (mW): 160.0 +# board power while running 3300 mW; jobs/s 12499751.7; updates/s 0.0; measured PL clock 99.998 MHz diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/t0-idle.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/t0-idle.dat new file mode 100644 index 000000000..094db6fd1 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/t0-idle.dat @@ -0,0 +1,505 @@ +# class t0-idle cores 1 +# wai-quantum-fpga meter passes=8 settle=60s samples=30 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793974380, tv_nsec: 248171637 } +# pass state sample power_uW +1 run 1 3130000 +1 run 2 3140000 +1 run 3 3130000 +1 run 4 3140000 +1 run 5 3140000 +1 run 6 3140000 +1 run 7 3150000 +1 run 8 3140000 +1 run 9 3150000 +1 run 10 3140000 +1 run 11 3150000 +1 run 12 3150000 +1 run 13 3140000 +1 run 14 3140000 +1 run 15 3150000 +1 run 16 3140000 +1 run 17 3150000 +1 run 18 3150000 +1 run 19 3140000 +1 run 20 3150000 +1 run 21 3140000 +1 run 22 3160000 +1 run 23 3140000 +1 run 24 3150000 +1 run 25 3150000 +1 run 26 3150000 +1 run 27 3150000 +1 run 28 3140000 +1 run 29 3140000 +1 run 30 3150000 +# point pass=1 state=run jobs_per_s=33332655.7 updates_per_s=0.0 clock_hz=99997945 +1 halt 1 3130000 +1 halt 2 3140000 +1 halt 3 3130000 +1 halt 4 3140000 +1 halt 5 3130000 +1 halt 6 3130000 +1 halt 7 3130000 +1 halt 8 3130000 +1 halt 9 3130000 +1 halt 10 3120000 +1 halt 11 3120000 +1 halt 12 3140000 +1 halt 13 3130000 +1 halt 14 3130000 +1 halt 15 3130000 +1 halt 16 3140000 +1 halt 17 3120000 +1 halt 18 3140000 +1 halt 19 3140000 +1 halt 20 3140000 +1 halt 21 3130000 +1 halt 22 3130000 +1 halt 23 3130000 +1 halt 24 3140000 +1 halt 25 3120000 +1 halt 26 3130000 +1 halt 27 3140000 +1 halt 28 3140000 +1 halt 29 3130000 +1 halt 30 3140000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997945 +2 halt 1 3140000 +2 halt 2 3360000 +2 halt 3 3140000 +2 halt 4 3140000 +2 halt 5 3140000 +2 halt 6 3140000 +2 halt 7 3150000 +2 halt 8 3130000 +2 halt 9 3140000 +2 halt 10 3140000 +2 halt 11 3130000 +2 halt 12 3130000 +2 halt 13 3140000 +2 halt 14 3130000 +2 halt 15 3160000 +2 halt 16 3150000 +2 halt 17 3140000 +2 halt 18 3140000 +2 halt 19 3130000 +2 halt 20 3150000 +2 halt 21 3140000 +2 halt 22 3130000 +2 halt 23 3140000 +2 halt 24 3150000 +2 halt 25 3140000 +2 halt 26 3130000 +2 halt 27 3140000 +2 halt 28 3130000 +2 halt 29 3130000 +2 halt 30 3130000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997945 +2 run 1 3120000 +2 run 2 3120000 +2 run 3 3130000 +2 run 4 3130000 +2 run 5 3110000 +2 run 6 3120000 +2 run 7 3150000 +2 run 8 3120000 +2 run 9 3140000 +2 run 10 3130000 +2 run 11 3130000 +2 run 12 3130000 +2 run 13 3120000 +2 run 14 3130000 +2 run 15 3140000 +2 run 16 3140000 +2 run 17 3130000 +2 run 18 3130000 +2 run 19 3130000 +2 run 20 3120000 +2 run 21 3130000 +2 run 22 3140000 +2 run 23 3140000 +2 run 24 3140000 +2 run 25 3130000 +2 run 26 3140000 +2 run 27 3130000 +2 run 28 3140000 +2 run 29 3120000 +2 run 30 3150000 +# point pass=2 state=run jobs_per_s=33332686.8 updates_per_s=0.0 clock_hz=99998037 +3 run 1 3140000 +3 run 2 3140000 +3 run 3 3130000 +3 run 4 3150000 +3 run 5 3140000 +3 run 6 3140000 +3 run 7 3130000 +3 run 8 3140000 +3 run 9 3140000 +3 run 10 3130000 +3 run 11 3140000 +3 run 12 3160000 +3 run 13 3140000 +3 run 14 3140000 +3 run 15 3150000 +3 run 16 3150000 +3 run 17 3120000 +3 run 18 3130000 +3 run 19 3130000 +3 run 20 3130000 +3 run 21 3540000 +3 run 22 3130000 +3 run 23 3130000 +3 run 24 3120000 +3 run 25 3120000 +3 run 26 3130000 +3 run 27 3150000 +3 run 28 3130000 +3 run 29 3130000 +3 run 30 3140000 +# point pass=3 state=run jobs_per_s=33332682.8 updates_per_s=0.0 clock_hz=99998024 +3 halt 1 3140000 +3 halt 2 3130000 +3 halt 3 3110000 +3 halt 4 3120000 +3 halt 5 3120000 +3 halt 6 3120000 +3 halt 7 3120000 +3 halt 8 3120000 +3 halt 9 3140000 +3 halt 10 3120000 +3 halt 11 3120000 +3 halt 12 3120000 +3 halt 13 3120000 +3 halt 14 3130000 +3 halt 15 3120000 +3 halt 16 3110000 +3 halt 17 3130000 +3 halt 18 3120000 +3 halt 19 3110000 +3 halt 20 3110000 +3 halt 21 3120000 +3 halt 22 3130000 +3 halt 23 3120000 +3 halt 24 3130000 +3 halt 25 3130000 +3 halt 26 3120000 +3 halt 27 3130000 +3 halt 28 3120000 +3 halt 29 3130000 +3 halt 30 3120000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99998013 +4 run 1 3120000 +4 run 2 3120000 +4 run 3 3120000 +4 run 4 3140000 +4 run 5 3130000 +4 run 6 3140000 +4 run 7 3130000 +4 run 8 3120000 +4 run 9 3130000 +4 run 10 3130000 +4 run 11 3110000 +4 run 12 3130000 +4 run 13 3130000 +4 run 14 3130000 +4 run 15 3140000 +4 run 16 3120000 +4 run 17 3130000 +4 run 18 3120000 +4 run 19 3120000 +4 run 20 3140000 +4 run 21 3140000 +4 run 22 3120000 +4 run 23 3130000 +4 run 24 3130000 +4 run 25 3120000 +4 run 26 3120000 +4 run 27 3120000 +4 run 28 3140000 +4 run 29 3140000 +4 run 30 3130000 +# point pass=4 state=run jobs_per_s=33332675.3 updates_per_s=0.0 clock_hz=99998003 +4 halt 1 3130000 +4 halt 2 3120000 +4 halt 3 3140000 +4 halt 4 3130000 +4 halt 5 3140000 +4 halt 6 3140000 +4 halt 7 3130000 +4 halt 8 3130000 +4 halt 9 3150000 +4 halt 10 3130000 +4 halt 11 3140000 +4 halt 12 3140000 +4 halt 13 3130000 +4 halt 14 3140000 +4 halt 15 3140000 +4 halt 16 3130000 +4 halt 17 3160000 +4 halt 18 3150000 +4 halt 19 3140000 +4 halt 20 3140000 +4 halt 21 3130000 +4 halt 22 3140000 +4 halt 23 3140000 +4 halt 24 3130000 +4 halt 25 3140000 +4 halt 26 3150000 +4 halt 27 3140000 +4 halt 28 3140000 +4 halt 29 3140000 +4 halt 30 3140000 +# point pass=4 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997996 +5 halt 1 3140000 +5 halt 2 3130000 +5 halt 3 3130000 +5 halt 4 3140000 +5 halt 5 3140000 +5 halt 6 3150000 +5 halt 7 3140000 +5 halt 8 3140000 +5 halt 9 3130000 +5 halt 10 3150000 +5 halt 11 3130000 +5 halt 12 3140000 +5 halt 13 3140000 +5 halt 14 3150000 +5 halt 15 3140000 +5 halt 16 3140000 +5 halt 17 3140000 +5 halt 18 3140000 +5 halt 19 3140000 +5 halt 20 3130000 +5 halt 21 3140000 +5 halt 22 3140000 +5 halt 23 3130000 +5 halt 24 3140000 +5 halt 25 3160000 +5 halt 26 3120000 +5 halt 27 3120000 +5 halt 28 3120000 +5 halt 29 3130000 +5 halt 30 3130000 +# point pass=5 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997989 +5 run 1 3150000 +5 run 2 3150000 +5 run 3 3150000 +5 run 4 3140000 +5 run 5 3130000 +5 run 6 3150000 +5 run 7 3140000 +5 run 8 3140000 +5 run 9 3140000 +5 run 10 3130000 +5 run 11 3160000 +5 run 12 3140000 +5 run 13 3140000 +5 run 14 3140000 +5 run 15 3140000 +5 run 16 3140000 +5 run 17 3140000 +5 run 18 3140000 +5 run 19 3140000 +5 run 20 3150000 +5 run 21 3140000 +5 run 22 3140000 +5 run 23 3460000 +5 run 24 3140000 +5 run 25 3140000 +5 run 26 3150000 +5 run 27 3140000 +5 run 28 3140000 +5 run 29 3140000 +5 run 30 3140000 +# point pass=5 state=run jobs_per_s=33332668.6 updates_per_s=0.0 clock_hz=99997984 +6 halt 1 3140000 +6 halt 2 3140000 +6 halt 3 3140000 +6 halt 4 3140000 +6 halt 5 3130000 +6 halt 6 3140000 +6 halt 7 3140000 +6 halt 8 3150000 +6 halt 9 3130000 +6 halt 10 3140000 +6 halt 11 3130000 +6 halt 12 3130000 +6 halt 13 3130000 +6 halt 14 3140000 +6 halt 15 3130000 +6 halt 16 3130000 +6 halt 17 3140000 +6 halt 18 3140000 +6 halt 19 3140000 +6 halt 20 3140000 +6 halt 21 3130000 +6 halt 22 3150000 +6 halt 23 3150000 +6 halt 24 3130000 +6 halt 25 3140000 +6 halt 26 3140000 +6 halt 27 3140000 +6 halt 28 3140000 +6 halt 29 3140000 +6 halt 30 3130000 +# point pass=6 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997979 +6 run 1 3140000 +6 run 2 3130000 +6 run 3 3140000 +6 run 4 3130000 +6 run 5 3120000 +6 run 6 3130000 +6 run 7 3140000 +6 run 8 3140000 +6 run 9 3140000 +6 run 10 3130000 +6 run 11 3150000 +6 run 12 3130000 +6 run 13 3140000 +6 run 14 3130000 +6 run 15 3130000 +6 run 16 3130000 +6 run 17 3130000 +6 run 18 3130000 +6 run 19 3160000 +6 run 20 3150000 +6 run 21 3130000 +6 run 22 3140000 +6 run 23 3140000 +6 run 24 3140000 +6 run 25 3120000 +6 run 26 3120000 +6 run 27 3140000 +6 run 28 3150000 +6 run 29 3130000 +6 run 30 3120000 +# point pass=6 state=run jobs_per_s=33332666.1 updates_per_s=0.0 clock_hz=99997975 +7 run 1 3140000 +7 run 2 3130000 +7 run 3 3150000 +7 run 4 3140000 +7 run 5 3130000 +7 run 6 3150000 +7 run 7 3140000 +7 run 8 3150000 +7 run 9 3130000 +7 run 10 3140000 +7 run 11 3140000 +7 run 12 3130000 +7 run 13 3130000 +7 run 14 3140000 +7 run 15 3130000 +7 run 16 3150000 +7 run 17 3150000 +7 run 18 3140000 +7 run 19 3140000 +7 run 20 3120000 +7 run 21 3120000 +7 run 22 3140000 +7 run 23 3130000 +7 run 24 3130000 +7 run 25 3150000 +7 run 26 3130000 +7 run 27 3130000 +7 run 28 3120000 +7 run 29 3130000 +7 run 30 3130000 +# point pass=7 state=run jobs_per_s=33332665.0 updates_per_s=0.0 clock_hz=99997972 +7 halt 1 3120000 +7 halt 2 3140000 +7 halt 3 3130000 +7 halt 4 3140000 +7 halt 5 3140000 +7 halt 6 3130000 +7 halt 7 3140000 +7 halt 8 3130000 +7 halt 9 3130000 +7 halt 10 3140000 +7 halt 11 3130000 +7 halt 12 3130000 +7 halt 13 3140000 +7 halt 14 3130000 +7 halt 15 3140000 +7 halt 16 3130000 +7 halt 17 3140000 +7 halt 18 3120000 +7 halt 19 3120000 +7 halt 20 3130000 +7 halt 21 3120000 +7 halt 22 3130000 +7 halt 23 3130000 +7 halt 24 3120000 +7 halt 25 3120000 +7 halt 26 3120000 +7 halt 27 3140000 +7 halt 28 3150000 +7 halt 29 3120000 +7 halt 30 3140000 +# point pass=7 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997971 +8 run 1 3150000 +8 run 2 3150000 +8 run 3 3140000 +8 run 4 3140000 +8 run 5 3140000 +8 run 6 3130000 +8 run 7 3130000 +8 run 8 3150000 +8 run 9 3140000 +8 run 10 3150000 +8 run 11 3130000 +8 run 12 3130000 +8 run 13 3130000 +8 run 14 3140000 +8 run 15 3140000 +8 run 16 3140000 +8 run 17 3140000 +8 run 18 3120000 +8 run 19 3130000 +8 run 20 3120000 +8 run 21 3130000 +8 run 22 3140000 +8 run 23 3130000 +8 run 24 3130000 +8 run 25 3150000 +8 run 26 3130000 +8 run 27 3140000 +8 run 28 3140000 +8 run 29 3140000 +8 run 30 3130000 +# point pass=8 state=run jobs_per_s=33332663.2 updates_per_s=0.0 clock_hz=99997967 +8 halt 1 3130000 +8 halt 2 3130000 +8 halt 3 3130000 +8 halt 4 3130000 +8 halt 5 3140000 +8 halt 6 3120000 +8 halt 7 3120000 +8 halt 8 3140000 +8 halt 9 3150000 +8 halt 10 3130000 +8 halt 11 3140000 +8 halt 12 3120000 +8 halt 13 3120000 +8 halt 14 3130000 +8 halt 15 3140000 +8 halt 16 3130000 +8 halt 17 3140000 +8 halt 18 3130000 +8 halt 19 3140000 +8 halt 20 3140000 +8 halt 21 3140000 +8 halt 22 3140000 +8 halt 23 3120000 +8 halt 24 3140000 +8 halt 25 3130000 +8 halt 26 3130000 +8 halt 27 3120000 +8 halt 28 3120000 +8 halt 29 3140000 +8 halt 30 3140000 +# point pass=8 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997966 +# done SystemTime { tv_sec: 1793975821, tv_nsec: 177880976 } +# passes used 8 of 8 (dropped: []) +# run - halt = 1.9 +/- 4.0 mW (per-pass sd 11.3); 4/8 passes positive; 3 sample excursions beyond 6 MAD +# per-pass differences (mW): 10.0 -10.0 20.0 -10.0 0.0 -10.0 5.0 10.0 +# board power while running 3136 mW; jobs/s 33332670.4; updates/s 0.0; measured PL clock 99.998 MHz +# pre-registered prediction 4.0 mW: measured/predicted = 0.47, -0.5 sigma from it diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/t0-recall-50MHz.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/t0-recall-50MHz.dat new file mode 100644 index 000000000..46d24f582 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/t0-recall-50MHz.dat @@ -0,0 +1,381 @@ +# class t0-recall cores 1 +# wai-quantum-fpga meter passes=6 settle=60s samples=30 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793975822, tv_nsec: 342834432 } +# pass state sample power_uW +1 run 1 3190000 +1 run 2 3190000 +1 run 3 3610000 +1 run 4 3190000 +1 run 5 3200000 +1 run 6 3190000 +1 run 7 3190000 +1 run 8 3190000 +1 run 9 3190000 +1 run 10 3190000 +1 run 11 3180000 +1 run 12 3180000 +1 run 13 3200000 +1 run 14 3200000 +1 run 15 3180000 +1 run 16 3180000 +1 run 17 3180000 +1 run 18 3190000 +1 run 19 3180000 +1 run 20 3190000 +1 run 21 3190000 +1 run 22 3210000 +1 run 23 3180000 +1 run 24 3180000 +1 run 25 3190000 +1 run 26 3190000 +1 run 27 3190000 +1 run 28 3200000 +1 run 29 3190000 +1 run 30 3180000 +# point pass=1 state=run jobs_per_s=6249874.2 updates_per_s=0.0 clock_hz=49998982 +1 halt 1 3110000 +1 halt 2 3130000 +1 halt 3 3120000 +1 halt 4 3110000 +1 halt 5 3120000 +1 halt 6 3120000 +1 halt 7 3110000 +1 halt 8 3120000 +1 halt 9 3120000 +1 halt 10 3130000 +1 halt 11 3120000 +1 halt 12 3120000 +1 halt 13 3110000 +1 halt 14 3110000 +1 halt 15 3110000 +1 halt 16 3110000 +1 halt 17 3100000 +1 halt 18 3120000 +1 halt 19 3110000 +1 halt 20 3110000 +1 halt 21 3110000 +1 halt 22 3110000 +1 halt 23 3100000 +1 halt 24 3110000 +1 halt 25 3120000 +1 halt 26 3110000 +1 halt 27 3110000 +1 halt 28 3110000 +1 halt 29 3110000 +1 halt 30 3100000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=49998982 +2 halt 1 3110000 +2 halt 2 3110000 +2 halt 3 3110000 +2 halt 4 3110000 +2 halt 5 3110000 +2 halt 6 3110000 +2 halt 7 3130000 +2 halt 8 3110000 +2 halt 9 3110000 +2 halt 10 3100000 +2 halt 11 3110000 +2 halt 12 3110000 +2 halt 13 3110000 +2 halt 14 3110000 +2 halt 15 3110000 +2 halt 16 3110000 +2 halt 17 3100000 +2 halt 18 3110000 +2 halt 19 3110000 +2 halt 20 3100000 +2 halt 21 3120000 +2 halt 22 3130000 +2 halt 23 3110000 +2 halt 24 3100000 +2 halt 25 3110000 +2 halt 26 3120000 +2 halt 27 3100000 +2 halt 28 3120000 +2 halt 29 3120000 +2 halt 30 3140000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=49998981 +2 run 1 3190000 +2 run 2 3190000 +2 run 3 3180000 +2 run 4 3200000 +2 run 5 3190000 +2 run 6 3180000 +2 run 7 3190000 +2 run 8 3190000 +2 run 9 3180000 +2 run 10 3180000 +2 run 11 3190000 +2 run 12 3190000 +2 run 13 3190000 +2 run 14 3180000 +2 run 15 3190000 +2 run 16 3190000 +2 run 17 3200000 +2 run 18 3190000 +2 run 19 3210000 +2 run 20 3190000 +2 run 21 3200000 +2 run 22 3190000 +2 run 23 3200000 +2 run 24 3200000 +2 run 25 3190000 +2 run 26 3190000 +2 run 27 3200000 +2 run 28 3200000 +2 run 29 3190000 +2 run 30 3190000 +# point pass=2 state=run jobs_per_s=6249874.0 updates_per_s=0.0 clock_hz=49998981 +3 halt 1 3110000 +3 halt 2 3110000 +3 halt 3 3110000 +3 halt 4 3100000 +3 halt 5 3110000 +3 halt 6 3110000 +3 halt 7 3120000 +3 halt 8 3110000 +3 halt 9 3120000 +3 halt 10 3110000 +3 halt 11 3110000 +3 halt 12 3110000 +3 halt 13 3120000 +3 halt 14 3120000 +3 halt 15 3130000 +3 halt 16 3130000 +3 halt 17 3110000 +3 halt 18 3120000 +3 halt 19 3110000 +3 halt 20 3120000 +3 halt 21 3120000 +3 halt 22 3110000 +3 halt 23 3110000 +3 halt 24 3130000 +3 halt 25 3110000 +3 halt 26 3120000 +3 halt 27 3100000 +3 halt 28 3110000 +3 halt 29 3110000 +3 halt 30 3110000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=49998981 +3 run 1 3170000 +3 run 2 3170000 +3 run 3 3190000 +3 run 4 3200000 +3 run 5 3170000 +3 run 6 3170000 +3 run 7 3180000 +3 run 8 3170000 +3 run 9 3180000 +3 run 10 3170000 +3 run 11 3180000 +3 run 12 3190000 +3 run 13 3200000 +3 run 14 3170000 +3 run 15 3180000 +3 run 16 3180000 +3 run 17 3180000 +3 run 18 3180000 +3 run 19 3180000 +3 run 20 3180000 +3 run 21 3200000 +3 run 22 3190000 +3 run 23 3200000 +3 run 24 3190000 +3 run 25 3190000 +3 run 26 3190000 +3 run 27 3190000 +3 run 28 3200000 +3 run 29 3190000 +3 run 30 3190000 +# point pass=3 state=run jobs_per_s=6249873.9 updates_per_s=0.0 clock_hz=49998980 +4 halt 1 3120000 +4 halt 2 3100000 +4 halt 3 3100000 +4 halt 4 3100000 +4 halt 5 3100000 +4 halt 6 3100000 +4 halt 7 3110000 +4 halt 8 3100000 +4 halt 9 3110000 +4 halt 10 3100000 +4 halt 11 3100000 +4 halt 12 3100000 +4 halt 13 3100000 +4 halt 14 3100000 +4 halt 15 3100000 +4 halt 16 3100000 +4 halt 17 3110000 +4 halt 18 3100000 +4 halt 19 3100000 +4 halt 20 3100000 +4 halt 21 3090000 +4 halt 22 3110000 +4 halt 23 3110000 +4 halt 24 3100000 +4 halt 25 3100000 +4 halt 26 3100000 +4 halt 27 3100000 +4 halt 28 3090000 +4 halt 29 3100000 +4 halt 30 3100000 +# point pass=4 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=49998980 +4 run 1 3180000 +4 run 2 3190000 +4 run 3 3180000 +4 run 4 3190000 +4 run 5 3190000 +4 run 6 3200000 +4 run 7 3190000 +4 run 8 3190000 +4 run 9 3170000 +4 run 10 3190000 +4 run 11 3190000 +4 run 12 3190000 +4 run 13 3190000 +4 run 14 3190000 +4 run 15 3180000 +4 run 16 3190000 +4 run 17 3200000 +4 run 18 3190000 +4 run 19 3190000 +4 run 20 3200000 +4 run 21 3200000 +4 run 22 3190000 +4 run 23 3180000 +4 run 24 3180000 +4 run 25 3170000 +4 run 26 3180000 +4 run 27 3170000 +4 run 28 3180000 +4 run 29 3200000 +4 run 30 3210000 +# point pass=4 state=run jobs_per_s=6249873.9 updates_per_s=0.0 clock_hz=49998979 +5 halt 1 3100000 +5 halt 2 3100000 +5 halt 3 3110000 +5 halt 4 3110000 +5 halt 5 3100000 +5 halt 6 3110000 +5 halt 7 3100000 +5 halt 8 3100000 +5 halt 9 3100000 +5 halt 10 3110000 +5 halt 11 3110000 +5 halt 12 3110000 +5 halt 13 3110000 +5 halt 14 3100000 +5 halt 15 3100000 +5 halt 16 3100000 +5 halt 17 3100000 +5 halt 18 3120000 +5 halt 19 3100000 +5 halt 20 3090000 +5 halt 21 3100000 +5 halt 22 3090000 +5 halt 23 3100000 +5 halt 24 3100000 +5 halt 25 3100000 +5 halt 26 3110000 +5 halt 27 3100000 +5 halt 28 3100000 +5 halt 29 3110000 +5 halt 30 3100000 +# point pass=5 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=49998980 +5 run 1 3180000 +5 run 2 3180000 +5 run 3 3200000 +5 run 4 3190000 +5 run 5 3180000 +5 run 6 3190000 +5 run 7 3190000 +5 run 8 3180000 +5 run 9 3190000 +5 run 10 3190000 +5 run 11 3170000 +5 run 12 3190000 +5 run 13 3180000 +5 run 14 3190000 +5 run 15 3180000 +5 run 16 3180000 +5 run 17 3220000 +5 run 18 3190000 +5 run 19 3180000 +5 run 20 3190000 +5 run 21 3180000 +5 run 22 3180000 +5 run 23 3180000 +5 run 24 3180000 +5 run 25 3180000 +5 run 26 3180000 +5 run 27 3200000 +5 run 28 3180000 +5 run 29 3190000 +5 run 30 3190000 +# point pass=5 state=run jobs_per_s=6249878.2 updates_per_s=0.0 clock_hz=49999014 +6 halt 1 3120000 +6 halt 2 3100000 +6 halt 3 3100000 +6 halt 4 3100000 +6 halt 5 3110000 +6 halt 6 3110000 +6 halt 7 3100000 +6 halt 8 3110000 +6 halt 9 3100000 +6 halt 10 3110000 +6 halt 11 3100000 +6 halt 12 3110000 +6 halt 13 3100000 +6 halt 14 3110000 +6 halt 15 3110000 +6 halt 16 3100000 +6 halt 17 3100000 +6 halt 18 3100000 +6 halt 19 3110000 +6 halt 20 3100000 +6 halt 21 3110000 +6 halt 22 3110000 +6 halt 23 3120000 +6 halt 24 3120000 +6 halt 25 3110000 +6 halt 26 3110000 +6 halt 27 3100000 +6 halt 28 3110000 +6 halt 29 3100000 +6 halt 30 3100000 +# point pass=6 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=49999283 +6 run 1 3190000 +6 run 2 3180000 +6 run 3 3190000 +6 run 4 3190000 +6 run 5 3170000 +6 run 6 3190000 +6 run 7 3200000 +6 run 8 3180000 +6 run 9 3200000 +6 run 10 3190000 +6 run 11 3350000 +6 run 12 3190000 +6 run 13 3190000 +6 run 14 3190000 +6 run 15 3180000 +6 run 16 3550000 +6 run 17 3190000 +6 run 18 3190000 +6 run 19 3190000 +6 run 20 3180000 +6 run 21 3180000 +6 run 22 3210000 +6 run 23 3320000 +6 run 24 3190000 +6 run 25 3180000 +6 run 26 3180000 +6 run 27 3190000 +6 run 28 3190000 +6 run 29 3190000 +6 run 30 3210000 +# point pass=6 state=run jobs_per_s=6249906.7 updates_per_s=0.0 clock_hz=49999241 +# done SystemTime { tv_sec: 1793976903, tv_nsec: 28061803 } +# passes used 6 of 6 (dropped: []) +# run - halt = 80.0 +/- 2.6 mW (per-pass sd 6.3); 6/6 passes positive; 5 sample excursions beyond 6 MAD +# per-pass differences (mW): 80.0 80.0 70.0 90.0 80.0 80.0 +# board power while running 3187 mW; jobs/s 6249880.1; updates/s 0.0; measured PL clock 49.999 MHz +# pre-registered prediction 80.0 mW: measured/predicted = 1.00, 0.0 sigma from it diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/t0-recall.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/t0-recall.dat new file mode 100644 index 000000000..24b2086c3 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/emio-classes/t0-recall.dat @@ -0,0 +1,629 @@ +# class t0-recall cores 1 +# wai-quantum-fpga meter passes=10 settle=60s samples=30 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793970777, tv_nsec: 815511996 } +# pass state sample power_uW +1 halt 1 3140000 +1 halt 2 3150000 +1 halt 3 3140000 +1 halt 4 3140000 +1 halt 5 3140000 +1 halt 6 3140000 +1 halt 7 3140000 +1 halt 8 3150000 +1 halt 9 3140000 +1 halt 10 3130000 +1 halt 11 3140000 +1 halt 12 3130000 +1 halt 13 3140000 +1 halt 14 3140000 +1 halt 15 3130000 +1 halt 16 3190000 +1 halt 17 3150000 +1 halt 18 3140000 +1 halt 19 3150000 +1 halt 20 3140000 +1 halt 21 3140000 +1 halt 22 3140000 +1 halt 23 3130000 +1 halt 24 3140000 +1 halt 25 3150000 +1 halt 26 3150000 +1 halt 27 3130000 +1 halt 28 3150000 +1 halt 29 3140000 +1 halt 30 3140000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997681 +1 run 1 3290000 +1 run 2 3300000 +1 run 3 3300000 +1 run 4 3300000 +1 run 5 3320000 +1 run 6 3290000 +1 run 7 3300000 +1 run 8 3300000 +1 run 9 3300000 +1 run 10 3290000 +1 run 11 3290000 +1 run 12 3300000 +1 run 13 3290000 +1 run 14 3290000 +1 run 15 3320000 +1 run 16 3300000 +1 run 17 3300000 +1 run 18 3290000 +1 run 19 3290000 +1 run 20 3290000 +1 run 21 3280000 +1 run 22 3290000 +1 run 23 3300000 +1 run 24 3300000 +1 run 25 3290000 +1 run 26 3290000 +1 run 27 3300000 +1 run 28 3290000 +1 run 29 3290000 +1 run 30 3290000 +# point pass=1 state=run jobs_per_s=12499718.2 updates_per_s=0.0 clock_hz=99997723 +2 halt 1 3130000 +2 halt 2 3140000 +2 halt 3 3130000 +2 halt 4 3130000 +2 halt 5 3150000 +2 halt 6 3130000 +2 halt 7 3120000 +2 halt 8 3140000 +2 halt 9 3140000 +2 halt 10 3140000 +2 halt 11 3140000 +2 halt 12 3120000 +2 halt 13 3150000 +2 halt 14 3120000 +2 halt 15 3140000 +2 halt 16 3140000 +2 halt 17 3130000 +2 halt 18 3140000 +2 halt 19 3120000 +2 halt 20 3150000 +2 halt 21 3130000 +2 halt 22 3130000 +2 halt 23 3120000 +2 halt 24 3120000 +2 halt 25 3140000 +2 halt 26 3130000 +2 halt 27 3120000 +2 halt 28 3150000 +2 halt 29 3150000 +2 halt 30 3120000 +# point pass=2 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997759 +2 run 1 3290000 +2 run 2 3310000 +2 run 3 3300000 +2 run 4 3290000 +2 run 5 3300000 +2 run 6 3290000 +2 run 7 3300000 +2 run 8 3310000 +2 run 9 3290000 +2 run 10 3290000 +2 run 11 3300000 +2 run 12 3290000 +2 run 13 3300000 +2 run 14 3300000 +2 run 15 3300000 +2 run 16 3320000 +2 run 17 3300000 +2 run 18 3290000 +2 run 19 3300000 +2 run 20 3290000 +2 run 21 3290000 +2 run 22 3300000 +2 run 23 3310000 +2 run 24 3300000 +2 run 25 3330000 +2 run 26 3310000 +2 run 27 3300000 +2 run 28 3300000 +2 run 29 3310000 +2 run 30 3300000 +# point pass=2 state=run jobs_per_s=12499726.4 updates_per_s=0.0 clock_hz=99997789 +3 run 1 3290000 +3 run 2 3290000 +3 run 3 3290000 +3 run 4 3300000 +3 run 5 3310000 +3 run 6 3290000 +3 run 7 3290000 +3 run 8 3300000 +3 run 9 3290000 +3 run 10 3300000 +3 run 11 3290000 +3 run 12 3300000 +3 run 13 3310000 +3 run 14 3300000 +3 run 15 3300000 +3 run 16 3290000 +3 run 17 3290000 +3 run 18 3300000 +3 run 19 3290000 +3 run 20 3290000 +3 run 21 3290000 +3 run 22 3310000 +3 run 23 3300000 +3 run 24 3290000 +3 run 25 3290000 +3 run 26 3300000 +3 run 27 3300000 +3 run 28 3290000 +3 run 29 3290000 +3 run 30 3300000 +# point pass=3 state=run jobs_per_s=12499729.5 updates_per_s=0.0 clock_hz=99997814 +3 halt 1 3140000 +3 halt 2 3150000 +3 halt 3 3140000 +3 halt 4 3140000 +3 halt 5 3140000 +3 halt 6 3130000 +3 halt 7 3140000 +3 halt 8 3130000 +3 halt 9 3140000 +3 halt 10 3160000 +3 halt 11 3150000 +3 halt 12 3140000 +3 halt 13 3140000 +3 halt 14 3130000 +3 halt 15 3140000 +3 halt 16 3150000 +3 halt 17 3140000 +3 halt 18 3130000 +3 halt 19 3140000 +3 halt 20 3140000 +3 halt 21 3130000 +3 halt 22 3130000 +3 halt 23 3140000 +3 halt 24 3140000 +3 halt 25 3150000 +3 halt 26 3140000 +3 halt 27 3130000 +3 halt 28 3130000 +3 halt 29 3120000 +3 halt 30 3130000 +# point pass=3 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997837 +4 halt 1 3120000 +4 halt 2 3130000 +4 halt 3 3130000 +4 halt 4 3130000 +4 halt 5 3130000 +4 halt 6 3130000 +4 halt 7 3120000 +4 halt 8 3120000 +4 halt 9 3120000 +4 halt 10 3120000 +4 halt 11 3120000 +4 halt 12 3120000 +4 halt 13 3130000 +4 halt 14 3120000 +4 halt 15 3120000 +4 halt 16 3120000 +4 halt 17 3120000 +4 halt 18 3120000 +4 halt 19 3120000 +4 halt 20 3140000 +4 halt 21 3140000 +4 halt 22 3130000 +4 halt 23 3120000 +4 halt 24 3120000 +4 halt 25 3130000 +4 halt 26 3130000 +4 halt 27 3120000 +4 halt 28 3120000 +4 halt 29 3140000 +4 halt 30 3120000 +# point pass=4 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997854 +4 run 1 3330000 +4 run 2 3290000 +4 run 3 3290000 +4 run 4 3290000 +4 run 5 3290000 +4 run 6 3300000 +4 run 7 3330000 +4 run 8 3300000 +4 run 9 3310000 +4 run 10 3290000 +4 run 11 3290000 +4 run 12 3300000 +4 run 13 3300000 +4 run 14 3300000 +4 run 15 3290000 +4 run 16 3290000 +4 run 17 3320000 +4 run 18 3310000 +4 run 19 3300000 +4 run 20 3290000 +4 run 21 3300000 +4 run 22 3300000 +4 run 23 3300000 +4 run 24 3300000 +4 run 25 3290000 +4 run 26 3310000 +4 run 27 3290000 +4 run 28 3300000 +4 run 29 3290000 +4 run 30 3290000 +# point pass=4 state=run jobs_per_s=12499736.5 updates_per_s=0.0 clock_hz=99997868 +5 halt 1 3120000 +5 halt 2 3140000 +5 halt 3 3130000 +5 halt 4 3130000 +5 halt 5 3130000 +5 halt 6 3150000 +5 halt 7 3130000 +5 halt 8 3130000 +5 halt 9 3130000 +5 halt 10 3120000 +5 halt 11 3130000 +5 halt 12 3140000 +5 halt 13 3130000 +5 halt 14 3150000 +5 halt 15 3150000 +5 halt 16 3130000 +5 halt 17 3120000 +5 halt 18 3120000 +5 halt 19 3120000 +5 halt 20 3140000 +5 halt 21 3140000 +5 halt 22 3130000 +5 halt 23 3130000 +5 halt 24 3130000 +5 halt 25 3120000 +5 halt 26 3120000 +5 halt 27 3140000 +5 halt 28 3130000 +5 halt 29 3130000 +5 halt 30 3120000 +# point pass=5 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997880 +5 run 1 3290000 +5 run 2 3320000 +5 run 3 3300000 +5 run 4 3280000 +5 run 5 3290000 +5 run 6 3290000 +5 run 7 3290000 +5 run 8 3280000 +5 run 9 3280000 +5 run 10 3290000 +5 run 11 3300000 +5 run 12 3290000 +5 run 13 3290000 +5 run 14 3280000 +5 run 15 3300000 +5 run 16 3290000 +5 run 17 3290000 +5 run 18 3290000 +5 run 19 3290000 +5 run 20 3290000 +5 run 21 3290000 +5 run 22 3280000 +5 run 23 3300000 +5 run 24 3290000 +5 run 25 3290000 +5 run 26 3300000 +5 run 27 3290000 +5 run 28 3280000 +5 run 29 3280000 +5 run 30 3280000 +# point pass=5 state=run jobs_per_s=12499739.0 updates_per_s=0.0 clock_hz=99997890 +6 run 1 3300000 +6 run 2 3310000 +6 run 3 3290000 +6 run 4 3300000 +6 run 5 3300000 +6 run 6 3300000 +6 run 7 3310000 +6 run 8 3320000 +6 run 9 3290000 +6 run 10 3290000 +6 run 11 3290000 +6 run 12 3300000 +6 run 13 3290000 +6 run 14 3290000 +6 run 15 3310000 +6 run 16 3300000 +6 run 17 3310000 +6 run 18 3300000 +6 run 19 3320000 +6 run 20 3290000 +6 run 21 3290000 +6 run 22 3320000 +6 run 23 3310000 +6 run 24 3290000 +6 run 25 3300000 +6 run 26 3290000 +6 run 27 3710000 +6 run 28 3300000 +6 run 29 3300000 +6 run 30 3300000 +# point pass=6 state=run jobs_per_s=12499740.2 updates_per_s=0.0 clock_hz=99997899 +6 halt 1 3140000 +6 halt 2 3150000 +6 halt 3 3140000 +6 halt 4 3140000 +6 halt 5 3130000 +6 halt 6 3140000 +6 halt 7 3140000 +6 halt 8 3130000 +6 halt 9 3130000 +6 halt 10 3130000 +6 halt 11 3150000 +6 halt 12 3130000 +6 halt 13 3140000 +6 halt 14 3140000 +6 halt 15 3140000 +6 halt 16 3120000 +6 halt 17 3130000 +6 halt 18 3130000 +6 halt 19 3150000 +6 halt 20 3150000 +6 halt 21 3130000 +6 halt 22 3140000 +6 halt 23 3140000 +6 halt 24 3130000 +6 halt 25 3150000 +6 halt 26 3140000 +6 halt 27 3130000 +6 halt 28 3150000 +6 halt 29 3130000 +6 halt 30 3160000 +# point pass=6 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997906 +7 halt 1 3140000 +7 halt 2 3130000 +7 halt 3 3140000 +7 halt 4 3150000 +7 halt 5 3140000 +7 halt 6 3130000 +7 halt 7 3140000 +7 halt 8 3140000 +7 halt 9 3140000 +7 halt 10 3140000 +7 halt 11 3120000 +7 halt 12 3120000 +7 halt 13 3140000 +7 halt 14 3120000 +7 halt 15 3120000 +7 halt 16 3140000 +7 halt 17 3150000 +7 halt 18 3120000 +7 halt 19 3120000 +7 halt 20 3130000 +7 halt 21 3120000 +7 halt 22 3120000 +7 halt 23 3130000 +7 halt 24 3130000 +7 halt 25 3140000 +7 halt 26 3130000 +7 halt 27 3120000 +7 halt 28 3240000 +7 halt 29 3130000 +7 halt 30 3140000 +# point pass=7 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997913 +7 run 1 3300000 +7 run 2 3300000 +7 run 3 3300000 +7 run 4 3300000 +7 run 5 3310000 +7 run 6 3290000 +7 run 7 3300000 +7 run 8 3320000 +7 run 9 3300000 +7 run 10 3290000 +7 run 11 3300000 +7 run 12 3300000 +7 run 13 3300000 +7 run 14 3310000 +7 run 15 3300000 +7 run 16 3320000 +7 run 17 3310000 +7 run 18 3290000 +7 run 19 3310000 +7 run 20 3300000 +7 run 21 3290000 +7 run 22 3300000 +7 run 23 3300000 +7 run 24 3300000 +7 run 25 3300000 +7 run 26 3300000 +7 run 27 3300000 +7 run 28 3300000 +7 run 29 3300000 +7 run 30 3310000 +# point pass=7 state=run jobs_per_s=12499742.5 updates_per_s=0.0 clock_hz=99997918 +8 run 1 3320000 +8 run 2 3310000 +8 run 3 3640000 +8 run 4 3310000 +8 run 5 3330000 +8 run 6 3300000 +8 run 7 3300000 +8 run 8 3300000 +8 run 9 3310000 +8 run 10 3310000 +8 run 11 3300000 +8 run 12 3310000 +8 run 13 3320000 +8 run 14 3310000 +8 run 15 3310000 +8 run 16 3290000 +8 run 17 3300000 +8 run 18 3300000 +8 run 19 3310000 +8 run 20 3290000 +8 run 21 3290000 +8 run 22 3300000 +8 run 23 3290000 +8 run 24 3290000 +8 run 25 3290000 +8 run 26 3290000 +8 run 27 3300000 +8 run 28 3310000 +8 run 29 3300000 +8 run 30 3300000 +# point pass=8 state=run jobs_per_s=12499743.0 updates_per_s=0.0 clock_hz=99997922 +8 halt 1 3150000 +8 halt 2 3150000 +8 halt 3 3130000 +8 halt 4 3130000 +8 halt 5 3140000 +8 halt 6 3140000 +8 halt 7 3140000 +8 halt 8 3130000 +8 halt 9 3130000 +8 halt 10 3140000 +8 halt 11 3140000 +8 halt 12 3120000 +8 halt 13 3130000 +8 halt 14 3120000 +8 halt 15 3140000 +8 halt 16 3120000 +8 halt 17 3120000 +8 halt 18 3120000 +8 halt 19 3120000 +8 halt 20 3140000 +8 halt 21 3130000 +8 halt 22 3140000 +8 halt 23 3130000 +8 halt 24 3130000 +8 halt 25 3150000 +8 halt 26 3130000 +8 halt 27 3130000 +8 halt 28 3120000 +8 halt 29 3120000 +8 halt 30 3130000 +# point pass=8 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997926 +9 halt 1 3130000 +9 halt 2 3140000 +9 halt 3 3140000 +9 halt 4 3140000 +9 halt 5 3130000 +9 halt 6 3140000 +9 halt 7 3140000 +9 halt 8 3130000 +9 halt 9 3140000 +9 halt 10 3140000 +9 halt 11 3140000 +9 halt 12 3140000 +9 halt 13 3140000 +9 halt 14 3140000 +9 halt 15 3120000 +9 halt 16 3140000 +9 halt 17 3130000 +9 halt 18 3140000 +9 halt 19 3150000 +9 halt 20 3130000 +9 halt 21 3130000 +9 halt 22 3140000 +9 halt 23 3120000 +9 halt 24 3140000 +9 halt 25 3130000 +9 halt 26 3130000 +9 halt 27 3130000 +9 halt 28 3130000 +9 halt 29 3140000 +9 halt 30 3150000 +# point pass=9 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997929 +9 run 1 3290000 +9 run 2 3290000 +9 run 3 3310000 +9 run 4 3300000 +9 run 5 3290000 +9 run 6 3290000 +9 run 7 3290000 +9 run 8 3290000 +9 run 9 3290000 +9 run 10 3310000 +9 run 11 3300000 +9 run 12 3290000 +9 run 13 3290000 +9 run 14 3300000 +9 run 15 3290000 +9 run 16 3290000 +9 run 17 3300000 +9 run 18 3310000 +9 run 19 3320000 +9 run 20 3290000 +9 run 21 3290000 +9 run 22 3290000 +9 run 23 3290000 +9 run 24 3290000 +9 run 25 3290000 +9 run 26 3290000 +9 run 27 3320000 +9 run 28 3290000 +9 run 29 3300000 +9 run 30 3290000 +# point pass=9 state=run jobs_per_s=12499744.1 updates_per_s=0.0 clock_hz=99997931 +10 run 1 3300000 +10 run 2 3320000 +10 run 3 3290000 +10 run 4 3300000 +10 run 5 3300000 +10 run 6 3310000 +10 run 7 3300000 +10 run 8 3290000 +10 run 9 3300000 +10 run 10 3290000 +10 run 11 3300000 +10 run 12 3290000 +10 run 13 3290000 +10 run 14 3300000 +10 run 15 3290000 +10 run 16 3300000 +10 run 17 3300000 +10 run 18 3300000 +10 run 19 3320000 +10 run 20 3300000 +10 run 21 3300000 +10 run 22 3300000 +10 run 23 3300000 +10 run 24 3310000 +10 run 25 3310000 +10 run 26 3320000 +10 run 27 3300000 +10 run 28 3300000 +10 run 29 3310000 +10 run 30 3300000 +# point pass=10 state=run jobs_per_s=12499744.5 updates_per_s=0.0 clock_hz=99997934 +10 halt 1 3140000 +10 halt 2 3140000 +10 halt 3 3140000 +10 halt 4 3130000 +10 halt 5 3140000 +10 halt 6 3150000 +10 halt 7 3150000 +10 halt 8 3140000 +10 halt 9 3140000 +10 halt 10 3140000 +10 halt 11 3140000 +10 halt 12 3140000 +10 halt 13 3140000 +10 halt 14 3140000 +10 halt 15 3150000 +10 halt 16 3140000 +10 halt 17 3140000 +10 halt 18 3140000 +10 halt 19 3140000 +10 halt 20 3140000 +10 halt 21 3140000 +10 halt 22 3140000 +10 halt 23 3140000 +10 halt 24 3140000 +10 halt 25 3140000 +10 halt 26 3150000 +10 halt 27 3130000 +10 halt 28 3140000 +10 halt 29 3150000 +10 halt 30 3160000 +# point pass=10 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997935 +# done SystemTime { tv_sec: 1793972578, tv_nsec: 968782358 } +# passes used 10 of 10 (dropped: []) +# run - halt = 162.0 +/- 3.3 mW (per-pass sd 10.3); 10/10 passes positive; 4 sample excursions beyond 6 MAD +# per-pass differences (mW): 150.0 170.0 150.0 180.0 160.0 160.0 170.0 170.0 150.0 160.0 +# board power while running 3296 mW; jobs/s 12499736.4; updates/s 0.0; measured PL clock 99.998 MHz +# pre-registered prediction 160.0 mW: measured/predicted = 1.01, 0.6 sigma from it diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/first-attempt/campaign.txt b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/first-attempt/campaign.txt new file mode 100644 index 000000000..843938b08 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/first-attempt/campaign.txt @@ -0,0 +1,6 @@ +2026-11-06T08:01:41Z start; engine answers: ID and version 0x00404002; measured clock 99.997 MHz +2026-11-06T08:11:42Z step done +2026-11-06T08:35:54Z known answer done exit=0 +wai-quantum-fpga: another session is active on the board, not loading: +1670130 sudo KNOWN_ANSWER=/home/ubuntu/kv_runhalt.sh KNOWN_BITSTREAM=ev_rdet.bit.bin setsid nohup sh power_campaign.sh campaign-v2 +2026-11-06T08:35:55Z reload of the engine failed diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/first-attempt/known_answer.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/first-attempt/known_answer.dat new file mode 100644 index 000000000..3898f0bdc --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/first-attempt/known_answer.dat @@ -0,0 +1,483 @@ +# kv_runhalt bitstream=ev_rdet.bit.bin gpio=594 settle=60s passes=8 samples=30 +# pass vehicle sample power_uW +1 halt 1 3070000 +1 halt 2 3150000 +1 halt 3 3080000 +1 halt 4 3170000 +1 halt 5 3080000 +1 halt 6 3170000 +1 halt 7 3080000 +1 halt 8 3180000 +1 halt 9 3100000 +1 halt 10 3170000 +1 halt 11 3090000 +1 halt 12 3170000 +1 halt 13 3210000 +1 halt 14 3080000 +1 halt 15 3220000 +1 halt 16 3080000 +1 halt 17 3240000 +1 halt 18 3080000 +1 halt 19 3210000 +1 halt 20 3080000 +1 halt 21 3240000 +1 halt 22 3080000 +1 halt 23 3100000 +1 halt 24 3090000 +1 halt 25 3260000 +1 halt 26 3080000 +1 halt 27 3250000 +1 halt 28 3100000 +1 halt 29 3100000 +1 halt 30 3070000 +1 run 1 3170000 +1 run 2 3230000 +1 run 3 3150000 +1 run 4 3230000 +1 run 5 3150000 +1 run 6 3220000 +1 run 7 3150000 +1 run 8 3210000 +1 run 9 3150000 +1 run 10 3220000 +1 run 11 3150000 +1 run 12 3240000 +1 run 13 3150000 +1 run 14 3250000 +1 run 15 3150000 +1 run 16 3240000 +1 run 17 3150000 +1 run 18 3250000 +1 run 19 3150000 +1 run 20 3250000 +1 run 21 3150000 +1 run 22 3250000 +1 run 23 3150000 +1 run 24 3230000 +1 run 25 3150000 +1 run 26 3230000 +1 run 27 3150000 +1 run 28 3250000 +1 run 29 3150000 +1 run 30 3270000 +2 run 1 3170000 +2 run 2 3240000 +2 run 3 3160000 +2 run 4 3250000 +2 run 5 3160000 +2 run 6 3240000 +2 run 7 3170000 +2 run 8 3250000 +2 run 9 3160000 +2 run 10 3250000 +2 run 11 3150000 +2 run 12 3250000 +2 run 13 3160000 +2 run 14 3250000 +2 run 15 3160000 +2 run 16 3240000 +2 run 17 3160000 +2 run 18 3250000 +2 run 19 3160000 +2 run 20 3280000 +2 run 21 3180000 +2 run 22 3250000 +2 run 23 3160000 +2 run 24 3260000 +2 run 25 3160000 +2 run 26 3230000 +2 run 27 3160000 +2 run 28 3240000 +2 run 29 3150000 +2 run 30 3260000 +2 halt 1 3150000 +2 halt 2 3080000 +2 halt 3 3140000 +2 halt 4 3080000 +2 halt 5 3150000 +2 halt 6 3070000 +2 halt 7 3120000 +2 halt 8 3090000 +2 halt 9 3140000 +2 halt 10 3100000 +2 halt 11 3110000 +2 halt 12 3080000 +2 halt 13 3120000 +2 halt 14 3070000 +2 halt 15 3130000 +2 halt 16 3080000 +2 halt 17 3120000 +2 halt 18 3080000 +2 halt 19 3140000 +2 halt 20 3080000 +2 halt 21 3150000 +2 halt 22 3090000 +2 halt 23 3170000 +2 halt 24 3080000 +2 halt 25 3170000 +2 halt 26 3080000 +2 halt 27 3180000 +2 halt 28 3100000 +2 halt 29 3210000 +2 halt 30 3090000 +3 run 1 3150000 +3 run 2 3160000 +3 run 3 3150000 +3 run 4 3150000 +3 run 5 3150000 +3 run 6 3150000 +3 run 7 3160000 +3 run 8 3150000 +3 run 9 3150000 +3 run 10 3150000 +3 run 11 3150000 +3 run 12 3160000 +3 run 13 3150000 +3 run 14 3150000 +3 run 15 3160000 +3 run 16 3150000 +3 run 17 3150000 +3 run 18 3160000 +3 run 19 3150000 +3 run 20 3150000 +3 run 21 3150000 +3 run 22 3150000 +3 run 23 3170000 +3 run 24 3150000 +3 run 25 3160000 +3 run 26 3150000 +3 run 27 3150000 +3 run 28 3140000 +3 run 29 3180000 +3 run 30 3150000 +3 halt 1 3170000 +3 halt 2 3080000 +3 halt 3 3170000 +3 halt 4 3110000 +3 halt 5 3180000 +3 halt 6 3080000 +3 halt 7 3180000 +3 halt 8 3090000 +3 halt 9 3180000 +3 halt 10 3100000 +3 halt 11 3160000 +3 halt 12 3080000 +3 halt 13 3180000 +3 halt 14 3080000 +3 halt 15 3180000 +3 halt 16 3090000 +3 halt 17 3190000 +3 halt 18 3100000 +3 halt 19 3170000 +3 halt 20 3080000 +3 halt 21 3190000 +3 halt 22 3090000 +3 halt 23 3190000 +3 halt 24 3080000 +3 halt 25 3190000 +3 halt 26 3100000 +3 halt 27 3190000 +3 halt 28 3080000 +3 halt 29 3180000 +3 halt 30 3080000 +4 halt 1 3100000 +4 halt 2 3070000 +4 halt 3 3080000 +4 halt 4 3070000 +4 halt 5 3070000 +4 halt 6 3070000 +4 halt 7 3090000 +4 halt 8 3080000 +4 halt 9 3090000 +4 halt 10 3070000 +4 halt 11 3100000 +4 halt 12 3070000 +4 halt 13 3100000 +4 halt 14 3080000 +4 halt 15 3130000 +4 halt 16 3070000 +4 halt 17 3120000 +4 halt 18 3090000 +4 halt 19 3130000 +4 halt 20 3100000 +4 halt 21 3160000 +4 halt 22 3080000 +4 halt 23 3160000 +4 halt 24 3070000 +4 halt 25 3160000 +4 halt 26 3070000 +4 halt 27 3160000 +4 halt 28 3090000 +4 halt 29 3170000 +4 halt 30 3070000 +4 run 1 3150000 +4 run 2 3150000 +4 run 3 3160000 +4 run 4 3160000 +4 run 5 3150000 +4 run 6 3160000 +4 run 7 3150000 +4 run 8 3150000 +4 run 9 3150000 +4 run 10 3150000 +4 run 11 3150000 +4 run 12 3150000 +4 run 13 3150000 +4 run 14 3150000 +4 run 15 3150000 +4 run 16 3170000 +4 run 17 3160000 +4 run 18 3170000 +4 run 19 3160000 +4 run 20 3160000 +4 run 21 3140000 +4 run 22 3180000 +4 run 23 3150000 +4 run 24 3200000 +4 run 25 3150000 +4 run 26 3180000 +4 run 27 3150000 +4 run 28 3200000 +4 run 29 3140000 +4 run 30 3180000 +5 run 1 3240000 +5 run 2 3160000 +5 run 3 3240000 +5 run 4 3150000 +5 run 5 3230000 +5 run 6 3160000 +5 run 7 3260000 +5 run 8 3140000 +5 run 9 3220000 +5 run 10 3130000 +5 run 11 3240000 +5 run 12 3150000 +5 run 13 3230000 +5 run 14 3150000 +5 run 15 3250000 +5 run 16 3140000 +5 run 17 3230000 +5 run 18 3140000 +5 run 19 3220000 +5 run 20 3150000 +5 run 21 3220000 +5 run 22 3140000 +5 run 23 3140000 +5 run 24 3230000 +5 run 25 3160000 +5 run 26 3240000 +5 run 27 3140000 +5 run 28 3230000 +5 run 29 3140000 +5 run 30 3250000 +5 halt 1 3070000 +5 halt 2 3240000 +5 halt 3 3080000 +5 halt 4 3070000 +5 halt 5 3070000 +5 halt 6 3090000 +5 halt 7 3070000 +5 halt 8 3170000 +5 halt 9 3070000 +5 halt 10 3170000 +5 halt 11 3070000 +5 halt 12 3160000 +5 halt 13 3070000 +5 halt 14 3170000 +5 halt 15 3070000 +5 halt 16 3170000 +5 halt 17 3070000 +5 halt 18 3160000 +5 halt 19 3100000 +5 halt 20 3180000 +5 halt 21 3080000 +5 halt 22 3190000 +5 halt 23 3070000 +5 halt 24 3170000 +5 halt 25 3080000 +5 halt 26 3160000 +5 halt 27 3070000 +5 halt 28 3160000 +5 halt 29 3070000 +5 halt 30 3180000 +6 halt 1 3250000 +6 halt 2 3080000 +6 halt 3 3240000 +6 halt 4 3080000 +6 halt 5 3240000 +6 halt 6 3090000 +6 halt 7 3250000 +6 halt 8 3080000 +6 halt 9 3250000 +6 halt 10 3120000 +6 halt 11 3250000 +6 halt 12 3100000 +6 halt 13 3270000 +6 halt 14 3080000 +6 halt 15 3080000 +6 halt 16 3090000 +6 halt 17 3080000 +6 halt 18 3090000 +6 halt 19 3090000 +6 halt 20 3080000 +6 halt 21 3090000 +6 halt 22 3090000 +6 halt 23 3080000 +6 halt 24 3090000 +6 halt 25 3080000 +6 halt 26 3090000 +6 halt 27 3080000 +6 halt 28 3080000 +6 halt 29 3080000 +6 halt 30 3090000 +6 run 1 3160000 +6 run 2 3240000 +6 run 3 3150000 +6 run 4 3240000 +6 run 5 3140000 +6 run 6 3240000 +6 run 7 3250000 +6 run 8 3150000 +6 run 9 3250000 +6 run 10 3140000 +6 run 11 3250000 +6 run 12 3150000 +6 run 13 3150000 +6 run 14 3150000 +6 run 15 3160000 +6 run 16 3150000 +6 run 17 3150000 +6 run 18 3150000 +6 run 19 3150000 +6 run 20 3150000 +6 run 21 3170000 +6 run 22 3160000 +6 run 23 3160000 +6 run 24 3150000 +6 run 25 3140000 +6 run 26 3160000 +6 run 27 3140000 +6 run 28 3150000 +6 run 29 3150000 +6 run 30 3150000 +7 halt 1 3080000 +7 halt 2 3160000 +7 halt 3 3080000 +7 halt 4 3160000 +7 halt 5 3080000 +7 halt 6 3190000 +7 halt 7 3070000 +7 halt 8 3160000 +7 halt 9 3100000 +7 halt 10 3190000 +7 halt 11 3080000 +7 halt 12 3190000 +7 halt 13 3080000 +7 halt 14 3190000 +7 halt 15 3080000 +7 halt 16 3220000 +7 halt 17 3080000 +7 halt 18 3210000 +7 halt 19 3080000 +7 halt 20 3230000 +7 halt 21 3090000 +7 halt 22 3210000 +7 halt 23 3090000 +7 halt 24 3220000 +7 halt 25 3080000 +7 halt 26 3230000 +7 halt 27 3080000 +7 halt 28 3250000 +7 halt 29 3090000 +7 halt 30 3110000 +7 run 1 3190000 +7 run 2 3140000 +7 run 3 3170000 +7 run 4 3150000 +7 run 5 3190000 +7 run 6 3150000 +7 run 7 3180000 +7 run 8 3150000 +7 run 9 3180000 +7 run 10 3150000 +7 run 11 3190000 +7 run 12 3410000 +7 run 13 3190000 +7 run 14 3140000 +7 run 15 3190000 +7 run 16 3150000 +7 run 17 3220000 +7 run 18 3150000 +7 run 19 3230000 +7 run 20 3150000 +7 run 21 3210000 +7 run 22 3140000 +7 run 23 3220000 +7 run 24 3240000 +7 run 25 3150000 +7 run 26 3230000 +7 run 27 3140000 +7 run 28 3260000 +7 run 29 3150000 +7 run 30 3250000 +8 halt 1 3090000 +8 halt 2 3080000 +8 halt 3 3080000 +8 halt 4 3080000 +8 halt 5 3090000 +8 halt 6 3080000 +8 halt 7 3130000 +8 halt 8 3090000 +8 halt 9 3130000 +8 halt 10 3070000 +8 halt 11 3120000 +8 halt 12 3070000 +8 halt 13 3110000 +8 halt 14 3080000 +8 halt 15 3100000 +8 halt 16 3080000 +8 halt 17 3110000 +8 halt 18 3080000 +8 halt 19 3120000 +8 halt 20 3080000 +8 halt 21 3140000 +8 halt 22 3070000 +8 halt 23 3120000 +8 halt 24 3080000 +8 halt 25 3120000 +8 halt 26 3070000 +8 halt 27 3140000 +8 halt 28 3080000 +8 halt 29 3140000 +8 halt 30 3080000 +8 run 1 3290000 +8 run 2 3150000 +8 run 3 3270000 +8 run 4 3150000 +8 run 5 3260000 +8 run 6 3150000 +8 run 7 3290000 +8 run 8 3160000 +8 run 9 3270000 +8 run 10 3170000 +8 run 11 3280000 +8 run 12 3150000 +8 run 13 3300000 +8 run 14 3150000 +8 run 15 3290000 +8 run 16 3170000 +8 run 17 3320000 +8 run 18 3160000 +8 run 19 3270000 +8 run 20 3170000 +8 run 21 3270000 +8 run 22 3170000 +8 run 23 3280000 +8 run 24 3160000 +8 run 25 3280000 +8 run 26 3160000 +8 run 27 3410000 +8 run 28 3150000 +8 run 29 3170000 +8 run 30 3160000 +# done diff --git a/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/first-attempt/step.dat b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/first-attempt/step.dat new file mode 100644 index 000000000..122da6210 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/measurements/2026-11-06/first-attempt/step.dat @@ -0,0 +1,610 @@ +# class t0-recall cores 1 +# wai-quantum-fpga meter passes=1 settle=0s samples=300 null=false sensor=/sys/class/hwmon/hwmon2/power1_input started=SystemTime { tv_sec: 1793952101, tv_nsec: 820210424 } +# pass state sample power_uW +1 halt 1 3370000 +1 halt 2 3140000 +1 halt 3 3120000 +1 halt 4 3130000 +1 halt 5 3120000 +1 halt 6 3120000 +1 halt 7 3110000 +1 halt 8 3120000 +1 halt 9 3130000 +1 halt 10 3130000 +1 halt 11 3120000 +1 halt 12 3140000 +1 halt 13 3110000 +1 halt 14 3120000 +1 halt 15 3120000 +1 halt 16 3120000 +1 halt 17 3130000 +1 halt 18 3130000 +1 halt 19 3130000 +1 halt 20 3110000 +1 halt 21 3120000 +1 halt 22 3140000 +1 halt 23 3130000 +1 halt 24 3120000 +1 halt 25 3130000 +1 halt 26 3140000 +1 halt 27 3130000 +1 halt 28 3110000 +1 halt 29 3120000 +1 halt 30 3120000 +1 halt 31 3120000 +1 halt 32 3120000 +1 halt 33 3130000 +1 halt 34 3130000 +1 halt 35 3150000 +1 halt 36 3120000 +1 halt 37 3120000 +1 halt 38 3130000 +1 halt 39 3120000 +1 halt 40 3120000 +1 halt 41 3120000 +1 halt 42 3110000 +1 halt 43 3120000 +1 halt 44 3130000 +1 halt 45 3120000 +1 halt 46 3120000 +1 halt 47 3120000 +1 halt 48 3120000 +1 halt 49 3120000 +1 halt 50 3140000 +1 halt 51 3130000 +1 halt 52 3120000 +1 halt 53 3120000 +1 halt 54 3130000 +1 halt 55 3120000 +1 halt 56 3130000 +1 halt 57 3120000 +1 halt 58 3140000 +1 halt 59 3140000 +1 halt 60 3120000 +1 halt 61 3130000 +1 halt 62 3130000 +1 halt 63 3120000 +1 halt 64 3120000 +1 halt 65 3120000 +1 halt 66 3120000 +1 halt 67 3150000 +1 halt 68 3120000 +1 halt 69 3120000 +1 halt 70 3130000 +1 halt 71 3120000 +1 halt 72 3130000 +1 halt 73 3130000 +1 halt 74 3120000 +1 halt 75 3110000 +1 halt 76 3120000 +1 halt 77 3130000 +1 halt 78 3120000 +1 halt 79 3110000 +1 halt 80 3120000 +1 halt 81 3120000 +1 halt 82 3140000 +1 halt 83 3120000 +1 halt 84 3120000 +1 halt 85 3130000 +1 halt 86 3130000 +1 halt 87 3120000 +1 halt 88 3120000 +1 halt 89 3120000 +1 halt 90 3140000 +1 halt 91 3150000 +1 halt 92 3130000 +1 halt 93 3120000 +1 halt 94 3130000 +1 halt 95 3120000 +1 halt 96 3130000 +1 halt 97 3120000 +1 halt 98 3120000 +1 halt 99 3140000 +1 halt 100 3120000 +1 halt 101 3120000 +1 halt 102 3120000 +1 halt 103 3120000 +1 halt 104 3140000 +1 halt 105 3120000 +1 halt 106 3140000 +1 halt 107 3130000 +1 halt 108 3130000 +1 halt 109 3140000 +1 halt 110 3130000 +1 halt 111 3140000 +1 halt 112 3140000 +1 halt 113 3150000 +1 halt 114 3150000 +1 halt 115 3120000 +1 halt 116 3130000 +1 halt 117 3130000 +1 halt 118 3140000 +1 halt 119 3120000 +1 halt 120 3140000 +1 halt 121 3130000 +1 halt 122 3150000 +1 halt 123 3140000 +1 halt 124 3130000 +1 halt 125 3140000 +1 halt 126 3130000 +1 halt 127 3130000 +1 halt 128 3140000 +1 halt 129 3130000 +1 halt 130 3140000 +1 halt 131 3140000 +1 halt 132 3140000 +1 halt 133 3140000 +1 halt 134 3130000 +1 halt 135 3140000 +1 halt 136 3140000 +1 halt 137 3150000 +1 halt 138 3140000 +1 halt 139 3130000 +1 halt 140 3130000 +1 halt 141 3150000 +1 halt 142 3130000 +1 halt 143 3140000 +1 halt 144 3130000 +1 halt 145 3150000 +1 halt 146 3150000 +1 halt 147 3130000 +1 halt 148 3130000 +1 halt 149 3160000 +1 halt 150 3130000 +1 halt 151 3120000 +1 halt 152 3130000 +1 halt 153 3140000 +1 halt 154 3150000 +1 halt 155 3130000 +1 halt 156 3140000 +1 halt 157 3130000 +1 halt 158 3130000 +1 halt 159 3140000 +1 halt 160 3140000 +1 halt 161 3140000 +1 halt 162 3140000 +1 halt 163 3130000 +1 halt 164 3140000 +1 halt 165 3150000 +1 halt 166 3140000 +1 halt 167 3130000 +1 halt 168 3140000 +1 halt 169 3150000 +1 halt 170 3140000 +1 halt 171 3140000 +1 halt 172 3130000 +1 halt 173 3150000 +1 halt 174 3140000 +1 halt 175 3130000 +1 halt 176 3130000 +1 halt 177 3150000 +1 halt 178 3140000 +1 halt 179 3140000 +1 halt 180 3120000 +1 halt 181 3140000 +1 halt 182 3140000 +1 halt 183 3140000 +1 halt 184 3140000 +1 halt 185 3140000 +1 halt 186 3140000 +1 halt 187 3120000 +1 halt 188 3130000 +1 halt 189 3140000 +1 halt 190 3130000 +1 halt 191 3150000 +1 halt 192 3150000 +1 halt 193 3140000 +1 halt 194 3140000 +1 halt 195 3140000 +1 halt 196 3140000 +1 halt 197 3140000 +1 halt 198 3120000 +1 halt 199 3140000 +1 halt 200 3150000 +1 halt 201 3150000 +1 halt 202 3140000 +1 halt 203 3150000 +1 halt 204 3140000 +1 halt 205 3140000 +1 halt 206 3140000 +1 halt 207 3140000 +1 halt 208 3140000 +1 halt 209 3150000 +1 halt 210 3130000 +1 halt 211 3140000 +1 halt 212 3130000 +1 halt 213 3140000 +1 halt 214 3140000 +1 halt 215 3140000 +1 halt 216 3130000 +1 halt 217 3130000 +1 halt 218 3120000 +1 halt 219 3140000 +1 halt 220 3130000 +1 halt 221 3140000 +1 halt 222 3140000 +1 halt 223 3130000 +1 halt 224 3140000 +1 halt 225 3140000 +1 halt 226 3130000 +1 halt 227 3130000 +1 halt 228 3150000 +1 halt 229 3130000 +1 halt 230 3130000 +1 halt 231 3130000 +1 halt 232 3150000 +1 halt 233 3140000 +1 halt 234 3120000 +1 halt 235 3130000 +1 halt 236 3130000 +1 halt 237 3120000 +1 halt 238 3140000 +1 halt 239 3120000 +1 halt 240 3130000 +1 halt 241 3130000 +1 halt 242 3120000 +1 halt 243 3260000 +1 halt 244 3120000 +1 halt 245 3130000 +1 halt 246 3130000 +1 halt 247 3120000 +1 halt 248 3500000 +1 halt 249 3130000 +1 halt 250 3130000 +1 halt 251 3120000 +1 halt 252 3120000 +1 halt 253 3120000 +1 halt 254 3140000 +1 halt 255 3140000 +1 halt 256 3140000 +1 halt 257 3120000 +1 halt 258 3120000 +1 halt 259 3120000 +1 halt 260 3120000 +1 halt 261 3110000 +1 halt 262 3120000 +1 halt 263 3120000 +1 halt 264 3140000 +1 halt 265 3120000 +1 halt 266 3120000 +1 halt 267 3130000 +1 halt 268 3130000 +1 halt 269 3130000 +1 halt 270 3120000 +1 halt 271 3120000 +1 halt 272 3120000 +1 halt 273 3120000 +1 halt 274 3120000 +1 halt 275 3120000 +1 halt 276 3120000 +1 halt 277 3120000 +1 halt 278 3140000 +1 halt 279 3150000 +1 halt 280 3120000 +1 halt 281 3120000 +1 halt 282 3120000 +1 halt 283 3130000 +1 halt 284 3130000 +1 halt 285 3120000 +1 halt 286 3130000 +1 halt 287 3140000 +1 halt 288 3140000 +1 halt 289 3120000 +1 halt 290 3130000 +1 halt 291 3120000 +1 halt 292 3120000 +1 halt 293 3120000 +1 halt 294 3120000 +1 halt 295 3120000 +1 halt 296 3140000 +1 halt 297 3120000 +1 halt 298 3120000 +1 halt 299 3130000 +1 halt 300 3120000 +# point pass=1 state=halt jobs_per_s=0.0 updates_per_s=0.0 clock_hz=99997998 +1 run 1 3520000 +1 run 2 3310000 +1 run 3 3300000 +1 run 4 3280000 +1 run 5 3290000 +1 run 6 3290000 +1 run 7 3290000 +1 run 8 3290000 +1 run 9 3290000 +1 run 10 3300000 +1 run 11 3290000 +1 run 12 3290000 +1 run 13 3290000 +1 run 14 3290000 +1 run 15 3290000 +1 run 16 3280000 +1 run 17 3290000 +1 run 18 3290000 +1 run 19 3290000 +1 run 20 3280000 +1 run 21 3300000 +1 run 22 3290000 +1 run 23 3280000 +1 run 24 3290000 +1 run 25 3310000 +1 run 26 3290000 +1 run 27 3290000 +1 run 28 3290000 +1 run 29 3290000 +1 run 30 3290000 +1 run 31 3290000 +1 run 32 3290000 +1 run 33 3300000 +1 run 34 3300000 +1 run 35 3290000 +1 run 36 3290000 +1 run 37 3300000 +1 run 38 3290000 +1 run 39 3290000 +1 run 40 3280000 +1 run 41 3280000 +1 run 42 3310000 +1 run 43 3290000 +1 run 44 3280000 +1 run 45 3300000 +1 run 46 3290000 +1 run 47 3290000 +1 run 48 3290000 +1 run 49 3290000 +1 run 50 3290000 +1 run 51 3290000 +1 run 52 3290000 +1 run 53 3290000 +1 run 54 3290000 +1 run 55 3290000 +1 run 56 3290000 +1 run 57 3300000 +1 run 58 3290000 +1 run 59 3290000 +1 run 60 3290000 +1 run 61 3300000 +1 run 62 3290000 +1 run 63 3290000 +1 run 64 3290000 +1 run 65 3320000 +1 run 66 3300000 +1 run 67 3290000 +1 run 68 3290000 +1 run 69 3290000 +1 run 70 3290000 +1 run 71 3280000 +1 run 72 3290000 +1 run 73 3290000 +1 run 74 3310000 +1 run 75 3300000 +1 run 76 3290000 +1 run 77 3290000 +1 run 78 3290000 +1 run 79 3290000 +1 run 80 3290000 +1 run 81 3290000 +1 run 82 3290000 +1 run 83 3290000 +1 run 84 3290000 +1 run 85 3290000 +1 run 86 3290000 +1 run 87 3290000 +1 run 88 3290000 +1 run 89 3300000 +1 run 90 3300000 +1 run 91 3290000 +1 run 92 3290000 +1 run 93 3290000 +1 run 94 3290000 +1 run 95 3290000 +1 run 96 3290000 +1 run 97 3310000 +1 run 98 3290000 +1 run 99 3290000 +1 run 100 3290000 +1 run 101 3290000 +1 run 102 3280000 +1 run 103 3300000 +1 run 104 3290000 +1 run 105 3290000 +1 run 106 3290000 +1 run 107 3290000 +1 run 108 3290000 +1 run 109 3290000 +1 run 110 3290000 +1 run 111 3290000 +1 run 112 3300000 +1 run 113 3290000 +1 run 114 3290000 +1 run 115 3290000 +1 run 116 3290000 +1 run 117 3290000 +1 run 118 3290000 +1 run 119 3290000 +1 run 120 3310000 +1 run 121 3310000 +1 run 122 3300000 +1 run 123 3290000 +1 run 124 3290000 +1 run 125 3290000 +1 run 126 3290000 +1 run 127 3290000 +1 run 128 3290000 +1 run 129 3310000 +1 run 130 3290000 +1 run 131 3290000 +1 run 132 3300000 +1 run 133 3290000 +1 run 134 3290000 +1 run 135 3290000 +1 run 136 3290000 +1 run 137 3290000 +1 run 138 3290000 +1 run 139 3290000 +1 run 140 3300000 +1 run 141 3290000 +1 run 142 3290000 +1 run 143 3290000 +1 run 144 3310000 +1 run 145 3290000 +1 run 146 3300000 +1 run 147 3290000 +1 run 148 3300000 +1 run 149 3290000 +1 run 150 3290000 +1 run 151 3290000 +1 run 152 3310000 +1 run 153 3300000 +1 run 154 3300000 +1 run 155 3300000 +1 run 156 3280000 +1 run 157 3280000 +1 run 158 3290000 +1 run 159 3290000 +1 run 160 3290000 +1 run 161 3290000 +1 run 162 3290000 +1 run 163 3290000 +1 run 164 3290000 +1 run 165 3290000 +1 run 166 3290000 +1 run 167 3290000 +1 run 168 3300000 +1 run 169 3290000 +1 run 170 3290000 +1 run 171 3290000 +1 run 172 3290000 +1 run 173 3290000 +1 run 174 3300000 +1 run 175 3320000 +1 run 176 3320000 +1 run 177 3310000 +1 run 178 3290000 +1 run 179 3300000 +1 run 180 3300000 +1 run 181 3300000 +1 run 182 3300000 +1 run 183 3310000 +1 run 184 3320000 +1 run 185 3290000 +1 run 186 3300000 +1 run 187 3310000 +1 run 188 3300000 +1 run 189 3300000 +1 run 190 3310000 +1 run 191 3300000 +1 run 192 3300000 +1 run 193 3300000 +1 run 194 3300000 +1 run 195 3300000 +1 run 196 3290000 +1 run 197 3300000 +1 run 198 3300000 +1 run 199 3320000 +1 run 200 3300000 +1 run 201 3300000 +1 run 202 3300000 +1 run 203 3290000 +1 run 204 3300000 +1 run 205 3300000 +1 run 206 3300000 +1 run 207 3320000 +1 run 208 3320000 +1 run 209 3300000 +1 run 210 3300000 +1 run 211 3310000 +1 run 212 3300000 +1 run 213 3300000 +1 run 214 3300000 +1 run 215 3310000 +1 run 216 3320000 +1 run 217 3300000 +1 run 218 3300000 +1 run 219 3310000 +1 run 220 3300000 +1 run 221 3300000 +1 run 222 3300000 +1 run 223 3300000 +1 run 224 3300000 +1 run 225 3300000 +1 run 226 3300000 +1 run 227 3300000 +1 run 228 3290000 +1 run 229 3290000 +1 run 230 3300000 +1 run 231 3320000 +1 run 232 3290000 +1 run 233 3300000 +1 run 234 3310000 +1 run 235 3300000 +1 run 236 3290000 +1 run 237 3290000 +1 run 238 3290000 +1 run 239 3300000 +1 run 240 3290000 +1 run 241 3290000 +1 run 242 3290000 +1 run 243 3290000 +1 run 244 3290000 +1 run 245 3290000 +1 run 246 3300000 +1 run 247 3290000 +1 run 248 3300000 +1 run 249 3290000 +1 run 250 3290000 +1 run 251 3290000 +1 run 252 3290000 +1 run 253 3290000 +1 run 254 3320000 +1 run 255 3290000 +1 run 256 3300000 +1 run 257 3290000 +1 run 258 3290000 +1 run 259 3290000 +1 run 260 3290000 +1 run 261 3290000 +1 run 262 3310000 +1 run 263 3300000 +1 run 264 3310000 +1 run 265 3290000 +1 run 266 3290000 +1 run 267 3300000 +1 run 268 3290000 +1 run 269 3290000 +1 run 270 3290000 +1 run 271 3310000 +1 run 272 3280000 +1 run 273 3290000 +1 run 274 3300000 +1 run 275 3290000 +1 run 276 3290000 +1 run 277 3290000 +1 run 278 3280000 +1 run 279 3310000 +1 run 280 3290000 +1 run 281 3300000 +1 run 282 3290000 +1 run 283 3290000 +1 run 284 3720000 +1 run 285 3300000 +1 run 286 3300000 +1 run 287 3290000 +1 run 288 3290000 +1 run 289 3410000 +1 run 290 3290000 +1 run 291 3290000 +1 run 292 3290000 +1 run 293 3290000 +1 run 294 3310000 +1 run 295 3310000 +1 run 296 3280000 +1 run 297 3290000 +1 run 298 3300000 +1 run 299 3290000 +1 run 300 3290000 +# point pass=1 state=run jobs_per_s=12499745.5 updates_per_s=0.0 clock_hz=99997962 +# done SystemTime { tv_sec: 1793952702, tv_nsec: 236216766 } +# passes used 1 of 1 (dropped: []) +# run - halt = 160.0 +/- NaN mW (per-pass sd NaN); 1/1 passes positive; 6 sample excursions beyond 6 MAD +# per-pass differences (mW): 160.0 +# board power while running 3290 mW; jobs/s 12499745.5; updates/s 0.0; measured PL clock 99.998 MHz diff --git a/wai/wai-quantum-landscape-fpga/rtl/landscape.xdc b/wai/wai-quantum-landscape-fpga/rtl/landscape.xdc new file mode 100644 index 000000000..278a48e52 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/rtl/landscape.xdc @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 +# The EMIO lines cross from the PS's bus clock into pl_clk0. req is synchronised in landscape_port.v; addr, +# we and wdata are stable before req is seen; rdata is stable before ack toggles. +set_false_path -to [get_cells -hierarchical -filter {NAME =~ *req_s1_reg*}] +set_false_path -through [get_pins -hierarchical -filter {NAME =~ *PS8_i/EMIOGPIOO*}] +set_false_path -through [get_pins -hierarchical -filter {NAME =~ *PS8_i/EMIOGPIOI*}] diff --git a/wai/wai-quantum-landscape-fpga/rtl/landscape_axi.v b/wai/wai-quantum-landscape-fpga/rtl/landscape_axi.v new file mode 100644 index 000000000..f4328d9b9 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/rtl/landscape_axi.v @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: Apache-2.0 +// The engine's link to the processor: an AXI-Lite register port, a write-list DMA from DDR, and a +// chain sequencer that runs a batch of chains in fabric. +// +// AXI-Lite (from the processor's full-power-domain master, through a width and a protocol +// converter): word address = byte address >> 2. Words 0x0000-0x7FFF are the engine's own map (src/regs.rs); +// 0x8000 and up are this wrapper's (src/axi.rs). Every access is answered within a few clocks, +// whatever the engine, the DMA or the sequencer is doing: an access that never completes would +// hold the processor's bus, and on a shared, remote board nobody is there to power-cycle it. So +// an engine-map access while the DMA or the sequencer holds the engine's bus is not queued: a +// write is dropped, a read returns 0xDEADBEEF, and either counts in DROPS, which the host checks. +// +// Write-list DMA (an AXI4 read master, through a width converter, into the processor's +// high-performance port): the host puts +// a list of 64-bit entries in DDR, {16'b0, addr[15:0], data[31:0]}, and the wrapper applies each +// as a register write, in order, one every two clocks (the engine needs a clock between a +// coupling-memory clear and the next write). An entry for the chain RAM (0x9000-0x97FF) is +// written there. The list must start on a 128-byte boundary and not cross a 4 KiB page: bursts +// are 16 beats of 8 bytes. A read error stops the applying (DMA_ERR) but the list is still +// drained, so DMA_BUSY always falls. +// +// Chain sequencer: for k in 0..SEQ_COUNT (at most 256), it writes chain k's six words from the +// chain RAM (BOUNDARY 0-3, X0_LO, X0_HI) into the engine, starts the job, waits for it, and copies +// STATE 0-3, STEPS and STATUS into the result RAM (0xA000 + 8k). The job's mode, bound, table and +// workload are what the host set before. The anneal loop runs in fabric; the processor only fills +// the chain RAM and collects the results. +// +// Result write-back (an AXI4 write master on the same port): WB_CHAINS chains of the result RAM from +// WB_FIRST, 32 bytes a chain (its eight words), go to DDR at WB_LO/HI in bursts of 16 beats, one +// burst outstanding. The address must be on a 128-byte boundary and the chains must not cross a 4 KiB +// page, 128 chains a page. A write error is held in WB_ERR; every burst is still sent. +// +// EMIO: eight input lines carry a constant signature (0xA5) that the host reads through the +// processor's GPIO controller before it touches an AXI address: a GPIO read cannot hang the bus, +// so a design replaced by another session's is caught before an AXI access could go unanswered. +`timescale 1ns/1ps +`default_nettype none + +module landscape_axi ( + input wire clk, + input wire rstn, + // AXI4-Lite slave + input wire [31:0] s_awaddr, + input wire s_awvalid, + output reg s_awready = 1'b0, + input wire [31:0] s_wdata, + input wire s_wvalid, + output reg s_wready = 1'b0, + output wire [1:0] s_bresp, + output reg s_bvalid = 1'b0, + input wire s_bready, + input wire [31:0] s_araddr, + input wire s_arvalid, + output reg s_arready = 1'b0, + output reg [31:0] s_rdata = 32'd0, + output wire [1:0] s_rresp, + output reg s_rvalid = 1'b0, + input wire s_rready, + // AXI4 read master (64-bit data) + output reg [48:0] m_araddr = 49'd0, + output wire [7:0] m_arlen, + output wire [2:0] m_arsize, + output wire [1:0] m_arburst, + output wire [3:0] m_arcache, + output wire [2:0] m_arprot, + output reg m_arvalid = 1'b0, + input wire m_arready, + input wire [63:0] m_rdata, + input wire [1:0] m_rresp, + input wire m_rlast, + input wire m_rvalid, + output wire m_rready, + // AXI4 write master (64-bit data) + output reg [48:0] m_awaddr = 49'd0, + output reg [7:0] m_awlen = 8'd0, + output wire [2:0] m_awsize, + output wire [1:0] m_awburst, + output wire [3:0] m_awcache, + output wire [2:0] m_awprot, + output reg m_awvalid = 1'b0, + input wire m_awready, + output reg [63:0] m_wdata = 64'd0, + output wire [7:0] m_wstrb, + output reg m_wlast = 1'b0, + output reg m_wvalid = 1'b0, + input wire m_wready, + input wire [1:0] m_bresp, + input wire m_bvalid, + output wire m_bready, + // EMIO signature + output wire [94:0] emio_i +); + localparam [31:0] LAXI = 32'h4C41_5849; // "LAXI" + localparam [31:0] WRAP_VERSION = 32'h0000_0002; + assign s_bresp = 2'b00; + assign s_rresp = 2'b00; + assign emio_i = {87'd0, 8'hA5}; + + // ---- the engine's register bus ------------------------------------------------------------ + reg stb = 1'b0, we = 1'b0; + reg [15:0] addr = 16'd0; + reg [31:0] wdata = 32'd0; + wire [31:0] rdata; + wire busy, done; + landscape_core core (.clk(clk), .reg_stb(stb), .reg_we(we), .reg_addr(addr), .reg_wdata(wdata), + .reg_rdata(rdata), .busy_o(busy), .done_o(done)); + + // ---- wrapper state ------------------------------------------------------------------------ + reg [31:0] dma_lo = 32'd0, dma_hi = 32'd0, dma_count = 32'd0; + reg [31:0] dma_left = 32'd0, dma_reqs = 32'd0; // entries still to receive, to request + reg dma_busy = 1'b0, dma_err = 1'b0; + reg [31:0] dma_done_count = 32'd0, drops = 32'd0; + reg [8:0] seq_count = 9'd0; + reg [15:0] seq_k = 16'd0, seq_done_count = 16'd0; + reg seq_busy = 1'b0; + reg [3:0] seq_ph = 4'd0; + reg [2:0] seq_i = 3'd0; + reg [3:0] seq_wait = 4'd0; + wire bus_free = !dma_busy && !seq_busy; + reg [31:0] wb_lo = 32'd0, wb_hi = 32'd0, wb_done_count = 32'd0; + reg [7:0] wb_first = 8'd0; + reg [8:0] wb_chains = 9'd0; + reg wb_busy = 1'b0, wb_err = 1'b0; + reg [2:0] wb_ph = 3'd0; // 0 address, 1-2 the two words of a beat, 3 data, 4 response + reg [10:0] wb_ra = 11'd0; // the result RAM word being fetched + reg [10:0] wb_beats = 11'd0; // beats still to send + reg [4:0] wb_left = 5'd0; // beats left in this burst + reg [31:0] wb_word = 32'd0; + + // ---- the chain RAM and the result RAM: 256 chains x 8 words each, one write port each ------- + reg [31:0] chain_ram [0:2047]; + reg [31:0] res_ram [0:2047]; + reg cr_we = 1'b0, rr_we = 1'b0; + reg [10:0] cr_wa = 11'd0, rr_wa = 11'd0; + reg [31:0] cr_wd = 32'd0, rr_wd = 32'd0; + reg [31:0] chain_q = 32'd0, res_q = 32'd0; + reg [15:0] ar_word = 16'd0; + always @(posedge clk) begin + if (cr_we) chain_ram[cr_wa] <= cr_wd; + chain_q <= chain_ram[{seq_k[7:0], seq_i}]; + end + always @(posedge clk) begin + if (rr_we) res_ram[rr_wa] <= rr_wd; + res_q <= res_ram[wb_busy ? wb_ra : ar_word[10:0]]; + end + + // ---- AXI-Lite capture --------------------------------------------------------------------- + reg aw_have = 1'b0, w_have = 1'b0, ar_have = 1'b0; + reg [15:0] aw_word = 16'd0; + reg [31:0] w_val = 32'd0; + reg [2:0] host_ph = 3'd0; // 0 idle, 2 engine read issued, 3 engine data next, 4 wrapper data, 5 result RAM data + reg [31:0] wrap_rdata = 32'd0; + + // ---- the DMA's read master ---------------------------------------------------------------- + assign m_arsize = 3'd3; // 8 bytes a beat + assign m_arburst = 2'b01; // INCR + assign m_arcache = 4'b0011; // normal, bufferable, not coherent: the host cleans the list to DDR + assign m_arprot = 3'b000; + reg [7:0] burst_len = 8'd0; + assign m_arlen = burst_len; + reg ent_have = 1'b0; // an entry waiting to be applied, on the next clock + reg [63:0] ent = 64'd0; + assign m_rready = !ent_have; + + // ---- the write-back's write master --------------------------------------------------------- + assign m_awsize = 3'd3; + assign m_awburst = 2'b01; + assign m_awcache = 4'b0011; + assign m_awprot = 3'b000; + assign m_wstrb = 8'hFF; + assign m_bready = 1'b1; + + always @(posedge clk) begin + stb <= 1'b0; + we <= 1'b0; + cr_we <= 1'b0; + rr_we <= 1'b0; + s_awready <= 1'b0; s_wready <= 1'b0; s_arready <= 1'b0; + if (!rstn) begin + dma_busy <= 1'b0; seq_busy <= 1'b0; m_arvalid <= 1'b0; ent_have <= 1'b0; + wb_busy <= 1'b0; m_awvalid <= 1'b0; m_wvalid <= 1'b0; + s_bvalid <= 1'b0; s_rvalid <= 1'b0; aw_have <= 1'b0; w_have <= 1'b0; ar_have <= 1'b0; host_ph <= 3'd0; + end else begin + // capture the host's access: an address and its data, or a read address + if (s_awvalid && !aw_have && !s_awready) begin s_awready <= 1'b1; aw_have <= 1'b1; aw_word <= s_awaddr[17:2]; end + if (s_wvalid && !w_have && !s_wready) begin s_wready <= 1'b1; w_have <= 1'b1; w_val <= s_wdata; end + if (s_arvalid && !ar_have && !s_arready && host_ph == 3'd0) begin s_arready <= 1'b1; ar_have <= 1'b1; ar_word <= s_araddr[17:2]; end + if (s_bvalid && s_bready) s_bvalid <= 1'b0; + if (s_rvalid && s_rready) s_rvalid <= 1'b0; + + // ---- the DMA: requests, beats, entries ---- + if (dma_busy && !m_arvalid && dma_reqs != 32'd0) begin + burst_len <= (dma_reqs > 32'd16) ? 8'd15 : dma_reqs[7:0] - 8'd1; + m_arvalid <= 1'b1; + end else if (m_arvalid && m_arready) begin + m_arvalid <= 1'b0; + m_araddr <= m_araddr + ({41'd0, burst_len} + 49'd1) * 49'd8; + dma_reqs <= dma_reqs - ({24'd0, burst_len} + 32'd1); + end + if (m_rvalid && m_rready) begin + dma_left <= dma_left - 32'd1; + if (m_rresp != 2'b00) dma_err <= 1'b1; + else if (!dma_err) begin ent <= m_rdata; ent_have <= 1'b1; end + end + if (dma_busy && dma_left == 32'd0 && dma_reqs == 32'd0 && !m_arvalid && !ent_have) begin + dma_busy <= 1'b0; + dma_done_count <= dma_done_count + 32'd1; + end + + if (ent_have) begin + ent_have <= 1'b0; + if (ent[47:32] < 16'h8000) begin + stb <= 1'b1; we <= 1'b1; addr <= ent[47:32]; wdata <= ent[31:0]; + end else if (ent[47:32] >= 16'h9000 && ent[47:32] < 16'h9800) begin + cr_we <= 1'b1; cr_wa <= ent[42:32]; cr_wd <= ent[31:0]; + end + end else if (seq_busy) begin + // per chain: six writes, a start, a wait, six reads into the result RAM + case (seq_ph) + 4'd0: seq_ph <= 4'd1; // chain_q follows {seq_k, seq_i} + 4'd1: begin + stb <= 1'b1; we <= 1'b1; wdata <= chain_q; + addr <= (seq_i < 3'd4) ? (16'h0100 + {13'd0, seq_i}) : (16'h0010 + {13'd0, seq_i - 3'd4}); + if (seq_i == 3'd5) begin seq_i <= 3'd0; seq_ph <= 4'd2; end + else begin seq_i <= seq_i + 3'd1; seq_ph <= 4'd0; end + end + 4'd2: begin stb <= 1'b1; we <= 1'b1; addr <= 16'h0003; wdata <= 32'd1; seq_wait <= 4'd3; seq_ph <= 4'd3; end + 4'd3: begin + if (seq_wait != 4'd0) seq_wait <= seq_wait - 4'd1; + else if (!busy) begin seq_i <= 3'd0; seq_ph <= 4'd4; end + end + 4'd4: begin + stb <= 1'b1; we <= 1'b0; + addr <= (seq_i < 3'd4) ? (16'h0110 + {13'd0, seq_i}) : ((seq_i == 3'd4) ? 16'h0028 : 16'h0002); + seq_ph <= 4'd5; + end + 4'd5: seq_ph <= 4'd6; // the engine registers its read data on the clock after stb + 4'd6: begin + rr_we <= 1'b1; rr_wa <= {seq_k[7:0], seq_i}; rr_wd <= rdata; + if (seq_i == 3'd5) begin + seq_i <= 3'd0; + seq_done_count <= seq_done_count + 16'd1; + if (seq_k + 16'd1 == {7'd0, seq_count}) seq_busy <= 1'b0; + seq_k <= seq_k + 16'd1; + seq_ph <= 4'd0; + end else begin seq_i <= seq_i + 3'd1; seq_ph <= 4'd4; end + end + default: seq_ph <= 4'd0; + endcase + end + + // ---- the write-back: per burst an address, then per beat two words, then the response ---- + if (wb_busy) begin + case (wb_ph) + 3'd0: begin + if (!m_awvalid) begin + m_awvalid <= 1'b1; + m_awlen <= (wb_beats > 11'd16) ? 8'd15 : wb_beats[7:0] - 8'd1; + wb_left <= (wb_beats > 11'd16) ? 5'd16 : wb_beats[4:0]; + end else if (m_awready) begin + m_awvalid <= 1'b0; + m_awaddr <= m_awaddr + ({41'd0, m_awlen} + 49'd1) * 49'd8; + wb_ph <= 3'd1; + end + end + 3'd1: begin wb_ra <= wb_ra + 11'd1; wb_ph <= 3'd2; end // res_q follows wb_ra + 3'd2: begin wb_word <= res_q; wb_ph <= 3'd5; end + 3'd5: begin // the high word's turn + m_wdata <= {res_q, wb_word}; + m_wvalid <= 1'b1; + m_wlast <= (wb_left == 5'd1); + wb_ra <= wb_ra + 11'd1; + wb_ph <= 3'd3; + end + 3'd3: if (m_wready) begin + m_wvalid <= 1'b0; + wb_left <= wb_left - 5'd1; + wb_beats <= wb_beats - 11'd1; + wb_ph <= (wb_left == 5'd1) ? 3'd4 : 3'd1; + end + 3'd4: if (m_bvalid) begin + if (m_bresp != 2'b00) wb_err <= 1'b1; + if (wb_beats == 11'd0) begin + wb_busy <= 1'b0; + wb_done_count <= wb_done_count + 32'd1; + end + wb_ph <= 3'd0; + end + default: wb_ph <= 3'd0; + endcase + end + + // ---- the host ---- + if (aw_have && w_have && host_ph == 3'd0 && !s_bvalid && !ent_have) begin + if (aw_word < 16'h8000) begin + if (bus_free) begin stb <= 1'b1; we <= 1'b1; addr <= aw_word; wdata <= w_val; end + else drops <= drops + 32'd1; + end else begin + case (aw_word) + 16'h8002: dma_lo <= w_val; + 16'h8003: dma_hi <= w_val; + 16'h8004: dma_count <= w_val; + 16'h8005: if (bus_free && dma_count != 32'd0) begin + dma_busy <= 1'b1; dma_err <= 1'b0; dma_left <= dma_count; dma_reqs <= dma_count; + m_araddr <= {dma_hi[16:0], dma_lo}; + end + 16'h8008: drops <= 32'd0; + 16'h8010: seq_count <= (w_val > 32'd256) ? 9'd256 : w_val[8:0]; + 16'h8011: if (bus_free && !wb_busy && seq_count != 9'd0) begin + seq_busy <= 1'b1; seq_k <= 16'd0; seq_ph <= 4'd0; seq_i <= 3'd0; + end + 16'h8020: wb_lo <= w_val; + 16'h8021: wb_hi <= w_val; + 16'h8022: wb_first <= w_val[7:0]; + 16'h8023: wb_chains <= (w_val > 32'd256) ? 9'd256 : w_val[8:0]; + 16'h8024: if (bus_free && !wb_busy && wb_chains != 9'd0) begin + wb_busy <= 1'b1; wb_err <= 1'b0; wb_ph <= 3'd0; + wb_ra <= {wb_first, 3'd0}; + wb_beats <= {wb_chains, 2'b00}; + m_awaddr <= {wb_hi[16:0], wb_lo}; + end + 16'h8013: if (seq_busy) begin + // abandon the batch and stop the engine's job + seq_busy <= 1'b0; + stb <= 1'b1; we <= 1'b1; addr <= 16'h0003; wdata <= 32'd4; + end + default: if (aw_word >= 16'h9000 && aw_word < 16'h9800) begin + cr_we <= 1'b1; cr_wa <= aw_word[10:0]; cr_wd <= w_val; + end + endcase + end + aw_have <= 1'b0; w_have <= 1'b0; s_bvalid <= 1'b1; + end else if (ar_have && host_ph == 3'd0 && !s_rvalid) begin + if (ar_word < 16'h8000) begin + if (bus_free) begin stb <= 1'b1; we <= 1'b0; addr <= ar_word; host_ph <= 3'd2; end + else begin drops <= drops + 32'd1; wrap_rdata <= 32'hDEAD_BEEF; host_ph <= 3'd4; end + end else begin + case (ar_word) + 16'h8000: wrap_rdata <= LAXI; + 16'h8001: wrap_rdata <= {27'd0, wb_err, wb_busy, dma_err, dma_busy, seq_busy}; + 16'h8002: wrap_rdata <= dma_lo; + 16'h8003: wrap_rdata <= dma_hi; + 16'h8004: wrap_rdata <= dma_count; + 16'h8006: wrap_rdata <= dma_done_count; + 16'h8007: wrap_rdata <= dma_left; + 16'h8008: wrap_rdata <= drops; + 16'h8009: wrap_rdata <= WRAP_VERSION; + 16'h8010: wrap_rdata <= {23'd0, seq_count}; + 16'h8012: wrap_rdata <= {16'd0, seq_done_count}; + 16'h8025: wrap_rdata <= wb_done_count; + default: wrap_rdata <= 32'hDEAD_BEEF; + endcase + host_ph <= (ar_word >= 16'hA000 && ar_word < 16'hA800) ? 3'd5 : 3'd4; + end + end + if (host_ph == 3'd2) host_ph <= 3'd3; + else if (host_ph == 3'd3) begin s_rdata <= rdata; s_rvalid <= 1'b1; ar_have <= 1'b0; host_ph <= 3'd0; end + else if (host_ph == 3'd4) begin s_rdata <= wrap_rdata; s_rvalid <= 1'b1; ar_have <= 1'b0; host_ph <= 3'd0; end + else if (host_ph == 3'd5) begin s_rdata <= res_q; s_rvalid <= 1'b1; ar_have <= 1'b0; host_ph <= 3'd0; end + end + end +endmodule + +`default_nettype wire diff --git a/wai/wai-quantum-landscape-fpga/rtl/landscape_core.v b/wai/wai-quantum-landscape-fpga/rtl/landscape_core.v new file mode 100644 index 000000000..b70f989e5 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/rtl/landscape_core.v @@ -0,0 +1,457 @@ +// SPDX-License-Identifier: Apache-2.0 +// Energy-landscape engine: the two kernels of wai.quantum.landscape/1 (extensions/quantum-landscape.md +// section 4) for up to 64 cells, in programmable logic. A classical design: three-state cells, a +// counter-based random stream, no quantum effect. +// +// One field cone per cell computes h_i = b_i + sum_j W_ij s_j from the current state, every clock. +// The couplings W (ternary), the fields b and the cost c are registers the host writes. +// +// MODE 0 T0 every cell at once to threshold(h, c): the settle kernel, section 4.1. One sweep +// per clock; it stops at a fixed point, a two-cycle or the bound. +// MODE 1 GIBBS one cell at a time, in order, each drawn given the cells before it have just +// moved: the sample kernel, section 4.2. Four clocks per cell. +// MODE 2 JACOBI every cell drawn from the same old state and moved together at the end of the +// sweep. NOT the sample kernel: it does not sample the joint distribution. It is +// here only as the negative control the spec's coupled test asks to fail. +// +// The draw of cell i in sweep k of a chain with seed C is the top 53 bits of out(C, k*n + i + 1), +// out(s, j) = mix(s + j * 0x9E3779B97F4A7C15), the SplitMix64 output. Cells go in order and the +// index rises by one per cell, so the engine keeps a counter x, adds the constant once per cell and +// runs mix() in a nine-stage pipeline that advances once per cell; the host writes x's start +// (C + the constant) and the pipeline is primed for nine clocks when a job starts. +// +// The draw is compared with two cut points the host computes for the cell's field at the sweep's +// temperature (a = floor(P(-1) 2^53), b = floor((P(-1)+P(0)) 2^53), 54 bits each): -1 if u < a, +// 0 if u < b, else +1. The table holds 8,192 pairs: 2^(13-WBITS) temperature levels of 2^WBITS +// fields from WIN_LO. A field outside the window takes threshold(h, c); the host puts the window +// where every field whose draw is not certain falls inside it, or refuses the job. +// +// Register map: src/regs.rs. Cycle counts are part of the contract with src/model.rs. +`timescale 1ns/1ps +`default_nettype none + +module landscape_field ( + input wire [127:0] s, // {neg,pos} per cell + input wire [127:0] w, // {neg,pos} per coupling, row i + input wire signed [19:0] b, + output wire signed [21:0] h +); + wire [63:0] p, n; + genvar j; + generate + for (j = 0; j < 64; j = j + 1) begin : T + assign p[j] = (w[2*j] & s[2*j]) | (w[2*j+1] & s[2*j+1]); + assign n[j] = (w[2*j] & s[2*j+1]) | (w[2*j+1] & s[2*j]); + end + endgenerate + function automatic signed [2:0] c3(input [2:0] pp, input [2:0] nn); + c3 = $signed({2'b0, pp[0]}) + $signed({2'b0, pp[1]}) + $signed({2'b0, pp[2]}) + - $signed({2'b0, nn[0]}) - $signed({2'b0, nn[1]}) - $signed({2'b0, nn[2]}); + endfunction + wire signed [2:0] v0 [0:21]; + wire signed [3:0] v1 [0:10]; + wire signed [4:0] v2 [0:5]; + wire signed [5:0] v3 [0:2]; + wire signed [6:0] v4 [0:1]; + wire signed [7:0] v5; + genvar k; + generate + for (k = 0; k < 21; k = k + 1) begin : C + assign v0[k] = c3(p[3*k+2:3*k], n[3*k+2:3*k]); + end + assign v0[21] = c3({2'b0, p[63]}, {2'b0, n[63]}); + for (k = 0; k < 11; k = k + 1) begin : L1 + assign v1[k] = v0[2*k] + v0[2*k+1]; + end + for (k = 0; k < 5; k = k + 1) begin : L2 + assign v2[k] = v1[2*k] + v1[2*k+1]; + end + assign v2[5] = v1[10]; + for (k = 0; k < 3; k = k + 1) begin : L3 + assign v3[k] = v2[2*k] + v2[2*k+1]; + end + endgenerate + assign v4[0] = v3[0] + v3[1]; + assign v4[1] = v3[2]; + assign v5 = v4[0] + v4[1]; + assign h = v5 + b; +endmodule + +// The low 64 bits of x * K for a 64-bit constant K, in three stages, each stage's registers enabled +// by `en`: sixteen-bit limbs, the ten partial products that reach the low word, their sums by +// weight, then the total. +module landscape_mul64 #(parameter [63:0] K = 64'd0) ( + input wire clk, + input wire en, + input wire [63:0] x, + output reg [63:0] y = 64'd0 +); + wire [15:0] x0 = x[15:0], x1 = x[31:16], x2 = x[47:32], x3 = x[63:48]; + localparam [15:0] K0 = K[15:0], K1 = K[31:16], K2 = K[47:32], K3 = K[63:48]; + reg [31:0] p00 = 0, p01 = 0, p10 = 0, p02 = 0, p11 = 0, p20 = 0, p03 = 0, p12 = 0, p21 = 0, p30 = 0; + reg [33:0] w0 = 0, w1 = 0, w2 = 0, w3 = 0; + always @(posedge clk) if (en) begin + p00 <= x0 * K0; + p01 <= x0 * K1; p10 <= x1 * K0; + p02 <= x0 * K2; p11 <= x1 * K1; p20 <= x2 * K0; + p03 <= x0 * K3; p12 <= x1 * K2; p21 <= x2 * K1; p30 <= x3 * K0; + w0 <= {2'b0, p00}; + w1 <= {2'b0, p01} + {2'b0, p10}; + w2 <= {2'b0, p02} + {2'b0, p11} + {2'b0, p20}; + w3 <= {2'b0, p03} + {2'b0, p12} + {2'b0, p21} + {2'b0, p30}; + y <= {30'd0, w0} + {14'd0, w1, 16'd0} + {w2[31:0], 32'd0} + {w3[15:0], 48'd0}; + end +endmodule + +// SplitMix64's mix() on a counter: u = top 53 bits of mix(x), nine stages, advancing on `en`. +module landscape_draws ( + input wire clk, + input wire load, // x <- x0, the pipeline's contents become stale (prime it) + input wire [63:0] x0, + input wire en, + output wire [52:0] u +); + localparam [63:0] GOLDEN = 64'h9E3779B97F4A7C15; + reg [63:0] x = 64'd0, g1 = 64'd0, g3 = 64'd0, g5 = 64'd0; + wire [63:0] m1, m2; + always @(posedge clk) begin + if (load) x <= x0; + else if (en) x <= x + GOLDEN; + if (en) begin + g1 <= x ^ (x >> 30); + g3 <= m1 ^ (m1 >> 27); + g5 <= m2 ^ (m2 >> 31); + end + end + landscape_mul64 #(.K(64'hBF58476D1CE4E5B9)) M1 (.clk(clk), .en(en), .x(g1), .y(m1)); + landscape_mul64 #(.K(64'h94D049BB133111EB)) M2 (.clk(clk), .en(en), .x(g3), .y(m2)); + assign u = g5[63:11]; +endmodule + +module landscape_core ( + input wire clk, + input wire reg_stb, // one clock + input wire reg_we, + input wire [15:0] reg_addr, + input wire [31:0] reg_wdata, + output reg [31:0] reg_rdata, + output wire busy_o, + output wire done_o +); + localparam MODE_T0 = 2'd0, MODE_GIBBS = 2'd1, MODE_JACOBI = 2'd2; + localparam [3:0] S_IDLE = 0, S_LOAD = 1, S_T0 = 2, S_REQ = 3, S_TBL = 4, S_COMMIT = 5, + S_JAC = 6, S_FINAL = 7, S_END = 8, S_IDX = 9, S_PRIME = 10; + localparam [1:0] TERM_NONE = 0, TERM_FP = 1, TERM_2C = 2, TERM_BOUND = 3; + localparam integer PRIME = 9; // the draw pipeline's depth + + // ---- host-written configuration ------------------------------------------------------ + reg [1:0] mode = MODE_T0; + reg rep = 1'b0; + reg final_t0 = 1'b0; + reg [5:0] n_m1 = 6'd0; + reg [19:0] theta = 20'd0; + reg [31:0] bound = 32'd0; + reg [15:0] spl = 16'd1; // sweeps per temperature level + reg [5:0] levels_m1 = 6'd0; + reg [127:0] boundary = 128'd0; + reg [63:0] x0 = 64'd0; // the draw counter's start: chain seed + 0x9E3779B97F4A7C15 + reg signed [21:0] win_lo = 22'sd0; // the table window's first field + reg [3:0] wbits = 4'd7; // the window holds 2^wbits fields + + wire w_we = reg_stb & reg_we & (reg_addr[15:8] == 8'h10); + wire b_we = reg_stb & reg_we & (reg_addr[15:6] == 10'b0000_0010_00); + reg w_clear = 1'b0; + + // ---- state --------------------------------------------------------------------------- + reg [127:0] state = 128'd0; + reg [127:0] prev = 128'd0; + reg [127:0] prev2 = 128'd0; + reg have1 = 1'b0, have2 = 1'b0; + reg [3:0] fsm = S_IDLE; + reg done = 1'b0; + reg [1:0] term = TERM_NONE; + reg [5:0] sel = 6'd0; + reg [63:0] sel_hot = 64'd1; + reg [5:0] level = 6'd0; + reg [15:0] spl_cnt = 16'd0; + reg [31:0] steps = 32'd0; + reg [3:0] prime_cnt = 4'd0; + + assign busy_o = (fsm != S_IDLE); + assign done_o = done; + + // ---- the cones ----------------------------------------------------------------------- + wire signed [21:0] h [0:63]; + wire [63:0] gt, lt; + wire signed [21:0] th_s = {2'b00, theta}; + wire signed [21:0] nth_s = -th_s; + genvar i; + generate + for (i = 0; i < 64; i = i + 1) begin : CELL + reg [127:0] row = 128'd0; + reg signed [19:0] b = 20'sd0; + always @(posedge clk) begin + if (w_clear) row <= 128'd0; + else if (w_we && reg_addr[7:2] == i) begin + case (reg_addr[1:0]) + 2'd0: row[31:0] <= reg_wdata; + 2'd1: row[63:32] <= reg_wdata; + 2'd2: row[95:64] <= reg_wdata; + 2'd3: row[127:96] <= reg_wdata; + endcase + end + if (w_clear) b <= 20'sd0; + else if (b_we && reg_addr[5:0] == i) b <= reg_wdata[19:0]; + end + landscape_field f (.s(state), .w(row), .b(b), .h(h[i])); + assign gt[i] = (h[i] > th_s); + assign lt[i] = (h[i] < nth_s); + end + endgenerate + + wire signed [21:0] h_sel = h[sel]; + reg signed [21:0] h_reg = 22'sd0; + reg det_gt = 1'b0, det_lt = 1'b0, in_win = 1'b0; + reg [12:0] tidx = 13'd0; + + // ---- the cut-point table: 8,192 x {b[53:0], a[53:0]} ----------------------------------- + (* ram_style = "ultra" *) reg [107:0] tbl [0:8191]; + reg [12:0] tbl_addr = 13'd0; + reg [53:0] wa = 54'd0; // a, written first + reg [31:0] tbl_b_lo = 32'd0; // b's low word; b's high word commits the pair + reg [107:0] tbl_q = 108'd0; + wire tbl_host_we = reg_stb & reg_we & (reg_addr == 16'h001A); + wire tbl_run_rd = (fsm == S_TBL); + reg tbl_host_rd = 1'b0; + wire [12:0] tbl_a = tbl_run_rd ? tidx : tbl_addr; + always @(posedge clk) + if (tbl_run_rd | tbl_host_rd | tbl_host_we) begin + if (tbl_host_we) tbl[tbl_a] <= {reg_wdata[21:0], tbl_b_lo, wa}; + else tbl_q <= tbl[tbl_a]; + end + wire [53:0] cut_a = tbl_q[53:0]; + wire [53:0] cut_b = tbl_q[107:54]; + + // ---- the draws ------------------------------------------------------------------------- + wire sampling = (mode == MODE_GIBBS) | (mode == MODE_JACOBI); + wire draw_load = (fsm == S_LOAD) & sampling; + wire draw_adv = (fsm == S_PRIME) | (fsm == S_COMMIT); + wire [52:0] u; + landscape_draws D (.clk(clk), .load(draw_load), .x0(x0), .en(draw_adv), .u(u)); + + wire [54:0] uz = {2'b00, u}; + wire u_lt_a = (uz < {1'b0, cut_a}); + wire u_lt_b = (uz < {1'b0, cut_b}); + wire [1:0] s_cut = u_lt_a ? 2'b10 : (u_lt_b ? 2'b00 : 2'b01); + wire [1:0] s_smp = in_win ? s_cut : {det_lt, det_gt}; + + // ---- termination, on registers only ---------------------------------------------------- + wire eq1 = (state == prev); + wire eq2 = (state == prev2); + wire step_limit = (steps == bound); + wire last_cell = (sel == n_m1); + wire last_sweep = (steps + 32'd1 == bound); + + wire t0_terminal = (have1 & eq1) | (have2 & eq2) | step_limit; + wire t0_commit = ((fsm == S_T0) & ~t0_terminal) | (fsm == S_FINAL); + wire g_commit = (fsm == S_COMMIT) & (mode == MODE_GIBBS); + wire j_commit = (fsm == S_COMMIT) & (mode == MODE_JACOBI); + wire jac_all = (fsm == S_JAC); + wire load_state = (fsm == S_LOAD) | (reg_stb & reg_we & (reg_addr == 16'h0003) & reg_wdata[3] & (fsm == S_IDLE)); + + generate + for (i = 0; i < 64; i = i + 1) begin : UPD + always @(posedge clk) begin + if (load_state) state[2*i +: 2] <= boundary[2*i +: 2]; + else if (t0_commit) state[2*i +: 2] <= {lt[i], gt[i]}; + else if (jac_all) state[2*i +: 2] <= prev[2*i +: 2]; + else if (g_commit & sel_hot[i]) state[2*i +: 2] <= s_smp; + + if (load_state) prev[2*i +: 2] <= boundary[2*i +: 2]; + else if (t0_commit) prev[2*i +: 2] <= state[2*i +: 2]; + else if (j_commit & sel_hot[i]) prev[2*i +: 2] <= s_smp; + + if (t0_commit) prev2[2*i +: 2] <= prev[2*i +: 2]; + end + end + endgenerate + + // ---- counters ------------------------------------------------------------------------ + reg [47:0] uptime = 48'd0; + reg [47:0] cycles = 48'd0; + reg [47:0] updates = 48'd0; + reg [47:0] jobs = 48'd0; + reg [20:0] rd_hi = 21'd0; + + wire start = reg_stb & reg_we & (reg_addr == 16'h0003) & reg_wdata[0]; + wire cont = reg_stb & reg_we & (reg_addr == 16'h0003) & reg_wdata[1]; + wire stop = reg_stb & reg_we & (reg_addr == 16'h0003) & reg_wdata[2]; + wire clrw = reg_stb & reg_we & (reg_addr == 16'h0003) & reg_wdata[4]; + wire clrc = reg_stb & reg_we & (reg_addr == 16'h0003) & reg_wdata[5]; + + // the window offset and the level's base, for the table index + wire signed [22:0] d_full = {h_reg[21], h_reg} - {win_lo[21], win_lo}; + wire [13:0] wsize = 14'd1 << wbits; + wire [12:0] lbase = {7'd0, level} << wbits; + + always @(posedge clk) begin + uptime <= uptime + 48'd1; + w_clear <= clrw; + tbl_host_rd <= reg_stb & reg_we & (reg_addr == 16'h0016); + + if (clrc) begin + cycles <= 48'd0; updates <= 48'd0; jobs <= 48'd0; + end else begin + if (fsm != S_IDLE) cycles <= cycles + 48'd1; + if (fsm == S_COMMIT) updates <= updates + 48'd1; + if (fsm == S_END) jobs <= jobs + 48'd1; + end + + if (fsm == S_REQ || fsm == S_IDLE) h_reg <= h_sel; + if (fsm == S_IDX) begin + in_win <= (d_full >= 23'sd0) && (d_full < $signed({9'd0, wsize})); + tidx <= lbase + d_full[12:0]; + det_gt <= (h_reg > th_s); + det_lt <= (h_reg < nth_s); + end + + case (fsm) + S_IDLE: begin + if (start) begin + fsm <= S_LOAD; done <= 1'b0; term <= TERM_NONE; + end else if (cont) begin + done <= 1'b0; term <= TERM_NONE; steps <= 32'd0; + level <= 6'd0; spl_cnt <= 16'd0; sel <= 6'd0; sel_hot <= 64'd1; + have1 <= 1'b0; have2 <= 1'b0; + fsm <= (mode == MODE_T0) ? S_T0 : S_REQ; + end + end + S_LOAD: begin + steps <= 32'd0; level <= 6'd0; spl_cnt <= 16'd0; sel <= 6'd0; sel_hot <= 64'd1; + have1 <= 1'b0; have2 <= 1'b0; prime_cnt <= 4'd0; + fsm <= (mode == MODE_T0) ? S_T0 : S_PRIME; + end + S_PRIME: begin + prime_cnt <= prime_cnt + 4'd1; + if (prime_cnt == PRIME - 1) + fsm <= (bound == 32'd0) ? (final_t0 ? S_FINAL : S_END) : S_REQ; + end + S_T0: begin + if (t0_terminal) begin + term <= (have1 & eq1) ? TERM_FP : ((have2 & eq2) ? TERM_2C : TERM_BOUND); + fsm <= S_END; + end else begin + steps <= steps + 32'd1; + have1 <= 1'b1; + have2 <= have1; + end + end + S_REQ: fsm <= S_IDX; + S_IDX: fsm <= S_TBL; + S_TBL: fsm <= S_COMMIT; + S_COMMIT: begin + if (last_cell) begin + sel <= 6'd0; sel_hot <= 64'd1; + if (mode == MODE_JACOBI) fsm <= S_JAC; + else begin + steps <= steps + 32'd1; + if (last_sweep) fsm <= final_t0 ? S_FINAL : S_END; + else begin + fsm <= S_REQ; + if (spl_cnt + 16'd1 == spl) begin + spl_cnt <= 16'd0; + if (level != levels_m1) level <= level + 6'd1; + end else spl_cnt <= spl_cnt + 16'd1; + end + end + end else begin + sel <= sel + 6'd1; + sel_hot <= {sel_hot[62:0], 1'b0}; + fsm <= S_REQ; + end + end + S_JAC: begin + steps <= steps + 32'd1; + if (last_sweep) fsm <= final_t0 ? S_FINAL : S_END; + else begin + fsm <= S_REQ; + if (spl_cnt + 16'd1 == spl) begin + spl_cnt <= 16'd0; + if (level != levels_m1) level <= level + 6'd1; + end else spl_cnt <= spl_cnt + 16'd1; + end + end + S_FINAL: fsm <= S_END; + S_END: begin + if (rep) fsm <= S_LOAD; + else begin fsm <= S_IDLE; done <= 1'b1; end + end + default: fsm <= S_IDLE; + endcase + + if (stop) begin fsm <= S_IDLE; done <= 1'b0; end + + // ---- register writes ------------------------------------------------------------- + if (reg_stb && reg_we) begin + case (reg_addr) + 16'h0004: begin mode <= reg_wdata[1:0]; rep <= reg_wdata[8]; final_t0 <= reg_wdata[9]; end + 16'h0005: n_m1 <= reg_wdata[5:0]; + 16'h0006: theta <= reg_wdata[19:0]; + 16'h0007: bound <= reg_wdata; + 16'h0008: spl <= reg_wdata[15:0]; + 16'h0009: levels_m1 <= reg_wdata[5:0]; + 16'h0010: x0[31:0] <= reg_wdata; + 16'h0011: x0[63:32] <= reg_wdata; + 16'h0012: win_lo <= reg_wdata[21:0]; + 16'h0013: wbits <= reg_wdata[3:0]; + 16'h0014: if (fsm == S_IDLE) sel <= reg_wdata[5:0]; + 16'h0016: tbl_addr <= reg_wdata[12:0]; + 16'h0017: wa[31:0] <= reg_wdata; + 16'h0018: wa[53:32] <= reg_wdata[21:0]; + 16'h0019: tbl_b_lo <= reg_wdata; + 16'h001A: tbl_addr <= tbl_addr + 13'd1; + 16'h0100: boundary[31:0] <= reg_wdata; + 16'h0101: boundary[63:32] <= reg_wdata; + 16'h0102: boundary[95:64] <= reg_wdata; + 16'h0103: boundary[127:96] <= reg_wdata; + default: ; + endcase + end + + // ---- register reads -------------------------------------------------------------- + if (reg_stb && !reg_we) begin + case (reg_addr) + 16'h0000: reg_rdata <= 32'h4C414E44; // "LAND" + 16'h0001: reg_rdata <= 32'h0040_4002; // 64 cells, 64 levels, rtl version 2 + 16'h0002: reg_rdata <= {28'd0, term, done, busy_o}; + 16'h0004: reg_rdata <= {22'd0, final_t0, rep, 6'd0, mode}; + 16'h0005: reg_rdata <= {26'd0, n_m1}; + 16'h0006: reg_rdata <= {12'd0, theta}; + 16'h0007: reg_rdata <= bound; + 16'h0012: reg_rdata <= {{10{win_lo[21]}}, win_lo}; + 16'h0013: reg_rdata <= {28'd0, wbits}; + 16'h0015: reg_rdata <= {{10{h_reg[21]}}, h_reg}; + 16'h0016: reg_rdata <= {19'd0, tbl_addr}; + 16'h0017: reg_rdata <= tbl_q[31:0]; + 16'h0018: reg_rdata <= {10'd0, tbl_q[53:32]}; + 16'h0019: reg_rdata <= tbl_q[85:54]; + 16'h001A: reg_rdata <= {10'd0, tbl_q[107:86]}; + 16'h001B: begin reg_rdata <= u[31:0]; rd_hi <= u[52:32]; end + 16'h001C: reg_rdata <= {11'd0, rd_hi}; + 16'h0020: begin reg_rdata <= uptime[31:0]; rd_hi <= {5'd0, uptime[47:32]}; end + 16'h0022: begin reg_rdata <= cycles[31:0]; rd_hi <= {5'd0, cycles[47:32]}; end + 16'h0024: begin reg_rdata <= updates[31:0]; rd_hi <= {5'd0, updates[47:32]}; end + 16'h0026: begin reg_rdata <= jobs[31:0]; rd_hi <= {5'd0, jobs[47:32]}; end + 16'h0021, 16'h0023, 16'h0025, 16'h0027: reg_rdata <= {11'd0, rd_hi}; + 16'h0028: reg_rdata <= steps; + 16'h0110: reg_rdata <= state[31:0]; + 16'h0111: reg_rdata <= state[63:32]; + 16'h0112: reg_rdata <= state[95:64]; + 16'h0113: reg_rdata <= state[127:96]; + default: reg_rdata <= 32'hDEAD_BEEF; + endcase + end + end +endmodule + +`default_nettype wire diff --git a/wai/wai-quantum-landscape-fpga/rtl/landscape_multi.v b/wai/wai-quantum-landscape-fpga/rtl/landscape_multi.v new file mode 100644 index 000000000..80f686fa1 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/rtl/landscape_multi.v @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: Apache-2.0 +// K copies of the engine behind one EMIO port: address bits [15:13] pick the core, [12:0] are the +// core's own map. busy is ORed and done ANDed across cores. The host addresses one core at a time +// (CorePort) or all at once (BroadcastPort). +`timescale 1ns/1ps +`default_nettype none +module landscape_multi #(parameter integer K = 4) ( + input wire clk, + input wire [94:0] emio_o, + output wire [94:0] emio_i +); + (* ASYNC_REG = "TRUE" *) reg req_s1 = 1'b0, req_s2 = 1'b0; + reg req_d = 1'b0; + reg [6:0] por = 7'd0; + wire por_done = por[6]; + always @(posedge clk) begin + req_s1 <= emio_o[80]; + req_s2 <= req_s1; + req_d <= req_s2; + if (!por_done) por <= por + 7'd1; + end + reg stb = 1'b0, we = 1'b0, ack = 1'b0; + reg [15:0] addr = 16'd0; + reg [31:0] wdata = 32'd0; + reg [3:0] wait_cnt = 4'd0; + always @(posedge clk) begin + stb <= 1'b0; + if (por_done && (req_s2 ^ req_d)) begin + addr <= emio_o[79:64]; we <= emio_o[81]; wdata <= emio_o[31:0]; + stb <= 1'b1; wait_cnt <= 4'd4; + end else if (wait_cnt != 4'd0) begin + wait_cnt <= wait_cnt - 4'd1; + if (wait_cnt == 4'd1) ack <= ~ack; + end + end + wire [31:0] rd [0:K-1]; + wire [K-1:0] busy, done; + genvar c; + generate + for (c = 0; c < K; c = c + 1) begin : CORE + landscape_core core ( + .clk(clk), .reg_stb(stb & (addr[15:13] == c)), .reg_we(we), + .reg_addr({3'b000, addr[12:0]}), .reg_wdata(wdata), + .reg_rdata(rd[c]), .busy_o(busy[c]), .done_o(done[c]) + ); + end + endgenerate + reg [31:0] rdata = 32'd0; + always @(posedge clk) rdata <= rd[addr[15:13] % K]; + assign emio_i = {10'd0, &done, |busy, ack, 18'd0, rdata, 32'd0}; +endmodule +`default_nettype wire diff --git a/wai/wai-quantum-landscape-fpga/rtl/landscape_port.v b/wai/wai-quantum-landscape-fpga/rtl/landscape_port.v new file mode 100644 index 000000000..d3f634823 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/rtl/landscape_port.v @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: Apache-2.0 +// The job port: register reads and writes carried over the PS's EMIO GPIO lines. +// +// Why not AXI. A PS load or store to an AXI address whose PL slave is gone never completes, and it +// takes the whole board with it until someone power-cycles it. This board is shared and remote, and +// another session's reload can replace the design between two accesses. An EMIO line is a PS +// register: with the design gone a read returns junk, the ID check fails, and the job gets an +// error. The cost is speed: about 1.6 us a register access, measured. +// +// The PS offers 95 EMIO lines (banks 3, 4 and 31 bits of 5): +// emio_o[31:0] wdata (bank 3) emio_i[63:32] rdata (bank 4) +// emio_o[79:64] addr (bank 5, 15:0) emio_o[80] req (toggle) emio_o[81] we +// emio_i[82] ack (toggle) emio_i[83] busy emio_i[84] done +// busy and done are wired straight through, so polling for the end of a job takes no transaction. +// +// Handshake: the host writes wdata, then addr/we/req in one register write. The req edge crosses a +// two-flop synchroniser, so by the time it is seen addr, we and wdata have long been stable; they are +// latched then, and ack toggles once the access is done. +`timescale 1ns/1ps +`default_nettype none + +module landscape_port ( + input wire clk, + input wire [94:0] emio_o, + output wire [94:0] emio_i +); + (* ASYNC_REG = "TRUE" *) reg req_s1 = 1'b0, req_s2 = 1'b0; + reg req_d = 1'b0; + reg [6:0] por = 7'd0; // the PS's lines may hold anything when we are configured + wire por_done = por[6]; + always @(posedge clk) begin + req_s1 <= emio_o[80]; + req_s2 <= req_s1; + req_d <= req_s2; + if (!por_done) por <= por + 7'd1; + end + + reg stb = 1'b0, we = 1'b0, ack = 1'b0; + reg [15:0] addr = 16'd0; + reg [31:0] wdata = 32'd0; + reg [3:0] wait_cnt = 4'd0; + wire [31:0] rdata; + wire busy, done; + + always @(posedge clk) begin + stb <= 1'b0; + if (por_done && (req_s2 ^ req_d)) begin + addr <= emio_o[79:64]; + we <= emio_o[81]; + wdata <= emio_o[31:0]; + stb <= 1'b1; + wait_cnt <= 4'd4; + end else if (wait_cnt != 4'd0) begin + wait_cnt <= wait_cnt - 4'd1; + if (wait_cnt == 4'd1) ack <= ~ack; + end + end + + landscape_core core ( + .clk(clk), .reg_stb(stb), .reg_we(we), .reg_addr(addr), .reg_wdata(wdata), + .reg_rdata(rdata), .busy_o(busy), .done_o(done) + ); + + assign emio_i = {10'd0, done, busy, ack, 18'd0, rdata, 32'd0}; +endmodule + +`default_nettype wire diff --git a/wai/wai-quantum-landscape-fpga/rtl/landscape_top.v b/wai/wai-quantum-landscape-fpga/rtl/landscape_top.v new file mode 100644 index 000000000..6fad282d4 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/rtl/landscape_top.v @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: Apache-2.0 +// KV260 top: the PS provides pl_clk0 and the EMIO lines; there is no other PL I/O. +`timescale 1ns/1ps +module design_top(); + wire pl_clk0; + wire [94:0] emio_o; + wire [94:0] emio_i; + sys_wrapper ps_i (.pl_clk0(pl_clk0), .emio_o(emio_o), .emio_i(emio_i)); + landscape_port u (.clk(pl_clk0), .emio_o(emio_o), .emio_i(emio_i)); +endmodule diff --git a/wai/wai-quantum-landscape-fpga/rtl/landscape_top_axi.v b/wai/wai-quantum-landscape-fpga/rtl/landscape_top_axi.v new file mode 100644 index 000000000..97122a5b5 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/rtl/landscape_top_axi.v @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: Apache-2.0 +// KV260 top for the AXI link: the processing system gives the clock, an AXI-Lite master (its +// full-power-domain master port, through a width and a protocol converter), a high-performance slave port +// into DDR (through a width converter), and the EMIO lines. See landscape.tcl for why the widths +// are what they are. The reset is the fabric's own: a counter that holds the link's control in +// reset for 128 clocks after configuration, so the design does not depend on the state the +// processor's PL reset line was left in. +`timescale 1ns/1ps +module design_top(); + wire pl_clk0; + reg [7:0] por = 8'd0; + always @(posedge pl_clk0) if (!por[7]) por <= por + 8'd1; + wire rstn = por[7]; + wire [39:0] l_awaddr, l_araddr; + wire [31:0] l_wdata, l_rdata; + wire l_awvalid, l_awready, l_wvalid, l_wready, l_bvalid, l_bready, l_arvalid, l_arready, l_rvalid, l_rready; + wire [1:0] l_bresp, l_rresp; + wire [3:0] l_wstrb; + wire [2:0] l_awprot, l_arprot; + wire [48:0] d_araddr; + wire [7:0] d_arlen; + wire [2:0] d_arsize, d_arprot; + wire [1:0] d_arburst, d_rresp; + wire [3:0] d_arcache; + wire d_arvalid, d_arready, d_rlast, d_rvalid, d_rready; + wire [48:0] d_awaddr; + wire [7:0] d_awlen, d_wstrb; + wire [2:0] d_awsize, d_awprot; + wire [1:0] d_awburst, d_bresp; + wire [3:0] d_awcache; + wire [63:0] d_wdata; + wire d_awvalid, d_awready, d_wlast, d_wvalid, d_wready, d_bvalid, d_bready; + wire [63:0] d_rdata; + wire [94:0] emio_o, emio_i; + sys_wrapper ps_i ( + .pl_clk0(pl_clk0), .aresetn(rstn), .emio_o(emio_o), .emio_i(emio_i), + .LITE_awaddr(l_awaddr), .LITE_awprot(l_awprot), .LITE_awvalid(l_awvalid), .LITE_awready(l_awready), + .LITE_wdata(l_wdata), .LITE_wstrb(l_wstrb), .LITE_wvalid(l_wvalid), .LITE_wready(l_wready), + .LITE_bresp(l_bresp), .LITE_bvalid(l_bvalid), .LITE_bready(l_bready), + .LITE_araddr(l_araddr), .LITE_arprot(l_arprot), .LITE_arvalid(l_arvalid), .LITE_arready(l_arready), + .LITE_rdata(l_rdata), .LITE_rresp(l_rresp), .LITE_rvalid(l_rvalid), .LITE_rready(l_rready), + .DMA_araddr(d_araddr), .DMA_arlen(d_arlen), .DMA_arsize(d_arsize), .DMA_arburst(d_arburst), + .DMA_arcache(d_arcache), .DMA_arprot(d_arprot), .DMA_arvalid(d_arvalid), .DMA_arready(d_arready), + .DMA_arlock(1'b0), .DMA_arqos(4'd0), .DMA_arregion(4'd0), + .DMA_rdata(d_rdata), .DMA_rresp(d_rresp), .DMA_rlast(d_rlast), .DMA_rvalid(d_rvalid), .DMA_rready(d_rready), + .DMA_awaddr(d_awaddr), .DMA_awlen(d_awlen), .DMA_awsize(d_awsize), .DMA_awburst(d_awburst), .DMA_awcache(d_awcache), + .DMA_awprot(d_awprot), .DMA_awvalid(d_awvalid), .DMA_awready(d_awready), .DMA_awlock(1'b0), .DMA_awqos(4'd0), .DMA_awregion(4'd0), + .DMA_wdata(d_wdata), .DMA_wstrb(d_wstrb), .DMA_wlast(d_wlast), .DMA_wvalid(d_wvalid), .DMA_wready(d_wready), + .DMA_bresp(d_bresp), .DMA_bvalid(d_bvalid), .DMA_bready(d_bready) + ); + landscape_axi u ( + .clk(pl_clk0), .rstn(rstn), + .s_awaddr(l_awaddr[31:0]), .s_awvalid(l_awvalid), .s_awready(l_awready), .s_wdata(l_wdata), .s_wvalid(l_wvalid), + .s_wready(l_wready), .s_bresp(l_bresp), .s_bvalid(l_bvalid), .s_bready(l_bready), + .s_araddr(l_araddr[31:0]), .s_arvalid(l_arvalid), .s_arready(l_arready), .s_rdata(l_rdata), .s_rresp(l_rresp), + .s_rvalid(l_rvalid), .s_rready(l_rready), + .m_araddr(d_araddr), .m_arlen(d_arlen), .m_arsize(d_arsize), .m_arburst(d_arburst), .m_arcache(d_arcache), + .m_arprot(d_arprot), .m_arvalid(d_arvalid), .m_arready(d_arready), .m_rdata(d_rdata), .m_rresp(d_rresp), + .m_rlast(d_rlast), .m_rvalid(d_rvalid), .m_rready(d_rready), + .m_awaddr(d_awaddr), .m_awlen(d_awlen), .m_awsize(d_awsize), .m_awburst(d_awburst), .m_awcache(d_awcache), + .m_awprot(d_awprot), .m_awvalid(d_awvalid), .m_awready(d_awready), .m_wdata(d_wdata), .m_wstrb(d_wstrb), + .m_wlast(d_wlast), .m_wvalid(d_wvalid), .m_wready(d_wready), .m_bresp(d_bresp), .m_bvalid(d_bvalid), .m_bready(d_bready), + .emio_i(emio_i) + ); +endmodule diff --git a/wai/wai-quantum-landscape-fpga/rtl/landscape_top_multi.v b/wai/wai-quantum-landscape-fpga/rtl/landscape_top_multi.v new file mode 100644 index 000000000..5c6c1c53b --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/rtl/landscape_top_multi.v @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: Apache-2.0 +`timescale 1ns/1ps +module design_top(); + wire pl_clk0; + wire [94:0] emio_o; + wire [94:0] emio_i; + sys_wrapper ps_i (.pl_clk0(pl_clk0), .emio_o(emio_o), .emio_i(emio_i)); + landscape_multi #(.K(`LANDSCAPE_K)) u (.clk(pl_clk0), .emio_o(emio_o), .emio_i(emio_i)); +endmodule diff --git a/wai/wai-quantum-landscape-fpga/scripts/build_bitstream.sh b/wai/wai-quantum-landscape-fpga/scripts/build_bitstream.sh new file mode 100755 index 000000000..bfedcb505 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/scripts/build_bitstream.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# SPDX-License-Identifier: Apache-2.0 +# Build the engine's bitstream and convert it for the Linux FPGA manager. Needs the vendor's tool on +# PATH, at the version this design was built and measured with: Vivado 2026.1 (landscape.tcl stops on +# any other). Its no-charge licence tier covers this part. The design uses no licensed IP: its vendor +# blocks are the processing system's configuration and, in the AXI build, the tool's AXI width and +# protocol converters. Run from an empty directory: +# sh /path/to/wai-quantum-landscape-fpga/scripts/build_bitstream.sh [MHz] [cores] [axi|emio] +# The AXI link is the default; the multi-core build (cores above 1) has the EMIO link only. +# JOBS (default 4) is how many tool runs go at once. On a small machine, run with JOBS=1 and a memory +# cap: the tool peaked at 5.1 GB alone, and a machine with 15 GB shared with other work ran out. +set -e +FREQ=${1:-100} +CORES=${2:-1} +LINK=${3:-axi} +if [ "$CORES" -gt 1 ]; then LINK=emio; fi +HERE=$(cd "$(dirname "$0")/.." && pwd) +vivado -version | head -1 +vivado -mode batch -nojournal -source "$HERE/landscape.tcl" -tclargs FREQ "$FREQ" TAG landscape JOBS "${JOBS:-4}" CORES "$CORES" LINK "$LINK" > build.log 2>&1 +grep -E "IMPL_STATUS|BITSTREAM" build.log +BIT=$(ls ev_landscape/ev_landscape.runs/impl_1/*.bit) +printf 'all:\n{\n %s\n}\n' "$BIT" > landscape.bif +bootgen -image landscape.bif -arch zynqmp -process_bitstream bin -w on +cp "$BIT.bin" landscape.bit.bin +grep -A6 "Design Timing Summary" ev_landscape.timing.rpt | tail -1 +sha256sum landscape.bit.bin diff --git a/wai/wai-quantum-landscape-fpga/scripts/build_host.sh b/wai/wai-quantum-landscape-fpga/scripts/build_host.sh new file mode 100755 index 000000000..74bf98809 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/scripts/build_host.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# SPDX-License-Identifier: Apache-2.0 +# Cross-compile the host for the board's processor (aarch64 Linux, glibc 2.39 on the board's image). +# Needs rustup's aarch64-unknown-linux-gnu target for the repository's pinned toolchain and the +# aarch64-linux-gnu-gcc linker. +set -e +cd "$(dirname "$0")/.." +rustup target add aarch64-unknown-linux-gnu +CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc cargo build --release --target aarch64-unknown-linux-gnu +ls -la "${CARGO_TARGET_DIR:-target}/aarch64-unknown-linux-gnu/release/wai-quantum-landscape-fpga" diff --git a/wai/wai-quantum-landscape-fpga/scripts/power_campaign.sh b/wai/wai-quantum-landscape-fpga/scripts/power_campaign.sh new file mode 100755 index 000000000..7d91d289b --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/scripts/power_campaign.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# SPDX-License-Identifier: Apache-2.0 +# The power campaign, in a fixed order: the run/halt step response, a known-answer vehicle where one +# is present, a null, each job class, then the clock-scaling check. Run ON the board as root, +# detached, and touch nothing on the board until DONE appears (the meter reads the whole board, the +# processor included): +# sudo setsid nohup sh power_campaign.sh [OUTDIR] > /dev/null 2>&1 & +# Needs wai-quantum-landscape-fpga and the loaded engine. A known-answer vehicle of your own goes in +# KNOWN_ANSWER (a script taking the bitstream name, settle, passes and samples, printing +# "pass run|halt sample microwatts" lines) and KNOWN_BITSTREAM; without them that step is skipped, +# and the null and the clock-scaling check are the instrument's checks. +cd "$(dirname "$0")" +OUT=${1:-power-$(date -u +%Y%m%dT%H%M%SZ)}/power; mkdir -p "$OUT" +BIT=${ENGINE_BITSTREAM:-landscape.bit.bin} +log() { echo "$(date -u +%FT%TZ) $*" >> "$OUT/campaign.log"; } +guard() { + # the tool leaves out itself and what it descends from: this script, and run_all.sh if that started it + f=$(./wai-quantum-landscape-fpga foreign) || { log "STOP: another session is on the board: $f"; echo STOPPED > "$OUT/DONE"; exit 3; } +} +log "start; $(./wai-quantum-landscape-fpga status 2>&1 | tr '\n' ' ')" +guard +./wai-quantum-landscape-fpga meter t0-recall 1 0 300 > "$OUT/step.dat" 2>&1; log "step done" +if [ -n "${KNOWN_ANSWER:-}" ] && [ -n "${KNOWN_BITSTREAM:-}" ]; then + guard + sh "$KNOWN_ANSWER" "$KNOWN_BITSTREAM" 60 8 30 > "$OUT/known_answer.dat" 2>&1; log "known answer done exit=$?" + [ -d /sys/class/gpio/gpio594 ] && echo 594 > /sys/class/gpio/unexport + ./wai-quantum-landscape-fpga load "$BIT" >> "$OUT/campaign.log" 2>&1 || { log "reload of the engine failed"; echo FAILED > "$OUT/DONE"; exit 2; } +else + log "known answer skipped: KNOWN_ANSWER and KNOWN_BITSTREAM not set" +fi +for spec in "null:t0-recall 8 60 30 --null --predict 0" "t0-recall:t0-recall 10 60 30 --predict 160" \ + "gibbs-recall:gibbs-recall 10 60 30 --predict 12" "t0-idle:t0-idle 8 60 30 --predict 4"; do + name=${spec%%:*}; args=${spec#*:} + guard + ./wai-quantum-landscape-fpga meter $args > "$OUT/$name.dat" 2>&1; log "$name done exit=$?" +done +guard +./wai-quantum-landscape-fpga clock 30 >> "$OUT/campaign.log" 2>&1 +./wai-quantum-landscape-fpga meter t0-recall 6 60 30 --predict 80 > "$OUT/t0-recall-50MHz.dat" 2>&1; log "50 MHz done exit=$?" +./wai-quantum-landscape-fpga clock 15 >> "$OUT/campaign.log" 2>&1 +log "end" +echo DONE > "$OUT/DONE" diff --git a/wai/wai-quantum-landscape-fpga/scripts/power_tables.py b/wai/wai-quantum-landscape-fpga/scripts/power_tables.py new file mode 100644 index 000000000..78b23a1ed --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/scripts/power_tables.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +"""Per-class table from meter logs, by the pre-registered statistic (mean of per-pass differences +of medians, SE across passes), plus a sensitivity column that was NOT pre-registered: the same +with a 10%-trimmed mean inside each point, which keeps sub-quantum information a median of +10 mW-quantised samples throws away. Passes flagged in the log are dropped. + python3 -I power_tables.py a.dat b.dat ... +""" +import statistics as st, sys, re + +def trimmed(xs, f=0.1): + s = sorted(xs); k = int(len(s) * f) + s = s[k:len(s) - k] if k else s + return sum(s) / len(s) + +for path in sys.argv[1:]: + pts, flagged = {}, set() + for line in open(path): + m = re.search(r'pass=(\d+)', line) + if line.startswith('#'): + if m and ('FLAGGED' in line or 'FOREIGN-LOAD' in line or 'NOT-OURS' in line): + flagged.add(int(m.group(1))) + continue + f = line.split() + if len(f) >= 4 and f[0].isdigit() and f[3].isdigit(): + pts.setdefault((int(f[0]), f[1]), []).append(int(f[3]) / 1000.0) + passes = sorted({p for p, _ in pts} - flagged) + dm = [st.median(pts[(p, 'run')]) - st.median(pts[(p, 'halt')]) for p in passes] + dt = [trimmed(pts[(p, 'run')]) - trimmed(pts[(p, 'halt')]) for p in passes] + n = len(passes) + fmt = lambda d: f"{st.mean(d):7.1f} +/- {st.stdev(d) / n ** 0.5:4.1f}" + pr = st.mean(st.median(pts[(p, 'run')]) for p in passes) + print(f"{path.split('/')[-1]:24s} passes {n:2d} medians {fmt(dm)} mW trimmed {fmt(dt)} mW P_run {pr:6.0f} mW flagged {sorted(flagged)}") diff --git a/wai/wai-quantum-landscape-fpga/scripts/run_all.sh b/wai/wai-quantum-landscape-fpga/scripts/run_all.sh new file mode 100755 index 000000000..5c77aa54b --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/scripts/run_all.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# SPDX-License-Identifier: Apache-2.0 +# Everything a builder runs on their own board, in order: load the engine, the conformance set, the +# worked examples against the CPU reference, the joint statistics against exact enumeration, the +# processor-to-logic latency, throughput, then the power campaign. On the board, as root, from a +# directory holding wai-quantum-landscape-fpga, landscape.bit.bin, this script and power_campaign.sh: +# sudo setsid nohup sh run_all.sh > /dev/null 2>&1 & +# and leave the board alone until results-*/power/DONE appears (about three hours). It refuses to +# start, and stops between steps, if another session is flashing or measuring, and it stops if a +# check fails: a power figure on a design that failed its checks is not worth the three hours. On a +# shared board, name the other sessions' tools in WAI_QUANTUM_LANDSCAPE_FPGA_FOREIGN. +cd "$(dirname "$0")" +OUT=results-$(date -u +%Y%m%dT%H%M%SZ) +mkdir -p "$OUT" +B=./wai-quantum-landscape-fpga +BIT=${ENGINE_BITSTREAM:-landscape.bit.bin} +log() { echo "$(date -u +%FT%TZ) $*" >> "$OUT/log.txt"; } +FOREIGN=$($B foreign) || { echo "another session is on the board: $FOREIGN" > "$OUT/STOPPED"; exit 3; } +{ + echo "fpga manager flags: $(cat /sys/class/fpga_manager/fpga0/flags)" + echo "last FPGA write: $(dmesg | grep 'writing.*FPGA' | tail -1)" + sha256sum "$BIT" "$B" +} > "$OUT/board_before.txt" +# A non-zero flags word makes the manager treat a plain bitstream as something else; it is put back. +FLAGS=$(cat /sys/class/fpga_manager/fpga0/flags) +echo 0 > /sys/class/fpga_manager/fpga0/flags +# The flock is not held here across the steps: each step takes it itself, and would wait on this +# script for ever. Between steps the board is free, which is why the session check runs at each. +$B load "$BIT" > "$OUT/load.txt" 2>&1 || { log "load failed"; echo "$FLAGS" > /sys/class/fpga_manager/fpga0/flags; exit 2; } +$B status > "$OUT/status.txt" 2>&1 +step() { + name=$1; shift + f=$($B foreign) || { log "STOP: another session is on the board: $f"; echo "$FLAGS" > /sys/class/fpga_manager/fpga0/flags; exit 3; } + $B "$@" > "$OUT/$name.txt" 2>&1; rc=$? + log "$name exit=$rc" + [ "$rc" -eq 0 ] || { echo "$FLAGS" > /sys/class/fpga_manager/fpga0/flags; exit 4; } +} +step conform conform +step agree agree --seeds 200 +step joint joint --seed 2027 +step latency latency +step throughput throughput +sh power_campaign.sh "$OUT" +$B release >> "$OUT/status.txt" 2>&1 +echo "$FLAGS" > /sys/class/fpga_manager/fpga0/flags diff --git a/wai/wai-quantum-landscape-fpga/scripts/run_tb.sh b/wai/wai-quantum-landscape-fpga/scripts/run_tb.sh new file mode 100755 index 000000000..3aa4ec8cf --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/scripts/run_tb.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# SPDX-License-Identifier: Apache-2.0 +# Replays the model's session against the logic in an open-source simulator (Icarus Verilog), the +# EMIO testbench and the AXI testbench, and fails on any mismatch. Needs iverilog and a Rust +# toolchain. The vendor's simulator takes the same files: the testbenches open landscape_tb.script +# and landscape_axi_tb.script in the directory they run in, so write those there with gen-tb and run +# xvlog rtl/landscape_core.v rtl/landscape_axi.v tb/tb_landscape_axi.v && xelab tb -s tbs && xsim tbs -R +# sh scripts/run_tb.sh [emio|axi|both] +set -e +WHICH=${1:-both} +HERE=$(cd "$(dirname "$0")/.." && pwd) +OUT=$(mktemp -d) +trap 'rm -rf "$OUT"' EXIT +cd "$HERE" +cargo build --locked --release +BIN=${CARGO_TARGET_DIR:-target}/release/wai-quantum-landscape-fpga +replay() { # name script gen-flag sources... + name=$1; script=$2; flag=$3; shift 3 + "$BIN" gen-tb "$OUT/$script" $flag + iverilog -g2012 -o "$OUT/$name.vvp" "$@" + (cd "$OUT" && vvp "$name.vvp") | tee "$OUT/$name.log" | tail -3 + grep -qE '^TB DONE: [0-9]+ lines, [0-9]+ checked reads, 0 mismatches' "$OUT/$name.log" || { echo "$name: the replay did not finish clean" >&2; exit 1; } +} +case "$WHICH" in emio|both) replay emio landscape_tb.script "" rtl/landscape_core.v rtl/landscape_port.v tb/tb_landscape.v ;; esac +case "$WHICH" in axi|both) replay axi landscape_axi_tb.script --axi rtl/landscape_core.v rtl/landscape_axi.v tb/tb_landscape_axi.v ;; esac diff --git a/wai/wai-quantum-landscape-fpga/scripts/step_settle.py b/wai/wai-quantum-landscape-fpga/scripts/step_settle.py new file mode 100644 index 000000000..150eb1782 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/scripts/step_settle.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: Apache-2.0 +"""Settle time of the run/halt switch, from `wai-quantum-landscape-fpga meter 1 0 300` (no +settle, 300 samples). + +LAST deviation, not first touch, and of the level, not of one sample: the sensor throws single-sample +spikes all through a segment, so each 15-sample median is held to a band around the segment's final +level, the band being 2 sensor quanta (20 mW). The settle used by the campaign must exceed the last +window outside it, or every point reads the previous state. The last single sample outside +max(20 mW, 3 x the tail's SD) is printed beside it, for the spikes. + python3 -I step_settle.py step.dat +""" +import statistics, sys + +WINDOW = 15 + +seg = {} +for line in open(sys.argv[1]): + if line.startswith('#') or not line.strip(): + continue + f = line.split() + if len(f) < 4: + continue + seg.setdefault((int(f[0]), f[1]), []).append(int(f[3]) / 1000.0) +for (p, state), xs in sorted(seg.items()): + tail = xs[-60:] + final = statistics.median(tail) + band = max(20.0, 3 * statistics.pstdev(tail)) + last = max((i for i, x in enumerate(xs) if abs(x - final) > band), default=-1) + medians = [statistics.median(xs[i:i + WINDOW]) for i in range(0, len(xs) - WINDOW + 1, WINDOW)] + off = max((k for k, m in enumerate(medians) if abs(m - final) > 20.0), default=-1) + print(f"pass {p} {state:4s}: final {final:.1f} mW; level settled by {(off + 1) * WINDOW} s of {len(xs)} " + f"({WINDOW}-sample medians within 20 mW after that); last single sample outside +-{band:.1f} " + f"at {last + 1} s; first 10 s mean {statistics.mean(xs[:10]):.1f} mW") diff --git a/wai/wai-quantum-landscape-fpga/src/axi.rs b/wai/wai-quantum-landscape-fpga/src/axi.rs new file mode 100644 index 000000000..021d44ff7 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/axi.rs @@ -0,0 +1,910 @@ +//! The board's AXI link (`rtl/landscape_axi.v`): the engine's registers on an AXI-Lite port at +//! 0xA000_0000, a write-list DMA that reads bulk loads from DDR, a sequencer that runs a batch of +//! chains in fabric, and a write-back that puts a batch's results in DDR. +//! +//! An AXI access to a programmable-logic address that nothing answers never completes, and it holds +//! the processor until the board is power-cycled. This board is shared and remote, and another +//! session may replace the design. So every access is preceded by a read of the link's signature on +//! EMIO bank 3 (a processor register, which always answers): if the signature is not there, the +//! access is not made. The link itself answers every access within a few clocks whatever the +//! engine is doing (an engine-map access while the DMA or the sequencer holds the engine is +//! dropped and counted, never queued), and this port never makes one: it checks DROPS after every +//! batch. +//! +//! The port is written against two small traits, [`Regs`] and [`Pages`], so that everything but the +//! `/dev/mem` mapping and the page table runs off the board: the tests here drive it against a +//! software link. + +/// The wrapper's registers and RAMs, as word addresses on the link. +pub const WRAP_ID: u16 = 0x8000; +pub const WRAP_ID_VALUE: u32 = 0x4C41_5849; // "LAXI" +pub const WRAP_STATUS: u16 = 0x8001; // [0] sequencer busy [1] DMA busy [2] DMA error [3] write-back busy [4] write-back error +pub const DMA_LO: u16 = 0x8002; +pub const DMA_HI: u16 = 0x8003; +pub const DMA_COUNT: u16 = 0x8004; +pub const DMA_GO: u16 = 0x8005; +pub const DMA_DONE: u16 = 0x8006; +pub const DMA_LEFT: u16 = 0x8007; +pub const WRAP_DROPS: u16 = 0x8008; +pub const WRAP_VERSION: u16 = 0x8009; +pub const WRAP_VERSION_VALUE: u32 = 2; +pub const SEQ_COUNT: u16 = 0x8010; +pub const SEQ_GO: u16 = 0x8011; +pub const SEQ_DONE: u16 = 0x8012; +pub const SEQ_ABORT: u16 = 0x8013; +pub const WB_LO: u16 = 0x8020; +pub const WB_HI: u16 = 0x8021; +pub const WB_FIRST: u16 = 0x8022; +pub const WB_CHAINS: u16 = 0x8023; +pub const WB_GO: u16 = 0x8024; +pub const WB_DONE: u16 = 0x8025; +pub const CHAIN_RAM: u16 = 0x9000; +pub const RESULT_RAM: u16 = 0xA000; +/// Chains the chain RAM holds. +pub const SEQ_MAX: usize = 256; +/// The EMIO signature: bank 3, bits 7:0. +pub const SIGNATURE: u32 = 0xA5; +/// The link's physical address and size. +pub const LITE_BASE: u64 = 0xA000_0000; +pub const LITE_LEN: usize = 0x4_0000; + +pub const ST_SEQ: u32 = 1; +pub const ST_DMA: u32 = 2; +pub const ST_DMA_ERR: u32 = 4; +pub const ST_WB: u32 = 8; +pub const ST_WB_ERR: u32 = 16; +/// Bytes a chain takes in the result RAM and in a write-back: eight words. +pub const WB_CHAIN_BYTES: usize = 32; + +use crate::port::{ChainWords, Error, Port, ResultWords, batch_plain, bulk_plain, err}; +use crate::regs::STATUS; +use std::time::{Duration, Instant}; + +/// A word every result word is set to before a write-back. All ones is the illegal cell pair, so a +/// result the link did not write cannot be taken for one it did. +pub const POISON: u32 = 0xFFFF_FFFF; + +const DATA_3_RO: usize = 0x06C; + +/// A window of 32-bit registers. +pub trait Regs { + fn rd(&self, off: usize) -> u32; + fn wr(&self, off: usize, v: u32); +} + +/// Pages the link reads lists from and writes results to, by physical address. +pub trait Pages { + /// Entries a page holds. + fn per_page(&self) -> usize; + /// The pages for lists; the rest are for write-backs. + fn list_pages(&self) -> usize; + /// Chains a page's write-back holds. + fn chains_per_page(&self) -> usize; + /// The page for write-back number `j` of a batch. + fn result_slot(&self, j: usize) -> usize; + /// The page's physical address, read afresh each time it is used. + fn phys(&self, k: usize) -> Result; + /// A list into page `k`, in DDR when this returns. + fn fill(&self, k: usize, list: &[(u16, u32)]); + /// `chains` results of page `k` set to [`POISON`] and pushed to DDR, nothing left in the caches. + fn poison(&self, k: usize, chains: usize); + /// Whatever the caches hold of page `k` dropped, so the next read is of DDR. + fn forget(&self, k: usize); + /// The six words of `chain` in page `k`. + fn result(&self, k: usize, chain: usize) -> ResultWords; +} + +/// Whether the processor's ports are as the AXI build is made for. See [`port_text`]. +pub fn ports_match(fpd: u32, rd: u32, wr: u32) -> bool { + (fpd >> 8) & 3 == 2 && rd & 3 == 0 && wr & 3 == 0 +} + +/// The processing system's settings for the two ports the link uses, in words: the +/// full-power-domain master's data width (FPD_SLCR AFI_FS, bits 9:8; 2 is 128 bits) and the +/// high-performance port's read and write widths (AFIFM2 RDCTRL and WRCTRL, bits 1:0; 0 is 128 +/// bits). The DMA reads through that port and the write-back writes through it, so both widths count. +pub fn port_text(fpd: u32, rd: u32, wr: u32) -> String { + let w = |v: u32, map: [&'static str; 4]| map[(v & 3) as usize]; + format!( + "FPD_SLCR AFI_FS {fpd:#010x}: M_AXI_HPM0_FPD {} bits; AFIFM2 RDCTRL {rd:#010x} WRCTRL {wr:#010x}: S_AXI_HP0_FPD reads {} bits, writes {} bits (the AXI build is made for 128 on all three)", + w(fpd >> 8, ["32", "64", "128", "?"]), + w(rd, ["128", "64", "32", "?"]), + w(wr, ["128", "64", "32", "?"]) + ) +} + +pub struct AxiPort { + lite: R, + gpio: R, + /// Check the signature before every access (on unless a measurement turns it off). + pub guard: bool, + pub dma: Option, + /// Lists shorter than this go as plain writes. + pub dma_min: usize, + /// Batches go to the sequencer; off, they go as plain accesses (for comparison). + pub sequencer: bool, + pub accesses: u64, + pub dma_lists: u64, + pub batches: u64, + pub write_backs: u64, +} + +impl AxiPort { + /// The link's ID and version over AXI, behind the signature. + pub fn attach(lite: R, gpio: R, dma: Option) -> Result { + let sig = gpio.rd(DATA_3_RO); + if sig & 0xFF != SIGNATURE { + return err(format!( + "the programmable logic does not carry the AXI link's signature (EMIO bank 3 reads {sig:#010x}, want {SIGNATURE:#x} in its low byte), \ + so no AXI address is touched. Load the AXI build first; if it was loaded, another session has replaced it." + )); + } + let mut p = AxiPort { lite, gpio, guard: true, dma: None, dma_min: 32, sequencer: true, accesses: 0, dma_lists: 0, batches: 0, write_backs: 0 }; + let id = p.rd(WRAP_ID)?; + if id != WRAP_ID_VALUE { + return err(format!("the AXI link answers {id:#010x} for its ID, want {WRAP_ID_VALUE:#010x}")); + } + let v = p.rd(WRAP_VERSION)?; + if v != WRAP_VERSION_VALUE { + return err(format!("AXI link version {v}, this host speaks {WRAP_VERSION_VALUE}")); + } + let st = p.rd(WRAP_STATUS)?; + if st & (ST_SEQ | ST_DMA | ST_WB) != 0 { + return err(format!("the AXI link is busy at open (status {st:#x}): another process is using it")); + } + p.wr(WRAP_DROPS, 0)?; + p.dma = dma; + Ok(p) + } + + pub fn name(&self) -> &'static str { + "AXI" + } + + #[inline] + pub fn signature(&self) -> u32 { + self.gpio.rd(DATA_3_RO) + } + + #[inline] + fn check(&self) -> Result<(), Error> { + if self.guard && self.gpio.rd(DATA_3_RO) & 0xFF != SIGNATURE { + return err("the AXI link's signature is gone: another session has replaced the design. Stopped before the next AXI access."); + } + Ok(()) + } + + /// A read of any word on the link, guarded. + #[inline] + pub fn rd(&mut self, word: u16) -> Result { + self.check()?; + self.accesses += 1; + Ok(self.lite.rd(word as usize * 4)) + } + + /// A write of any word on the link, guarded. + #[inline] + pub fn wr(&mut self, word: u16, v: u32) -> Result<(), Error> { + self.check()?; + self.accesses += 1; + self.lite.wr(word as usize * 4, v); + Ok(()) + } + + /// Unguarded, for the latency measurement only. + #[inline] + pub fn rd_raw(&self, word: u16) -> u32 { + self.lite.rd(word as usize * 4) + } + #[inline] + pub fn wr_raw(&self, word: u16, v: u32) { + self.lite.wr(word as usize * 4, v) + } + + fn wait_wrap(&mut self, bits: u32, timeout: Duration, what: &str) -> Result { + let t0 = Instant::now(); + let mut k = 0u32; + loop { + let st = self.rd(WRAP_STATUS)?; + if st & bits == 0 { + return Ok(st); + } + k += 1; + if k % 256 == 0 && t0.elapsed() > timeout { + return err(format!("{what} still busy after {timeout:?} (status {st:#x})")); + } + } + } + + fn pages(&self) -> Result<&D, Error> { + self.dma.as_ref().ok_or_else(|| Error("no DMA pages".into())) + } + + /// A page that moved while the link was using it held nothing the link saw. The kernel may move + /// a locked page; this catches it after the fact (README, what is not done). + fn still_at(&self, slot: usize, pa: u64) -> Result<(), Error> { + let now = self.pages()?.phys(slot)?; + if now != pa { + return err(format!("a DMA page moved from {pa:#x} to {now:#x} during a transfer: what it carried is not kept")); + } + Ok(()) + } + + /// One list of at most a page, by DMA, waited for. + fn dma_page(&mut self, slot: usize, list: &[(u16, u32)], timeout: Duration) -> Result<(), Error> { + let pa = { + let d = self.pages()?; + d.fill(slot, list); + d.phys(slot)? + }; + let before = self.rd(DMA_DONE)?; + self.wr(DMA_LO, pa as u32)?; + self.wr(DMA_HI, (pa >> 32) as u32)?; + self.wr(DMA_COUNT, list.len() as u32)?; + self.wr(DMA_GO, 1)?; + let st = self.wait_wrap(ST_DMA, timeout, "the DMA")?; + if st & ST_DMA_ERR != 0 { + return err(format!("the DMA's read of the list at {pa:#x} came back with an error")); + } + let after = self.rd(DMA_DONE)?; + if after != before.wrapping_add(1) { + return err(format!("the DMA did not run (done count {before} -> {after})")); + } + self.still_at(slot, pa)?; + self.dma_lists += 1; + Ok(()) + } + + /// A write list of any length, a page at a time. + pub fn dma_list(&mut self, list: &[(u16, u32)], timeout: Duration) -> Result<(), Error> { + let (per, pages) = match &self.dma { + Some(d) => (d.per_page(), d.list_pages()), + None => return bulk_plain(self, list), + }; + for (k, chunk) in list.chunks(per).enumerate() { + self.dma_page(k % pages, chunk, timeout)?; + } + Ok(()) + } + + /// The first `chains` results of the result RAM, written back to DDR a page at a time. + pub fn write_back(&mut self, chains: usize, timeout: Duration) -> Result, Error> { + let per = self.pages()?.chains_per_page(); + let mut out = Vec::with_capacity(chains); + for (j, first) in (0..chains).step_by(per).enumerate() { + let n = per.min(chains - first); + let (slot, pa) = { + let d = self.pages()?; + let slot = d.result_slot(j); + d.poison(slot, n); + (slot, d.phys(slot)?) + }; + let before = self.rd(WB_DONE)?; + self.wr(WB_LO, pa as u32)?; + self.wr(WB_HI, (pa >> 32) as u32)?; + self.wr(WB_FIRST, first as u32)?; + self.wr(WB_CHAINS, n as u32)?; + self.wr(WB_GO, 1)?; + let st = self.wait_wrap(ST_WB, timeout, "the write-back")?; + if st & ST_WB_ERR != 0 { + return err(format!("the write-back to {pa:#x} came back with an error")); + } + let after = self.rd(WB_DONE)?; + if after != before.wrapping_add(1) { + return err(format!("the write-back did not run (done count {before} -> {after})")); + } + self.still_at(slot, pa)?; + let d = self.pages()?; + d.forget(slot); + for k in 0..n { + let r = d.result(slot, k); + if r[..4].contains(&POISON) { + return err(format!("the write-back reported done, and chain {} of it still holds what was there before it", first + k)); + } + out.push(r); + } + self.write_backs += 1; + } + Ok(out) + } + + fn drops_zero(&mut self) -> Result<(), Error> { + let d = self.rd(WRAP_DROPS)?; + if d != 0 { + return err(format!("{d} engine accesses were dropped while the link held the engine")); + } + Ok(()) + } +} + +impl Port for AxiPort { + fn write(&mut self, addr: u16, val: u32) -> Result<(), Error> { + if addr >= 0x8000 { + return err(format!("{addr:#06x} is not an engine register")); + } + self.wr(addr, val) + } + fn read(&mut self, addr: u16) -> Result { + if addr >= 0x8000 { + return err(format!("{addr:#06x} is not an engine register")); + } + self.rd(addr) + } + fn wait_idle(&mut self, timeout: Duration) -> Result<(), Error> { + let t0 = Instant::now(); + let mut k = 0u32; + loop { + let st = self.rd(STATUS)?; + if st & 1 == 0 { + return Ok(()); + } + k += 1; + if k % 256 == 0 && t0.elapsed() > timeout { + return err(format!("the engine still busy after {timeout:?} (status {st:#x})")); + } + } + } + fn bulk(&mut self, list: &[(u16, u32)]) -> Result<(), Error> { + if list.len() < self.dma_min || self.dma.is_none() { + return bulk_plain(self, list); + } + self.dma_list(list, Duration::from_secs(5)) + } + fn batch(&mut self, chains: &[ChainWords], timeout: Duration) -> Result, Error> { + if !self.sequencer { + return batch_plain(self, chains, timeout); + } + let mut out = Vec::with_capacity(chains.len()); + for group in chains.chunks(SEQ_MAX) { + let mut list = Vec::with_capacity(group.len() * 6); + for (k, c) in group.iter().enumerate() { + for (i, &w) in c.iter().enumerate() { + list.push((CHAIN_RAM + (8 * k + i) as u16, w)); + } + } + if self.dma.is_some() { + self.dma_list(&list, timeout)?; + } else { + for &(a, v) in &list { + self.wr(a, v)?; + } + } + let before = self.rd(SEQ_DONE)?; + self.wr(SEQ_COUNT, group.len() as u32)?; + self.wr(SEQ_GO, 1)?; + if let Err(e) = self.wait_wrap(ST_SEQ, timeout, "the sequencer") { + let _ = self.wr(SEQ_ABORT, 1); + return Err(e); + } + let after = self.rd(SEQ_DONE)?; + if after.wrapping_sub(before) & 0xFFFF != group.len() as u32 { + return err(format!("the sequencer ran {} chains of {}", after.wrapping_sub(before) & 0xFFFF, group.len())); + } + if self.dma.is_some() { + out.extend(self.write_back(group.len(), timeout)?); + } else { + for k in 0..group.len() { + let mut r = [0u32; 6]; + for (i, w) in r.iter_mut().enumerate() { + *w = self.rd(RESULT_RAM + (8 * k + i) as u16)?; + } + out.push(r); + } + } + self.drops_zero()?; + self.batches += 1; + } + Ok(out) + } +} + +#[cfg(target_os = "linux")] +pub use board_side::*; + +/// What only the board has: `/dev/mem` and the page table. +#[cfg(target_os = "linux")] +mod board_side { + use super::*; + use crate::emio::Mem; + use std::fs::File; + use std::os::unix::fs::FileExt; + + const GPIO_BASE: u64 = 0xFF0A_0000; + + unsafe extern "C" { + fn mmap(addr: *mut u8, len: usize, prot: i32, flags: i32, fd: i32, off: i64) -> *mut u8; + fn munmap(addr: *mut u8, len: usize) -> i32; + fn sysconf(name: i32) -> i64; + } + const PROT_RW: i32 = 1 | 2; + const MAP_PRIVATE: i32 = 0x02; + const MAP_ANONYMOUS: i32 = 0x20; + const MAP_LOCKED: i32 = 0x2000; + const MAP_POPULATE: i32 = 0x8000; + const SC_PAGESIZE: i32 = 30; + + impl Regs for Mem { + #[inline] + fn rd(&self, off: usize) -> u32 { + Mem::rd(self, off) + } + #[inline] + fn wr(&self, off: usize, v: u32) { + Mem::wr(self, off, v) + } + } + + /// The data cache's line size, from CTR_EL0. + #[cfg(target_arch = "aarch64")] + fn dline() -> usize { + let ctr: u64; + unsafe { core::arch::asm!("mrs {0}, ctr_el0", out(reg) ctr) }; + 4 << ((ctr >> 16) & 0xF) + } + + /// Cleans `len` bytes from `p` to the point of coherency: the DMA port is not coherent with the + /// processor's caches, so a list the processor wrote must be in DDR before the link reads it. + #[cfg(target_arch = "aarch64")] + fn clean(p: *const u8, len: usize) { + let line = dline(); + let mut a = p as usize & !(line - 1); + let end = p as usize + len; + while a < end { + unsafe { core::arch::asm!("dc cvac, {0}", in(reg) a) }; + a += line; + } + unsafe { core::arch::asm!("dsb sy") }; + } + #[cfg(not(target_arch = "aarch64"))] + fn clean(_p: *const u8, _len: usize) {} + + /// Cleans and invalidates `len` bytes from `p`: before a write-back, so nothing in the caches + /// lands on what the link writes, and after it, so the processor reads DDR and not a line it + /// fetched meanwhile. + #[cfg(target_arch = "aarch64")] + fn flush(p: *const u8, len: usize) { + let line = dline(); + let mut a = p as usize & !(line - 1); + let end = p as usize + len; + while a < end { + unsafe { core::arch::asm!("dc civac, {0}", in(reg) a) }; + a += line; + } + unsafe { core::arch::asm!("dsb sy") }; + } + #[cfg(not(target_arch = "aarch64"))] + fn flush(_p: *const u8, _len: usize) {} + + /// Locked pages for write lists and results, and their physical addresses from + /// /proc/self/pagemap (root). Locked is not pinned: the kernel may still move such a page, and + /// a kernel-owned buffer is what would rule that out (README, what is not done). + pub struct Dma { + buf: *mut u8, + pages: usize, + page: usize, + pagemap: File, + } + + impl Dma { + pub fn new(pages: usize) -> Result { + let page = unsafe { sysconf(SC_PAGESIZE) } as usize; + if !(4096..=65536).contains(&page) { + return err(format!("page size {page}")); + } + let len = pages * page; + let buf = unsafe { mmap(std::ptr::null_mut(), len, PROT_RW, MAP_PRIVATE | MAP_ANONYMOUS | MAP_LOCKED | MAP_POPULATE, -1, 0) }; + if buf as isize == -1 || buf.is_null() { + return err("could not lock pages for the DMA's lists"); + } + let pagemap = File::open("/proc/self/pagemap").map_err(|e| Error(format!("/proc/self/pagemap: {e}")))?; + let d = Dma { buf, pages, page, pagemap }; + for k in 0..pages { + d.phys(k)?; + } + Ok(d) + } + } + + impl Pages for Dma { + fn per_page(&self) -> usize { + self.page / 8 + } + fn list_pages(&self) -> usize { + self.pages - 2 + } + fn chains_per_page(&self) -> usize { + self.page / WB_CHAIN_BYTES + } + fn result_slot(&self, j: usize) -> usize { + self.pages - 1 - j % 2 + } + fn phys(&self, k: usize) -> Result { + let va = self.buf as usize + k * self.page; + let mut e = [0u8; 8]; + self.pagemap.read_exact_at(&mut e, (va / self.page * 8) as u64).map_err(|x| Error(format!("pagemap: {x}")))?; + let e = u64::from_le_bytes(e); + let pfn = e & ((1 << 55) - 1); + if e >> 63 == 0 || pfn == 0 { + return err("no physical address for a DMA page (run as root)"); + } + Ok(pfn * self.page as u64) + } + fn fill(&self, k: usize, list: &[(u16, u32)]) { + let p = unsafe { self.buf.add(k * self.page) } as *mut u64; + for (i, &(a, v)) in list.iter().enumerate() { + unsafe { std::ptr::write_volatile(p.add(i), ((a as u64) << 32) | v as u64) }; + } + clean(p as *const u8, list.len() * 8); + } + fn poison(&self, k: usize, chains: usize) { + let p = unsafe { self.buf.add(k * self.page) } as *mut u32; + for i in 0..chains * WB_CHAIN_BYTES / 4 { + unsafe { std::ptr::write_volatile(p.add(i), POISON) }; + } + flush(p as *const u8, self.page); + } + fn forget(&self, k: usize) { + flush(unsafe { self.buf.add(k * self.page) }, self.page); + } + fn result(&self, k: usize, chain: usize) -> ResultWords { + let p = unsafe { self.buf.add(k * self.page + chain * WB_CHAIN_BYTES) } as *const u32; + let mut r = [0u32; 6]; + for (i, w) in r.iter_mut().enumerate() { + *w = unsafe { std::ptr::read_volatile(p.add(i)) }; + } + r + } + } + + impl Drop for Dma { + fn drop(&mut self) { + unsafe { + munmap(self.buf, self.pages * self.page); + } + } + } + + pub type BoardAxi = AxiPort; + + /// Whether the loaded design carries the AXI link's signature: a GPIO read, safe whatever is loaded. + pub fn signature_present() -> bool { + Mem::map(GPIO_BASE, 0x1000).map(|g| g.rd(DATA_3_RO) & 0xFF == SIGNATURE).unwrap_or(false) + } + + /// The two ports' widths as the board's boot left them (read only; loading a bitstream through + /// the FPGA manager does not change them): whether they match, and the sentence that says so. + pub fn ps_ports() -> Result<(bool, String), Error> { + let fpd = Mem::map(0xFD61_5000, 0x1000)?.rd(0); + let afi = Mem::map(0xFD38_0000, 0x1000)?; + let (rd, wr) = (afi.rd(0x000), afi.rd(0x014)); + Ok((ports_match(fpd, rd, wr), port_text(fpd, rd, wr))) + } + + /// Opens the board's link: the signature and the port widths first, both by registers that always + /// answer, then the wrapper's ID and version over AXI. + pub fn open() -> Result { + let gpio = Mem::map(GPIO_BASE, 0x1000)?; + let sig = gpio.rd(DATA_3_RO); + if sig & 0xFF != SIGNATURE { + return err(format!( + "the programmable logic does not carry the AXI link's signature (EMIO bank 3 reads {sig:#010x}, want {SIGNATURE:#x} in its low byte), \ + so no AXI address is touched. Load the AXI build first; if it was loaded, another session has replaced it." + )); + } + let (ok, text) = ps_ports()?; + if !ok { + return err(format!("the processing system's ports are not set as the AXI build needs, so no AXI address is touched: {text}")); + } + let lite = Mem::map(LITE_BASE, LITE_LEN)?; + AxiPort::attach(lite, gpio, Some(Dma::new(16)?)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::conform::bits; + use crate::engine::Engine; + use crate::member::{BoardInfo, BoardMember}; + use crate::model::ModelPort; + use crate::port::batch_plain; + use std::cell::RefCell; + use std::rc::Rc; + + const PAGE: usize = 4096; + const BASE: u64 = 0x1000_0000; + + /// The link in software: the wrapper's registers and RAMs, over the model of the engine, with + /// its DMA and write-back working on [`FakePages`]. What a test wants broken, it sets here. + struct Link { + model: ModelPort, + pages: Rc>>>, + signature: u32, + chain_ram: Vec, + result_ram: Vec, + regs: std::collections::HashMap, + dma_done: u32, + seq_done: u32, + wb_done: u32, + drops: u32, + lite_accesses: u64, + // faults + wb_writes_nothing: bool, + seq_loses_one: bool, + wb_swaps_chains: bool, + } + + impl Link { + fn reg(&self, a: u16) -> u32 { + self.regs.get(&a).copied().unwrap_or(0) + } + fn word(&self, addr: u64) -> usize { + (addr - BASE) as usize + } + fn write(&mut self, a: u16, v: u32) { + match a { + DMA_GO => { + let at = self.word(((self.reg(DMA_HI) as u64) << 32) | self.reg(DMA_LO) as u64); + for i in 0..self.reg(DMA_COUNT) as usize { + let e = u64::from_le_bytes(self.pages.borrow()[at / PAGE][at % PAGE + 8 * i..at % PAGE + 8 * i + 8].try_into().unwrap()); + let (ea, ev) = ((e >> 32) as u16, e as u32); + if ea >= CHAIN_RAM { + self.chain_ram[(ea - CHAIN_RAM) as usize] = ev; + } else { + self.model.write(ea, ev).unwrap(); + } + } + self.dma_done += 1; + } + SEQ_GO => { + let n = self.reg(SEQ_COUNT) as usize; + let chains: Vec = (0..n).map(|k| std::array::from_fn(|i| self.chain_ram[8 * k + i])).collect(); + for (k, r) in batch_plain(&mut self.model, &chains, Duration::from_secs(1)).unwrap().iter().enumerate() { + self.result_ram[8 * k..8 * k + 6].copy_from_slice(r); + } + self.seq_done += (n - usize::from(self.seq_loses_one)) as u32; + } + WB_GO => { + let at = self.word(((self.reg(WB_HI) as u64) << 32) | self.reg(WB_LO) as u64); + if !self.wb_writes_nothing { + let first = self.reg(WB_FIRST) as usize; + for k in 0..self.reg(WB_CHAINS) as usize { + let from = if self.wb_swaps_chains { k ^ 1 } else { k }; + for i in 0..8 { + let w = self.result_ram[8 * (first + from) + i]; + let o = at % PAGE + k * WB_CHAIN_BYTES + 4 * i; + self.pages.borrow_mut()[at / PAGE][o..o + 4].copy_from_slice(&w.to_le_bytes()); + } + } + } + self.wb_done += 1; + } + WRAP_DROPS => self.drops = 0, + a if a < 0x8000 => self.model.write(a, v).unwrap(), + a if (CHAIN_RAM..CHAIN_RAM + 0x800).contains(&a) => self.chain_ram[(a - CHAIN_RAM) as usize] = v, + a => { + self.regs.insert(a, v); + } + } + } + fn read(&mut self, a: u16) -> u32 { + match a { + WRAP_ID => WRAP_ID_VALUE, + WRAP_VERSION => WRAP_VERSION_VALUE, + WRAP_STATUS => 0, + DMA_DONE => self.dma_done, + SEQ_DONE => self.seq_done, + WB_DONE => self.wb_done, + WRAP_DROPS => self.drops, + a if a < 0x8000 => self.model.read(a).unwrap(), + a if (RESULT_RAM..RESULT_RAM + 0x800).contains(&a) => self.result_ram[(a - RESULT_RAM) as usize], + a => self.reg(a), + } + } + } + + #[derive(Clone)] + struct Bus { + link: Rc>, + gpio: bool, + } + + impl Regs for Bus { + fn rd(&self, off: usize) -> u32 { + let mut l = self.link.borrow_mut(); + if self.gpio { + return l.signature; + } + l.lite_accesses += 1; + l.read((off / 4) as u16) + } + fn wr(&self, off: usize, v: u32) { + assert!(!self.gpio); + let mut l = self.link.borrow_mut(); + l.lite_accesses += 1; + l.write((off / 4) as u16, v); + } + } + + struct FakePages { + pages: Rc>>>, + /// Whether the kernel moves a page between the address's two reads. + moves: std::cell::Cell, + reads: std::cell::Cell, + } + + impl Pages for FakePages { + fn per_page(&self) -> usize { + PAGE / 8 + } + fn list_pages(&self) -> usize { + self.pages.borrow().len() - 2 + } + fn chains_per_page(&self) -> usize { + PAGE / WB_CHAIN_BYTES + } + fn result_slot(&self, j: usize) -> usize { + self.pages.borrow().len() - 1 - j % 2 + } + fn phys(&self, k: usize) -> Result { + self.reads.set(self.reads.get() + 1); + let moved = self.moves.get() && self.reads.get() % 2 == 0; + Ok(BASE + (k * PAGE) as u64 + if moved { 0x100_0000 } else { 0 }) + } + fn fill(&self, k: usize, list: &[(u16, u32)]) { + for (i, &(a, v)) in list.iter().enumerate() { + self.pages.borrow_mut()[k][8 * i..8 * i + 8].copy_from_slice(&(((a as u64) << 32) | v as u64).to_le_bytes()); + } + } + fn poison(&self, k: usize, chains: usize) { + self.pages.borrow_mut()[k][..chains * WB_CHAIN_BYTES].fill(0xFF); + } + fn forget(&self, _k: usize) {} + fn result(&self, k: usize, chain: usize) -> ResultWords { + let p = self.pages.borrow(); + std::array::from_fn(|i| { + let o = chain * WB_CHAIN_BYTES + 4 * i; + u32::from_le_bytes(p[k][o..o + 4].try_into().unwrap()) + }) + } + } + + type FakePort = AxiPort; + + fn fake() -> (FakePort, Rc>) { + let pages = Rc::new(RefCell::new(vec![vec![0u8; PAGE]; 16])); + let link = Rc::new(RefCell::new(Link { + model: ModelPort::new(), + pages: pages.clone(), + signature: SIGNATURE, + chain_ram: vec![0; 2048], + result_ram: vec![0; 2048], + regs: Default::default(), + dma_done: 0, + seq_done: 0, + wb_done: 0, + drops: 0, + lite_accesses: 0, + wb_writes_nothing: false, + seq_loses_one: false, + wb_swaps_chains: false, + })); + let p = AxiPort::attach(Bus { link: link.clone(), gpio: false }, Bus { link: link.clone(), gpio: true }, Some(FakePages { pages, moves: Default::default(), reads: Default::default() })).unwrap(); + (p, link) + } + + fn chains(n: u32) -> Vec { + (0..n).map(|k| [k & 1, 0, 0, 0, k, 0]).collect() + } + + /// A one-cell job through the port, set up by plain accesses. + fn set_up(p: &mut FakePort) { + p.write(crate::regs::MODE, crate::regs::MODE_T0).unwrap(); + p.write(crate::regs::BOUND, 3).unwrap(); + } + + #[test] + fn the_port_gives_the_model_s_bits_through_dma_sequencer_and_write_back() { + let (p, link) = fake(); + let m = BoardMember::new(Engine::open(p).unwrap(), BoardInfo::default()); + let b = bits(&m).unwrap(); + assert!(b.settle_ok && b.chains_ok, "{}", b.text); + let e = m.engine.borrow(); + assert!(e.port.dma_lists > 0 && e.port.batches > 0 && e.port.write_backs > 0, "{} {} {}", e.port.dma_lists, e.port.batches, e.port.write_backs); + assert_eq!(link.borrow().drops, 0); + } + + #[test] + fn more_chains_than_a_page_holds_come_back_in_order() { + let (mut p, _) = fake(); + set_up(&mut p); + let got = p.batch(&chains(300), Duration::from_secs(1)).unwrap(); + assert_eq!(got.len(), 300); + let (mut q, _) = fake(); + set_up(&mut q); + q.sequencer = false; + assert_eq!(got, q.batch(&chains(300), Duration::from_secs(1)).unwrap()); + } + + #[test] + fn no_access_is_made_without_the_signature() { + let (mut p, link) = fake(); + let before = link.borrow().lite_accesses; + link.borrow_mut().signature = 0; + assert!(p.rd(WRAP_ID).is_err()); + assert!(p.wr(DMA_COUNT, 1).is_err()); + assert!(p.read(crate::regs::ID).is_err()); + assert_eq!(link.borrow().lite_accesses, before); + } + + #[test] + fn a_design_without_the_signature_is_not_touched_at_open() { + let (p, link) = fake(); + drop(p); + link.borrow_mut().signature = 0; + let before = link.borrow().lite_accesses; + let lite = Bus { link: link.clone(), gpio: false }; + let gpio = Bus { link: link.clone(), gpio: true }; + assert!(AxiPort::::attach(lite, gpio, None).is_err()); + assert_eq!(link.borrow().lite_accesses, before); + } + + #[test] + fn a_write_back_that_wrote_nothing_is_caught() { + let (mut p, link) = fake(); + set_up(&mut p); + p.batch(&chains(4), Duration::from_secs(1)).unwrap(); + // the page still holds the last batch's good results; the poison is what shows + link.borrow_mut().wb_writes_nothing = true; + let e = p.batch(&chains(4), Duration::from_secs(1)).expect_err("stale results"); + assert!(e.0.contains("still holds"), "{}", e.0); + } + + #[test] + fn a_write_back_out_of_place_changes_the_result() { + let (mut p, _) = fake(); + set_up(&mut p); + let good = p.batch(&chains(4), Duration::from_secs(1)).unwrap(); + let (mut q, link) = fake(); + set_up(&mut q); + link.borrow_mut().wb_swaps_chains = true; + assert_ne!(good, q.batch(&chains(4), Duration::from_secs(1)).unwrap()); + } + + #[test] + fn a_page_that_moved_during_a_transfer_is_an_error() { + let (mut p, _) = fake(); + set_up(&mut p); + let d = p.dma.as_ref().unwrap(); + d.reads.set(0); + d.moves.set(true); + let e = p.batch(&chains(4), Duration::from_secs(1)).expect_err("a moved page"); + assert!(e.0.contains("moved"), "{}", e.0); + } + + #[test] + fn a_short_sequencer_run_is_an_error() { + let (mut p, link) = fake(); + set_up(&mut p); + link.borrow_mut().seq_loses_one = true; + let e = p.batch(&chains(4), Duration::from_secs(1)).expect_err("a chain short"); + assert!(e.0.contains("the sequencer ran"), "{}", e.0); + } + + #[test] + fn a_dropped_access_is_an_error() { + let (mut p, link) = fake(); + set_up(&mut p); + link.borrow_mut().drops = 1; + let e = p.batch(&chains(2), Duration::from_secs(1)).expect_err("a dropped access"); + assert!(e.0.contains("dropped"), "{}", e.0); + } + + #[test] + fn the_link_s_port_widths_are_all_three() { + assert!(ports_match(0xa00, 0x3b0, 0x3b0)); + assert!(!ports_match(0x000, 0x3b0, 0x3b0), "the master at 32 bits"); + assert!(!ports_match(0xa00, 0x3b1, 0x3b0), "reads at 64 bits"); + assert!(!ports_match(0xa00, 0x3b0, 0x3b1), "writes at 64 bits"); + } +} diff --git a/wai/wai-quantum-landscape-fpga/src/board.rs b/wai/wai-quantum-landscape-fpga/src/board.rs new file mode 100644 index 000000000..9aa6e1a1a --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/board.rs @@ -0,0 +1,200 @@ +//! Board housekeeping: loading the bitstream and proving the load took, the PL clock, the power +//! sensor, the single-tenant lock, and the checks that another session has not touched the PL. + +use crate::emio::Mem; +use crate::port::{Error, err}; +use std::fs; +use std::process::Command; + +pub const FPGA: &str = "/sys/class/fpga_manager/fpga0"; +const CRL_BASE: u64 = 0xFF5E_0000; +const PL0_REF_CTRL: usize = 0xC0; + +pub fn dmesg_fpga_writes() -> Result, Error> { + let out = Command::new("dmesg").output().map_err(|e| Error(format!("dmesg: {e}")))?; + Ok(String::from_utf8_lossy(&out.stdout) + .lines() + .filter(|l| l.contains("writing") && l.contains("FPGA")) + .map(|l| l.to_string()) + .collect()) +} + +/// This process and every process it descends from: a campaign script's own command line may match +/// the patterns below (its arguments name the vehicles it runs), and it is not another session. +fn ancestors() -> Vec { + let mut out = Vec::new(); + let mut pid = std::process::id(); + while pid > 1 && out.len() < 64 { + out.push(pid); + let stat = fs::read_to_string(format!("/proc/{pid}/stat")).unwrap_or_default(); + // the fields after the command's closing parenthesis: state, then the parent's id + pid = stat.rsplit_once(')').and_then(|(_, rest)| rest.split_whitespace().nth(1)).and_then(|v| v.parse().ok()).unwrap_or(0); + } + out +} + +/// What counts as another session: this tool, the two scripts that drive it, and the vendor's +/// loader. A site adds its own in `WAI_QUANTUM_LANDSCAPE_FPGA_FOREIGN`, an extended regex: on a +/// shared board, the names the other sessions' tools go by. +pub fn foreign_pattern(site: Option<&str>) -> String { + let own = "wai-quantum-landscape-fpga|run_all\\.sh|power_campaign\\.sh|fpgautil"; + match site { + Some(s) if !s.is_empty() => format!("{own}|{s}"), + _ => own.to_string(), + } +} + +/// The lines of `pgrep -af` that are another session's: not the search itself, and not this process +/// or anything it descends from. Another run of this tool counts: its lock does not stop a reload +/// by something else, and a queued job is still a job. +pub fn foreign_lines(pgrep: &str, mine: &[u32]) -> String { + pgrep + .lines() + .filter(|l| !l.contains("pgrep")) + .filter(|l| l.split_whitespace().next().and_then(|p| p.parse::().ok()).is_none_or(|p| !mine.contains(&p))) + .collect::>() + .join("\n") +} + +/// Processes that mean another session is flashing or measuring. +pub fn foreign_sessions() -> String { + let pat = foreign_pattern(std::env::var("WAI_QUANTUM_LANDSCAPE_FPGA_FOREIGN").ok().as_deref()); + let out = Command::new("pgrep").arg("-af").arg(&pat).output(); + let mine = ancestors(); + out.map(|o| foreign_lines(&String::from_utf8_lossy(&o.stdout), &mine)).unwrap_or_default() +} + +/// Loads a bitstream through the FPGA manager and proves the load by its dmesg line. The caller +/// holds [`lock`]: a reload must wait for the job that holds the board. +pub fn load_bitstream(path: &str, _held: &Lock) -> Result { + let f = foreign_sessions(); + if !f.is_empty() { + return err(format!("another session is active on the board, not loading:\n{f}")); + } + let flags = fs::read_to_string(format!("{FPGA}/flags")).unwrap_or_default(); + if flags.trim() != "0" { + return err(format!("fpga manager flags = {} (want 0)", flags.trim())); + } + let name = std::path::Path::new(path).file_name().and_then(|s| s.to_str()).ok_or_else(|| Error("bad path".into()))?.to_string(); + let fw = format!("/lib/firmware/{name}"); + if std::path::Path::new(path) != std::path::Path::new(&fw) { + fs::copy(path, &fw).map_err(|e| Error(format!("copy to {fw}: {e}")))?; + } + let before = dmesg_fpga_writes()?.iter().filter(|l| l.contains(&format!("writing {name} "))).count(); + fs::write(format!("{FPGA}/firmware"), &name).map_err(|e| Error(format!("fpga manager: {e}")))?; + std::thread::sleep(std::time::Duration::from_secs(3)); + let w = dmesg_fpga_writes()?; + let after = w.iter().filter(|l| l.contains(&format!("writing {name} "))).count(); + if after <= before { + return err(format!("LOAD-NOOP: no new dmesg line for {name}; the old design is still running")); + } + let last = w.last().cloned().unwrap_or_default(); + if last.contains("fail") || last.contains("error") { + return err(format!("load reported an error: {last}")); + } + Ok(last) +} + +/// pl_clk0 = IOPLL / div0 / div1. Returns (raw register, MHz) assuming the 1500 MHz source this +/// board's IOPLL runs at; the engine's uptime counter checks it by behaviour. +pub fn pl0_ctrl() -> Result<(u32, f64), Error> { + let m = Mem::map(CRL_BASE, 0x1000)?; + let v = m.rd(PL0_REF_CTRL); + let d0 = ((v >> 8) & 0x3F).max(1); + let d1 = ((v >> 16) & 0x3F).max(1); + Ok((v, 1500.0 / (d0 * d1) as f64)) +} + +/// Sets div0 for pl_clk0 (div1 = 1). 15 -> 100 MHz. Returns the previous register value. +pub fn set_pl0_div(div0: u32) -> Result { + if !(4..=63).contains(&div0) { + return err("div0 must be 4..63"); + } + let m = Mem::map(CRL_BASE, 0x1000)?; + let old = m.rd(PL0_REF_CTRL); + let new = (old & !(0x3F << 8) & !(0x3F << 16)) | (div0 << 8) | (1 << 16) | (1 << 24); + m.wr(PL0_REF_CTRL, new); + Ok(old) +} + +pub fn restore_pl0(v: u32) -> Result<(), Error> { + let m = Mem::map(CRL_BASE, 0x1000)?; + m.wr(PL0_REF_CTRL, v); + Ok(()) +} + +pub fn find_power_sensor() -> Result { + for e in fs::read_dir("/sys/class/hwmon").map_err(|e| Error(e.to_string()))?.flatten() { + let p = e.path(); + if fs::read_to_string(p.join("name")).map(|s| s.trim() == "ina260_u14").unwrap_or(false) { + return Ok(p.join("power1_input").to_string_lossy().to_string()); + } + } + err("no ina260_u14 power sensor") +} + +pub fn read_uw(path: &str) -> Result { + fs::read_to_string(path).map_err(|e| Error(e.to_string()))?.trim().parse::().map_err(|e| Error(e.to_string())) +} + +unsafe extern "C" { + fn flock(fd: i32, op: i32) -> i32; +} + +/// The board is single-tenant: jobs queue on this lock, in the order the kernel grants it. +pub struct Lock(#[allow(dead_code)] fs::File); +pub fn lock() -> Result { + use std::os::unix::io::AsRawFd; + let f = fs::OpenOptions::new().create(true).write(true).truncate(false).open("/run/lock/wai-quantum-landscape-fpga.lock") + .or_else(|_| fs::OpenOptions::new().create(true).write(true).truncate(false).open("/tmp/wai-quantum-landscape-fpga.lock")) + .map_err(|e| Error(format!("lock file: {e}")))?; + if unsafe { flock(f.as_raw_fd(), 2) } != 0 { + return err("flock failed"); + } + Ok(Lock(f)) +} + +#[cfg(test)] +mod tests { + use super::*; + + const PGREP: &str = "101 sudo ./wai-quantum-landscape-fpga conform\n102 ./wai-quantum-landscape-fpga conform\n200 sh power_campaign.sh out\n300 ./wai-quantum-landscape-fpga load x.bit.bin\n301 pgrep -af wai-quantum-landscape-fpga"; + + #[test] + fn another_run_of_this_tool_is_seen() { + let f = foreign_lines(PGREP, &[300]); + assert!(f.contains("102 ./wai-quantum-landscape-fpga conform"), "{f}"); + assert!(f.contains("200 sh power_campaign.sh"), "{f}"); + } + + #[test] + fn this_process_its_parents_and_the_search_are_not() { + let f = foreign_lines(PGREP, &[300, 200, 101, 102]); + assert_eq!(f, ""); + } + + #[test] + fn the_pattern_names_this_tool_whatever_a_site_adds() { + assert!(foreign_pattern(None).contains("wai-quantum-landscape-fpga")); + let p = foreign_pattern(Some("their_tool")); + assert!(p.contains("wai-quantum-landscape-fpga") && p.ends_with("|their_tool"), "{p}"); + } + + #[test] + fn the_lock_serialises_two_holders() { + // two opens of one lock file in one process: the second must wait for the first to drop + use std::sync::mpsc::channel; + use std::time::Duration; + let first = lock().unwrap(); + let (tx, rx) = channel(); + let t = std::thread::spawn(move || { + let l = lock().unwrap(); + tx.send(()).unwrap(); + drop(l); + }); + assert!(rx.recv_timeout(Duration::from_millis(200)).is_err(), "the second holder did not wait"); + drop(first); + rx.recv_timeout(Duration::from_secs(5)).unwrap(); + t.join().unwrap(); + } +} diff --git a/wai/wai-quantum-landscape-fpga/src/conform.rs b/wai/wai-quantum-landscape-fpga/src/conform.rs new file mode 100644 index 000000000..2eff51609 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/conform.rs @@ -0,0 +1,407 @@ +//! The checks, written once against any port: the board's, the model's, or the testbench recording. +//! +//! - [`bits`]: the conformance set's `settle` and `chains` cases, which a bit-exact kernel gives +//! exactly, case by case; the host's certification (`member::certify`) runs the same cases. +//! - [`full`]: those; the `cells` cut points as the host computes them, and draws of single cells +//! on the device against the reference's, draw for draw and by frequency; the statistical +//! battery, and the all-at-once control it must catch; the `jobs` requests; random settles up +//! to 64 cells. +//! - [`agree`]: every worked example over many seeds, at its own temperature and at 0, on the board +//! and on the CPU reference, answer for answer. + +use crate::engine::Loaded; +use crate::member::{BoardMember, VECTORS, beyond, lowered, plan, run_schedule}; +use crate::port::Port; +use crate::regs::*; +use serde_json::{Value, json}; +use std::fmt::Write as _; +use wai_quantum::quantum_landscape::conformance::{MUST_TAKE_FIELD_BOUND, battery, chain_cases, run_battery, settle_cases}; +use wai_quantum::quantum_landscape::energy::Landscape; +use wai_quantum::quantum_landscape::member::{Certified, Chain, Member, check_chain, check_settle, named}; +use wai_quantum::quantum_landscape::program::read; +use wai_quantum::quantum_landscape::run::{Job, run_on}; +use wai_quantum::quantum_landscape::sample::{anneal_with, cell, chain_seed, cuts, schedule}; +use wai_quantum::quantum_landscape::settle::Workload; +use wai_quantum::quantum_landscape::{EXAMPLES, MAX_JOB_BYTES, job}; + +#[derive(Default)] +pub struct Report { + pub text: String, + pub failures: Vec, + pub checks: usize, +} + +impl Report { + pub fn line(&mut self, s: impl AsRef) { + self.text.push_str(s.as_ref()); + self.text.push('\n'); + } + pub fn check(&mut self, ok: bool, what: impl Into) { + let w = what.into(); + self.checks += 1; + let _ = writeln!(self.text, " [{}] {}", if ok { "PASS" } else { "FAIL" }, w); + if !ok { + self.failures.push(w); + } + } +} + +pub struct Bits { + /// Every settle case the engine can hold gave the reference's bits, and every one it cannot + /// failed with a sentence. + pub settle_ok: bool, + pub chains_ok: bool, + /// Cases beyond the engine's capacity, by name (`member::beyond`): the spec does not let a + /// member decline them, so each costs the kernel its certificate. + pub settle_beyond: Vec, + pub chains_beyond: Vec, + pub text: String, +} + +fn vectors() -> Value { + serde_json::from_str(VECTORS).expect("the conformance set is JSON") +} + +/// The `settle` and `chains` cases on the member, case by case, each answer also held to the job +/// (`check_settle`, `check_chain`): what the host's certification grades. +pub fn bits(m: &BoardMember

) -> Result { + let mut text = String::new(); + let may_decline = |w: &Workload| w.field_bound() > MUST_TAKE_FIELD_BOUND; + let (mut s_ok, mut s_n, mut s_declined, mut s_wrong) = (0, 0, 0, 0); + let mut settle_beyond = Vec::new(); + for c in settle_cases() { + let w = c.landscape.lower(); + if m.takes(&w, false).is_err() && may_decline(&w) { + s_declined += 1; + continue; + } + let want = w.settle(&c.start, c.bound); + let got = m.settle(&w, &c.start, c.bound); + if let Some(why) = beyond(&w, &[]) { + match got { + Err(_) => settle_beyond.push(format!("{} ({why})", c.name)), + Ok(_) => { + s_wrong += 1; + let _ = writeln!(text, " settle {}: beyond the engine ({why}), and it answered anyway", c.name); + } + } + continue; + } + s_n += 1; + match got { + Ok(o) if o == want && check_settle(&o, &w, c.bound).is_ok() => s_ok += 1, + Ok(o) => { + s_wrong += 1; + let _ = writeln!(text, " settle {}: got {:?}, want {:?}", c.name, o, want); + } + Err(e) => { + s_wrong += 1; + let _ = writeln!(text, " settle {}: {e}", c.name); + } + } + } + let (mut c_ok, mut c_n, mut c_declined, mut c_wrong) = (0, 0, 0, 0); + let mut chains_beyond = Vec::new(); + for c in chain_cases() { + let w = c.landscape.lower(); + let temps = c.temperatures.each(); + let chains = c.chains(); + if m.takes(&w, temps.iter().any(|&t| t > 0.0)).is_err() && may_decline(&w) { + c_declined += chains.len(); + continue; + } + let got = m.chains(&w, &chains, &temps); + if let Some(why) = beyond(&w, &temps) { + match got { + Err(_) => chains_beyond.push(format!("{} ({why})", c.name)), + Ok(_) => { + c_wrong += 1; + let _ = writeln!(text, " chains {}: beyond the engine ({why}), and it answered anyway", c.name); + } + } + continue; + } + c_n += chains.len(); + let want: Vec<_> = chains.iter().map(|ch| anneal_with(&w, &ch.start, &temps, ch.seed)).collect(); + match got { + Ok(got) => { + for (g, wnt) in got.iter().zip(&want) { + if g == wnt && check_chain(g, &w, &temps).is_ok() { + c_ok += 1; + } else { + c_wrong += 1; + let _ = writeln!(text, " chain {}: got {:?}, want {:?}", c.name, g.state, wnt.state); + } + } + } + Err(e) => { + c_wrong += 1; + let _ = writeln!(text, " chains {}: {e}", c.name); + } + } + } + let _ = writeln!( + text, + "settle cases the engine holds: {s_ok}/{s_n} bit for bit; {} beyond its capacity; {s_declined} declined, as the spec lets a member", + settle_beyond.len() + ); + let _ = writeln!( + text, + "chains the engine holds: {c_ok}/{c_n} bit for bit; {} cases beyond its capacity; {c_declined} chains declined, as the spec lets a member", + chains_beyond.len() + ); + for b in settle_beyond.iter().chain(&chains_beyond) { + let _ = writeln!(text, " beyond the engine: {b}"); + } + Ok(Bits { settle_ok: s_wrong == 0 && s_ok == s_n, chains_ok: c_wrong == 0 && c_ok == c_n, settle_beyond, chains_beyond, text }) +} + +/// `count` chains of one cell, one sweep each at temperature `t`, chain `r` with the seed +/// `chain_seed(seed, r)`: each final state is one draw of the device's, the first of its stream. +fn cell_draws(m: &BoardMember

, l: &Loaded, t: f64, seed: u64, count: u64) -> Result, String> { + let segs = plan(l, &[t])?; + let mut e = m.engine.borrow_mut(); + e.load(l).map_err(|e| e.0)?; + let mut out = Vec::with_capacity(count as usize); + let mut r0 = 0u64; + while r0 < count { + let r1 = (r0 + 4096).min(count); + let list: Vec<(Vec, u64)> = (r0..r1).map(|r| (vec![0], chain_seed(seed, r))).collect(); + out.extend(run_schedule(&mut e, l, &segs, false, &list, 0, MODE_GIBBS)?.into_iter().map(|s| s[0])); + r0 = r1; + } + Ok(out) +} + +/// Every check, at `scale` times the draw counts. +pub fn full(m: &BoardMember

, scale: f64) -> Result { + let f = vectors(); + let mut rep = Report::default(); + let b = bits(m)?; + rep.line("wai.quantum.landscape/1 member tests (quantum-conformance/landscape/vectors.json)"); + rep.text.push_str(&b.text); + rep.check(b.settle_ok, "settle kernel: every settle case the engine holds, bit for bit (state, sweeps, ending, accumulates), each held to the job; every one it cannot hold refused"); + rep.check(b.chains_ok, "sample kernel: every chain vector the engine holds, bit for bit (the state from the device; sweeps, ending, accumulates and draws by the schedule, as check_chain fixes them), each held to the job; every one it cannot hold refused"); + + // the cut points the host gives the engine, against the set's + let cells = f["cells"].as_array().unwrap(); + let mut bad = 0; + for c in cells { + let t = f64::from_bits(u64::from_str_radix(c["temperature_bits"].as_str().unwrap(), 16).unwrap()); + if cuts(c["field"].as_i64().unwrap(), c["cost"].as_i64().unwrap(), 1.0 / t) != (c["cut_a"].as_u64().unwrap(), c["cut_b"].as_u64().unwrap()) { + bad += 1; + } + } + rep.check(bad == 0, format!("cells: {}/{} cut points the host computes for the engine equal the set's, bit for bit", cells.len() - bad, cells.len())); + + // one cell's draws on the device: every draw the reference's, and the frequencies the cut points give + let draws = ((100_000.0 * scale) as u64).max(2_000); + for c in cells.iter().step_by(23) { + let (h, cost, t) = (c["field"].as_i64().unwrap(), c["cost"].as_i64().unwrap(), c["temperature"].as_f64().unwrap()); + let (a, bb) = (c["cut_a"].as_u64().unwrap() as f64, c["cut_b"].as_u64().unwrap() as f64); + let p = [a / TWO53 as f64, (bb - a) / TWO53 as f64, (TWO53 as f64 - bb) / TWO53 as f64]; + let l = Loaded { n: 1, rows: vec![vec![]], fields: vec![h], cost }; + let seed = 0x5EED ^ (h as u64).wrapping_mul(31) ^ (cost as u64).wrapping_mul(97); + let got = cell_draws(m, &l, t, seed, draws)?; + let mut cnt = [0u64; 3]; + let mut same = 0u64; + for (r, &s) in got.iter().enumerate() { + cnt[(s + 1) as usize] += 1; + if s == cell(h, cost, 1.0 / t, chain_seed(seed, r as u64), 1) { + same += 1; + } + } + let n = draws as f64; + let z: Vec = (0..3) + .map(|i| { + let sd = (n * p[i] * (1.0 - p[i])).sqrt(); + let d = cnt[i] as f64 - n * p[i]; + if sd > 0.0 { d / sd } else if d.abs() < 1.0 { 0.0 } else { f64::INFINITY } + }) + .collect(); + rep.check( + z.iter().all(|x| x.abs() <= 4.0) && same == draws, + format!("cell h={h} c={cost} T={t}: {draws} draws, counts {cnt:?}, z {:+.2} {:+.2} {:+.2} (limit 4); {same}/{draws} equal to the reference's draw", z[0], z[1], z[2]), + ); + } + + // the statistical battery, and the all-at-once control it is built to catch + let held: Vec = battery().iter().map(|c| beyond(&c.landscape.lower(), &c.temperatures).is_none()).collect(); + for (r, holds) in run_battery(m).into_iter().zip(&held) { + if !holds && !r.declined { + let c = battery().into_iter().find(|c| c.name == r.name).expect("the battery's own case"); + let why = beyond(&c.landscape.lower(), &c.temperatures).unwrap_or_default(); + rep.check(!r.passed, format!("battery {}: beyond the engine ({why}), refused", r.name)); + } else if r.declined { + rep.check(r.passed, format!("battery {}: declined, as the spec lets a member", r.name)); + } else { + rep.check(r.passed, format!("battery {}: chi-square {:.1} on {} degrees of freedom (critical {:.1})", r.name, r.chi_square, r.degrees, r.critical)); + } + } + m.jacobi_control.set(true); + let control = run_battery(m); + m.jacobi_control.set(false); + let caught: Vec<&str> = control.iter().zip(&held).filter(|(r, h)| **h && !r.passed).map(|(r, _)| r.name).collect(); + rep.check(!caught.is_empty(), format!("the all-at-once control (every cell moved together) fails the battery on {caught:?}")); + + let (mut ok, mut n) = (0, 0); + let mut first = String::new(); + let c = named(m)?; + for j in f["jobs"].as_array().unwrap() { + n += 1; + let got = match job::call_certified(&c, "run", &j["request"], MAX_JOB_BYTES) { + Ok(a) => json!({ "state": a["state"], "energy": a["energy"], "verdict": a["verdict"], "mode": a["mode"], "restarts": a["restarts"], "sweeps": a["sweeps"], "accumulates": a["work"]["accumulates"], "draws": a["work"]["draws"], "replay": a["replay"] }), + Err(r) => json!({ "refused": r.plain(), "line": r.line }), + }; + if got == j["expect"] { + ok += 1; + } else if first.is_empty() { + first = format!("; first difference: {}: got {got}, want {}", j["name"], j["expect"]); + } + } + rep.check(ok == n, format!("jobs: {ok}/{n} requests answer as the set says (state, energy, verdict, mode, restarts, sweeps, accumulates, draws, replay digest, or the refusal){first}")); + + rep.text.push_str(&random_settles(m, ((2000.0 * scale) as usize).max(50), 0xA11CE)?.text); + Ok(rep) +} + +/// Random workloads up to 64 cells, with fields and a cost, against the reference's settle. +pub fn random_settles(m: &BoardMember

, count: usize, seed: u64) -> Result { + let mut rep = Report::default(); + let mut z = seed; + let mut next = || { + z = z.wrapping_add(GOLDEN); + let mut r = z; + r = (r ^ (r >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9); + r = (r ^ (r >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB); + r ^ (r >> 31) + }; + let mut bad = 0; + for _ in 0..count { + let n = 2 + (next() % 63) as usize; + let dens = 5 + next() % 90; + let mut l = Landscape::new(n); + for i in 0..n { + for j in (i + 1)..n { + if next() % 100 < dens { + l.couple(i, j, if next() & 1 == 0 { 1 } else { -1 }); + } + } + l.set_field(i, (next() % 11) as i64 - 5); + } + l.set_cost((next() % 4) as i64); + let start: Vec = (0..n).map(|_| (next() % 3) as i8 - 1).collect(); + let bound = 1 + (next() % 80) as u32; + let w = l.lower(); + if m.settle(&w, &start, bound)? != w.settle(&start, bound) { + bad += 1; + } + } + rep.check(bad == 0, format!("{}/{count} random workloads (2-64 cells, fields -5..5, cost 0-3) settle exactly as the reference does", count - bad)); + Ok(rep) +} + +/// Every field read back from the engine at random states, against W s + b. +pub fn fields(m: &BoardMember

, states: usize) -> Result { + let mut rep = Report::default(); + let mut l = Landscape::new(64); + let mut z = 0xF1E1Du64; + let mut next = || { + z ^= z << 13; + z ^= z >> 7; + z ^= z << 17; + z + }; + for i in 0..64 { + for j in (i + 1)..64 { + let r = next() % 3; + if r != 0 { + l.couple(i, j, if r == 1 { 1 } else { -1 }); + } + } + l.set_field(i, (next() % (2 * FIELD_MAX as u64 + 1)) as i64 - FIELD_MAX); + } + let w: Workload = l.lower(); + let lw = lowered(&w); + let mut e = m.engine.borrow_mut(); + e.load(&lw).map_err(|e| e.0)?; + let mut bad = 0; + for _ in 0..states { + let s: Vec = (0..64).map(|_| (next() % 3) as i8 - 1).collect(); + e.load_state(&s).map_err(|e| e.0)?; + for i in 0..64 { + if e.field(i).map_err(|e| e.0)? != w.field(&s, i) { + bad += 1; + } + } + } + rep.check(bad == 0, format!("{}/{} fields read back equal W s + b (dense W, fields across the engine's ±{FIELD_MAX})", states * 64 - bad, states * 64)); + Ok(rep) +} + +/// Every worked example, `seeds` seeds, at its own temperature and at 0: the board's answer +/// against the CPU reference's, field for field (the member's name and label aside). +pub fn agree(m: &BoardMember

, seeds: u64) -> Result { + let mut rep = Report::default(); + rep.line(format!("the worked examples on the board and on the CPU reference, {seeds} seeds each")); + let key = |a: &Value| json!([a["state"], a["energy"], a["verdict"], a["work"], a["replay"], a["truth"], a["reached"], a["checks"], a["mode"], a["temperature"]]); + for (name, text) in EXAMPLES { + let p = match read(text) { + Ok(p) => p, + Err(r) => { + rep.check(true, format!("{name}: refused by the reader before any member runs: {}", r.plain())); + continue; + } + }; + let job = Job::new(p); + let board = named(m)?; + let reference = Certified::reference(); + for temp in [None, Some(0.0)] { + let (mut same, mut n) = (0u64, 0u64); + let mut first = String::new(); + for s in 1..=seeds { + n += 1; + let a = run_on(&board, &job, s, temp).map_err(|r| r.plain())?; + let b = run_on(&reference, &job, s, temp).map_err(|r| r.plain())?; + if key(&a) == key(&b) { + same += 1; + } else if first.is_empty() { + first = format!("; first difference at seed {s}: board {} vs reference {}", a["state"], b["state"]); + } + } + let t = match temp { None => "its own temperature".to_string(), Some(t) => format!("temperature {t}") }; + rep.check(same == n, format!("{name} at {t}: {same}/{n} answers identical{first}")); + } + } + Ok(rep) +} + +/// A short session for the RTL testbench: both kernels through the member, a schedule longer than +/// the table, the all-at-once mode, a field outside the window, table and draw read-back. +pub fn tb_session(m: &BoardMember

) -> Result<(), String> { + bits(m)?; + fields(m, 2)?; + let mut l = Landscape::new(6); + for i in 0..5 { + l.couple(i, i + 1, if i % 2 == 0 { 1 } else { -1 }); + } + l.set_field(0, 3).set_field(5, 500).set_cost(1); + let w = l.lower(); + let start = [1i8, 0, -1, 0, 1, -1]; + m.chains(&w, &[Chain { start: start.to_vec(), seed: 77 }], &schedule(3.0, 140))?; + m.chains(&w, &[Chain { start: start.to_vec(), seed: 78 }, Chain { start: vec![0; 6], seed: 79 }], &schedule(0.0, 9))?; + // a schedule with a sweep at 0 between sweeps above 0 + m.chains(&w, &[Chain { start: start.to_vec(), seed: 80 }], &[2.0, 1.0, 0.0, 0.0, 1.5, 0.5, 0.0])?; + let lw = lowered(&w); + let seg = plan(&lw, &[1.5, 0.75])?.remove(0); + let mut e = m.engine.borrow_mut(); + e.load_table(seg.win_lo, seg.wbits, seg.first, &seg.levels).map_err(|e| e.0)?; + e.chain(5).map_err(|e| e.0)?; + e.run_sweeps(MODE_JACOBI, &start, 2, 1, false).map_err(|e| e.0)?; + e.next_draw().map_err(|e| e.0)?; + e.table_entry(((1 << seg.wbits) + (seg.first - seg.win_lo)) as usize).map_err(|e| e.0)?; + for c in [UPTIME, CYCLES, UPDATES, JOBS] { + e.counter(c).map_err(|e| e.0)?; + } + Ok(()) +} diff --git a/wai/wai-quantum-landscape-fpga/src/emio.rs b/wai/wai-quantum-landscape-fpga/src/emio.rs new file mode 100644 index 000000000..c4d93e040 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/emio.rs @@ -0,0 +1,168 @@ +//! The board's port: the PS GPIO controller's EMIO banks, reached through /dev/mem. See +//! `rtl/landscape_port.v` for the PL side and why this is not AXI. +//! +//! Bank 3 (EMIO 31:0) wdata out; bank 4 (EMIO 63:32) rdata in; bank 5 (EMIO 94:64): addr 15:0, +//! req 16, we 17 out, ack 18, busy 19, done 20 in. The directions this sets are restored on drop. + +use crate::port::{Error, Port, err}; +use std::fs::OpenOptions; +use std::os::unix::fs::OpenOptionsExt; +use std::os::unix::io::AsRawFd; +use std::time::{Duration, Instant}; + +unsafe extern "C" { + fn mmap(addr: *mut u8, len: usize, prot: i32, flags: i32, fd: i32, off: i64) -> *mut u8; + fn munmap(addr: *mut u8, len: usize) -> i32; +} +const PROT_RW: i32 = 1 | 2; +const MAP_SHARED: i32 = 1; +const O_SYNC: i32 = 0o4010000; + +pub struct Mem { + p: *mut u8, + len: usize, +} +impl Mem { + pub fn map(base: u64, len: usize) -> Result { + let f = OpenOptions::new() + .read(true) + .write(true) + .custom_flags(O_SYNC) + .open("/dev/mem") + .map_err(|e| Error(format!("/dev/mem: {e} (run as root)")))?; + let p = unsafe { mmap(std::ptr::null_mut(), len, PROT_RW, MAP_SHARED, f.as_raw_fd(), base as i64) }; + if p as isize == -1 || p.is_null() { + return err(format!("mmap of {base:#x} failed")); + } + Ok(Mem { p, len }) + } + #[inline] + pub fn rd(&self, off: usize) -> u32 { + unsafe { std::ptr::read_volatile(self.p.add(off) as *const u32) } + } + #[inline] + pub fn wr(&self, off: usize, v: u32) { + unsafe { std::ptr::write_volatile(self.p.add(off) as *mut u32, v) } + } +} +impl Drop for Mem { + fn drop(&mut self) { + unsafe { + munmap(self.p, self.len); + } + } +} + +const GPIO_BASE: u64 = 0xFF0A_0000; +const DATA_3: usize = 0x04C; +const DATA_5: usize = 0x054; +const DATA_4_RO: usize = 0x070; +const DATA_5_RO: usize = 0x074; +const DIRM_3: usize = 0x2C4; +const OEN_3: usize = 0x2C8; +const DIRM_4: usize = 0x304; +const OEN_4: usize = 0x308; +const DIRM_5: usize = 0x344; +const OEN_5: usize = 0x348; +const OUT5: u32 = 0x0003_FFFF; +const ACK: u32 = 1 << 18; +const BUSY: u32 = 1 << 19; + +pub struct EmioPort { + m: Mem, + req: u32, + saved: [u32; 7], + pub txns: u64, +} + +impl EmioPort { + pub fn name(&self) -> &'static str { + "EMIO" + } + + pub fn open() -> Result { + let m = Mem::map(GPIO_BASE, 0x1000)?; + let saved = [m.rd(DIRM_3), m.rd(OEN_3), m.rd(DIRM_4), m.rd(OEN_4), m.rd(DIRM_5), m.rd(OEN_5), m.rd(DATA_5)]; + m.wr(DIRM_3, 0xFFFF_FFFF); + m.wr(OEN_3, 0xFFFF_FFFF); + m.wr(DIRM_4, 0); + m.wr(OEN_4, 0); + m.wr(DIRM_5, OUT5); + m.wr(OEN_5, OUT5); + let req = (m.rd(DATA_5) >> 16) & 1; + Ok(EmioPort { m, req, saved, txns: 0 }) + } + + fn txn(&mut self, we: bool, addr: u16, wdata: u32) -> Result { + let ack0 = self.m.rd(DATA_5_RO) & ACK; + if we { + self.m.wr(DATA_3, wdata); + } + self.req ^= 1; + self.m.wr(DATA_5, ((we as u32) << 17) | (self.req << 16) | addr as u32); + let t = Instant::now(); + let mut spins = 0u32; + while self.m.rd(DATA_5_RO) & ACK == ack0 { + spins += 1; + if spins > 64 && t.elapsed() > Duration::from_millis(50) { + return err(format!( + "no ack from the PL for {} {addr:#06x}: the landscape engine bitstream is not loaded, its clock is stopped, or another session replaced it", + if we { "write" } else { "read" } + )); + } + } + self.txns += 1; + Ok(if we { 0 } else { self.m.rd(DATA_4_RO) }) + } + + /// Puts the three EMIO banks back to inputs with outputs disabled, the state this board boots in. + /// For the end of a session, or after a process that held the port was killed before its drop. + pub fn release_to_boot_state() -> Result<(), Error> { + let m = Mem::map(GPIO_BASE, 0x1000)?; + for (d, o) in [(DIRM_3, OEN_3), (DIRM_4, OEN_4), (DIRM_5, OEN_5)] { + m.wr(o, 0); + m.wr(d, 0); + } + m.wr(DATA_3, 0); + m.wr(DATA_5, 0); + Ok(()) + } + + pub fn busy(&self) -> bool { + self.m.rd(DATA_5_RO) & BUSY != 0 + } +} + +impl Port for EmioPort { + fn write(&mut self, addr: u16, val: u32) -> Result<(), Error> { + self.txn(true, addr, val).map(|_| ()) + } + fn read(&mut self, addr: u16) -> Result { + self.txn(false, addr, 0) + } + fn wait_idle(&mut self, timeout: Duration) -> Result<(), Error> { + let t = Instant::now(); + loop { + if !self.busy() { + return Ok(()); + } + if t.elapsed() > timeout { + return err("the engine stayed busy past the timeout"); + } + std::hint::spin_loop(); + } + } +} + +impl Drop for EmioPort { + fn drop(&mut self) { + let s = self.saved; + self.m.wr(DATA_5, s[6]); + self.m.wr(DIRM_3, s[0]); + self.m.wr(OEN_3, s[1]); + self.m.wr(DIRM_4, s[2]); + self.m.wr(OEN_4, s[3]); + self.m.wr(DIRM_5, s[4]); + self.m.wr(OEN_5, s[5]); + } +} diff --git a/wai/wai-quantum-landscape-fpga/src/engine.rs b/wai/wai-quantum-landscape-fpga/src/engine.rs new file mode 100644 index 000000000..2c93a20a4 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/engine.rs @@ -0,0 +1,535 @@ +//! The driver: put a workload, a cut-point table and a draw counter into the engine, run it, read +//! it back. Generic over the port, so the same code drives the board, the model and the testbench. + +use crate::port::{Error, Port, err}; +use crate::regs::*; +use std::time::Duration; + +pub fn encode(s: &[i8]) -> [u32; 4] { + let mut w = [0u32; 4]; + for (j, &t) in s.iter().enumerate() { + let v: u32 = match t { + 1 => 0b01, + -1 => 0b10, + _ => 0, + }; + let b = 2 * j; + w[b >> 5] |= v << (b & 31); + } + w +} + +pub fn decode(w: &[u32; 4], n: usize) -> Result, Error> { + (0..n) + .map(|j| { + let b = 2 * j; + match (w[b >> 5] >> (b & 31)) & 3 { + 0b00 => Ok(0), + 0b01 => Ok(1), + 0b10 => Ok(-1), + _ => err(format!("cell {j} reads back as the illegal pair (1,1)")), + } + }) + .collect() +} + +#[derive(Clone, Debug, PartialEq)] +pub struct T0Run { + pub state: Vec, + pub steps: u32, + pub term: u32, + pub cycles: u64, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct SweepRun { + pub state: Vec, + pub sweeps: u32, + pub cycles: u64, + pub updates: u64, +} + +/// A workload as the engine holds it: rows of (column, ±1), one field a cell, the cost. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Loaded { + pub n: usize, + pub rows: Vec>, + pub fields: Vec, + pub cost: i64, +} + +impl Loaded { + pub fn nonzeros(&self) -> u64 { + self.rows.iter().map(|r| r.len() as u64).sum() + } + pub fn key(&self) -> [u8; 32] { + let mut h = blake3::Hasher::new(); + h.update(&(self.n as u64).to_le_bytes()); + for r in &self.rows { + h.update(&(r.len() as u64).to_le_bytes()); + for &(j, v) in r { + h.update(&(j as u64).to_le_bytes()); + h.update(&[v as u8]); + } + } + for f in &self.fields { + h.update(&f.to_le_bytes()); + } + h.update(&self.cost.to_le_bytes()); + *h.finalize().as_bytes() + } +} + +/// One chain of a batch: where it ended, after how many sweeps (or steps, at temperature 0), and how. +#[derive(Clone, Debug, PartialEq)] +pub struct BatchRun { + pub state: Vec, + pub steps: u32, + pub term: u32, +} + +pub struct Engine { + pub port: P, + pub timeout: Duration, + n: usize, + loaded: Option<[u8; 32]>, + table: Option<[u8; 32]>, + /// The uptime counter when last read, and what BOUND last held: see [`Engine::alive`]. + uptime: u64, + bound: u32, +} + +/// What BOUND holds from [`Engine::open`] until the first job: any value but the 0 a reload leaves. +const BOUND_AT_OPEN: u32 = 0x4C41_4E44; +/// The uptime counter is 48 bits. It may wrap inside this much of its top, and not be a reload. +const UPTIME_TOP: u64 = 1 << 48; +const UPTIME_WRAP: u64 = 1 << 36; + +impl Engine

{ + /// Opens the engine. Refuses anything whose ID and version are not this design's: on a shared + /// board that is how a foreign bitstream is caught before it is driven. + pub fn open(mut port: P) -> Result { + let id = port.read(ID)?; + if id != ID_VALUE { + return err(format!( + "the programmable logic is not running the landscape engine (ID {id:#010x}, want {ID_VALUE:#010x}). \ + Load the bitstream first; if it was loaded, another session has replaced it." + )); + } + let v = port.read(VERSION)?; + if v != VERSION_VALUE { + return err(format!("engine version {v:#010x}, this host speaks {VERSION_VALUE:#010x}")); + } + port.write(BOUND, BOUND_AT_OPEN)?; + let mut e = Engine { port, timeout: Duration::from_secs(60), n: 0, loaded: None, table: None, uptime: 0, bound: BOUND_AT_OPEN }; + e.uptime = e.counter(UPTIME)?; + Ok(e) + } + + /// Whether the engine is still the one this session loaded. A reload of the same design passes + /// the link's signature and the engine's ID, and leaves W, the fields, the cost and the table + /// empty while the keys here still say they are loaded, so a job would run on a wiped engine and + /// give states that look valid. A reload shows two ways: the uptime counter starts again, and + /// BOUND goes back to 0. Checked before anything is taken as loaded and after every job: a + /// result read across a reload is refused, not kept. After a refusal nothing is taken as loaded. + pub fn alive(&mut self) -> Result<(), Error> { + let u = self.counter(UPTIME)?; + let b = self.port.read(BOUND)?; + let wrapped = self.uptime >= UPTIME_TOP - UPTIME_WRAP && u < UPTIME_WRAP; + if (u < self.uptime && !wrapped) || (self.bound != 0 && b != self.bound) { + let was = (self.uptime, self.bound); + self.loaded = None; + self.table = None; + self.n = 0; + self.uptime = u; + self.bound = b; + return err(format!( + "the engine was reloaded under this session (uptime {} -> {u}, BOUND {:#x} -> {b:#x}): its workload and table are gone, and this job's result is not kept", + was.0, was.1 + )); + } + self.uptime = u; + Ok(()) + } + + fn set_bound(&mut self, v: u32) -> Result<(), Error> { + self.port.write(BOUND, v)?; + self.bound = v; + Ok(()) + } + + pub fn n(&self) -> usize { + self.n + } + + pub fn counter(&mut self, lo: u16) -> Result { + let l = self.port.read(lo)? as u64; + let h = self.port.read(lo + 1)? as u64; + Ok((h << 32) | l) + } + + /// Writes W, the fields and the cost, unless the same workload is already there. + pub fn load(&mut self, w: &Loaded) -> Result<(), Error> { + if w.n == 0 || w.n > CELLS { + return err(format!("{} variables; this engine holds 1 to {CELLS}", w.n)); + } + if let Some(i) = w.fields.iter().position(|f| f.abs() > FIELD_MAX) { + return err(format!("variable {i} has the field {}, beyond the engine's ±{FIELD_MAX}", w.fields[i])); + } + if !(0..=COST_MAX).contains(&w.cost) { + return err(format!("the cost {} is beyond the engine's 0 to {COST_MAX}", w.cost)); + } + self.alive()?; + let key = w.key(); + if self.loaded == Some(key) { + self.n = w.n; + return Ok(()); + } + self.loaded = None; + let mut list = vec![(CONTROL, CTL_CLEARW)]; + for (i, row) in w.rows.iter().enumerate() { + let mut cells = vec![0i8; CELLS]; + for &(j, v) in row { + if !(v == 1 || v == -1) || j >= w.n { + return err(format!("row {i}: a coupling must be ±1 to a variable below {}", w.n)); + } + cells[j] = v; + } + for (k, &word) in encode(&cells).iter().enumerate() { + if word != 0 { + list.push((W + (i as u16) * 4 + k as u16, word)); + } + } + if w.fields[i] != 0 { + list.push((FIELDS + i as u16, (w.fields[i] as u32) & 0xF_FFFF)); + } + } + list.push((N_M1, (w.n - 1) as u32)); + list.push((COST, w.cost as u32)); + self.port.bulk(&list)?; + self.n = w.n; + self.loaded = Some(key); + Ok(()) + } + + /// Writes the window and its cut points: `levels[l][k]` is the pair for field `first + k` at + /// level `l`. Skipped when the same table is already there. + pub fn load_table(&mut self, win_lo: i64, wbits: u32, first: i64, levels: &[Vec<(u64, u64)>]) -> Result<(), Error> { + if wbits > MAX_WBITS || levels.is_empty() || levels.len() > (TABLE >> wbits).min(LEVELS) { + return err(format!("{} levels of 2^{wbits} fields do not fit the table", levels.len())); + } + let mut h = blake3::Hasher::new(); + h.update(&win_lo.to_le_bytes()); + h.update(&wbits.to_le_bytes()); + h.update(&first.to_le_bytes()); + for l in levels { + h.update(&(l.len() as u64).to_le_bytes()); + for &(a, b) in l { + h.update(&a.to_le_bytes()); + h.update(&b.to_le_bytes()); + } + } + let key = *h.finalize().as_bytes(); + self.alive()?; + let mut list = vec![(WIN_LO, (win_lo as u32) & 0x3F_FFFF), (WBITS, wbits), (LEVELS_M1, (levels.len() - 1) as u32)]; + if self.table == Some(key) { + return self.port.bulk(&list); + } + self.table = None; + for (l, entries) in levels.iter().enumerate() { + if entries.is_empty() { + continue; + } + let off = first - win_lo; + if off < 0 || off as usize + entries.len() > (1usize << wbits) { + return err("table entries outside the window"); + } + list.push((TBL_ADDR, ((l << wbits) + off as usize) as u32)); + for &(a, b) in entries { + list.extend([(TBL_A_LO, a as u32), (TBL_A_HI, (a >> 32) as u32), (TBL_B_LO, b as u32), (TBL_B_HI, (b >> 32) as u32)]); + } + } + self.port.bulk(&list)?; + self.table = Some(key); + Ok(()) + } + + /// Reads back one entry of the table. + pub fn table_entry(&mut self, addr: usize) -> Result<(u64, u64), Error> { + self.port.write(TBL_ADDR, addr as u32)?; + let a = self.port.read(TBL_A_LO)? as u64 | ((self.port.read(TBL_A_HI)? as u64) << 32); + let b = self.port.read(TBL_B_LO)? as u64 | ((self.port.read(TBL_B_HI)? as u64) << 32); + Ok((a, b)) + } + + /// The draw counter's start for a chain: its seed plus GOLDEN, so the first draw is out(chain, 1). + pub fn chain(&mut self, chain_seed: u64) -> Result<(), Error> { + let x0 = chain_seed.wrapping_add(GOLDEN); + self.port.write(X0_LO, x0 as u32)?; + self.port.write(X0_HI, (x0 >> 32) as u32) + } + + /// The draw the next cell would take, after a sampling job. + pub fn next_draw(&mut self) -> Result { + let lo = self.port.read(DRAW_LO)? as u64; + let hi = self.port.read(DRAW_HI)? as u64; + Ok((hi << 32) | lo) + } + + pub fn set_boundary(&mut self, s: &[i8]) -> Result<(), Error> { + if s.len() != self.n { + return err(format!("a start of {} cells for {} variables", s.len(), self.n)); + } + for (k, &word) in encode(s).iter().enumerate() { + self.port.write(BOUNDARY + k as u16, word)?; + } + Ok(()) + } + + pub fn read_state(&mut self) -> Result, Error> { + let need = (2 * self.n).div_ceil(32); + let mut w = [0u32; 4]; + for (k, word) in w.iter_mut().enumerate().take(need) { + *word = self.port.read(STATE + k as u16)?; + } + decode(&w, self.n) + } + + /// The field the engine computes for cell `i` at its current state. + pub fn field(&mut self, i: usize) -> Result { + self.port.write(SEL, i as u32)?; + Ok(self.port.read(FIELD)? as i32 as i64) + } + + pub fn load_state(&mut self, s: &[i8]) -> Result<(), Error> { + self.set_boundary(s)?; + self.port.write(CONTROL, CTL_LOADSTATE) + } + + fn finish(&mut self) -> Result<(), Error> { + self.port.wait_idle(self.timeout)?; + self.alive()?; + let st = self.port.read(STATUS)?; + if st & 2 == 0 { + return err(format!("the job stopped without finishing (status {st:#x})")); + } + Ok(()) + } + + /// The settle kernel: every cell at once, to a fixed point, a two-cycle or the bound. + pub fn run_t0(&mut self, start: &[i8], bound: u32) -> Result { + self.port.write(MODE, MODE_T0)?; + self.set_bound(bound)?; + self.set_boundary(start)?; + self.port.write(CONTROL, CTL_CLRCNT)?; + self.port.write(CONTROL, CTL_START)?; + self.finish()?; + let term = (self.port.read(STATUS)? >> 2) & 3; + let steps = self.port.read(STEPS)?; + let cycles = self.counter(CYCLES)?; + Ok(T0Run { state: self.read_state()?, steps, term, cycles }) + } + + /// `sweeps` sweeps of `mode` from `start` with the draws of the counter set by [`Self::chain`], + /// the level stepping every `spl` sweeps, then one synchronous T=0 sweep if `final_t0`. + pub fn run_sweeps(&mut self, mode: u32, start: &[i8], sweeps: u32, spl: u32, final_t0: bool) -> Result { + self.prepare(mode, start, sweeps, spl, final_t0)?; + self.port.write(CONTROL, CTL_CLRCNT)?; + self.port.write(CONTROL, CTL_START)?; + self.finish()?; + self.sweep_result() + } + + /// More sweeps from the current state, the level back to 0 and the draws continuing: with a + /// fresh table this is how a schedule longer than the table runs. + pub fn cont_sweeps(&mut self, mode: u32, sweeps: u32, spl: u32, final_t0: bool) -> Result { + if sweeps == 0 { + return err("CONT needs at least one sweep"); + } + self.port.write(MODE, mode | if final_t0 { MODE_FINAL_T0 } else { 0 })?; + self.set_bound(sweeps)?; + self.port.write(SPL, spl.max(1))?; + self.port.write(CONTROL, CTL_CLRCNT)?; + self.port.write(CONTROL, CTL_CONT)?; + self.finish()?; + self.sweep_result() + } + + fn sweep_result(&mut self) -> Result { + let sweeps = self.port.read(STEPS)?; + let cycles = self.counter(CYCLES)?; + let updates = self.counter(UPDATES)?; + Ok(SweepRun { state: self.read_state()?, sweeps, cycles, updates }) + } + + pub fn prepare(&mut self, mode: u32, start: &[i8], sweeps: u32, spl: u32, final_t0: bool) -> Result<(), Error> { + self.port.write(MODE, mode | if final_t0 { MODE_FINAL_T0 } else { 0 })?; + self.set_bound(sweeps)?; + self.port.write(SPL, spl.max(1))?; + self.set_boundary(start) + } + + /// Repeat mode, for power: the job restarts from its start every time it ends, until + /// [`Self::halt`]. A sampling job reloads its counter, so every repeat is the same chain. + pub fn run_repeat(&mut self, mode: u32, bound: u32, spl: u32, final_t0: bool) -> Result<(), Error> { + self.port.write(MODE, mode | MODE_REPEAT | if final_t0 { MODE_FINAL_T0 } else { 0 })?; + self.set_bound(bound)?; + self.port.write(SPL, spl.max(1))?; + self.port.write(CONTROL, CTL_CLRCNT)?; + self.port.write(CONTROL, CTL_START) + } + + /// A run of chains on the job already set (mode, bound, sweeps per level, table, workload): + /// for each, its start and the draw counter's start, `x0`. On the AXI link the chains run in + /// fabric, one after another, with nothing from the processor between them. + pub fn run_batch(&mut self, mode: u32, bound: u32, spl: u32, final_t0: bool, chains: &[(Vec, u64)]) -> Result, Error> { + self.alive()?; + self.port.bulk(&[(MODE, mode | if final_t0 { MODE_FINAL_T0 } else { 0 }), (BOUND, bound), (SPL, spl.max(1))])?; + self.bound = bound; + let mut words = Vec::with_capacity(chains.len()); + for (start, x0) in chains { + if start.len() != self.n { + return err(format!("a start of {} cells for {} variables", start.len(), self.n)); + } + let b = encode(start); + words.push([b[0], b[1], b[2], b[3], *x0 as u32, (*x0 >> 32) as u32]); + } + let results = self.port.batch(&words, self.timeout)?; + self.alive()?; + if results.len() != words.len() { + return err(format!("{} results for a batch of {} chains", results.len(), words.len())); + } + let mut out = Vec::with_capacity(chains.len()); + for r in results { + if r[5] & 2 == 0 { + return err(format!("a chain of the batch stopped without finishing (status {:#x})", r[5])); + } + out.push(BatchRun { state: decode(&[r[0], r[1], r[2], r[3]], self.n)?, steps: r[4], term: (r[5] >> 2) & 3 }); + } + Ok(out) + } + + pub fn halt(&mut self) -> Result<(), Error> { + self.port.write(CONTROL, CTL_STOP)?; + let m = self.port.read(MODE)?; + self.port.write(MODE, m & !MODE_REPEAT) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::model::ModelPort; + use crate::port::{ChainWords, ResultWords}; + + fn workload() -> Loaded { + Loaded { n: 3, rows: vec![vec![(1, 1)], vec![(0, 1), (2, -1)], vec![(1, -1)]], fields: vec![2, 0, -1], cost: 1 } + } + + /// The same design loaded again, as a port sees it: every register back at its reset value. + fn reload(e: &mut Engine) { + e.port = ModelPort::new(); + } + + #[test] + fn a_reload_between_jobs_stops_the_next_job() { + let w = workload(); + let mut e = Engine::open(ModelPort::new()).unwrap(); + e.load(&w).unwrap(); + let good = e.run_t0(&[1, 0, -1], 20).unwrap(); + reload(&mut e); + let refused = e.load(&w).expect_err("a cached workload on a wiped engine"); + assert!(refused.0.contains("reloaded"), "{}", refused.0); + // nothing is taken as loaded now: the workload goes back in, and the job gives the same bits + e.load(&w).unwrap(); + assert_eq!(e.run_t0(&[1, 0, -1], 20).unwrap().state, good.state); + } + + #[test] + fn a_reload_shows_by_bound_where_uptime_has_passed_its_old_value() { + let w = workload(); + let mut e = Engine::open(ModelPort::new()).unwrap(); + e.load(&w).unwrap(); + e.run_t0(&[1, 0, -1], 20).unwrap(); + reload(&mut e); + for _ in 0..1000 { + e.port.read(ID).unwrap(); // the fresh engine's uptime counts past the old one's + } + assert!(e.load(&w).is_err()); + } + + #[test] + fn a_table_is_not_taken_as_loaded_across_a_reload() { + let levels = vec![vec![(1u64, 2u64); 4]]; + let mut e = Engine::open(ModelPort::new()).unwrap(); + e.load(&workload()).unwrap(); + e.load_table(0, 2, 0, &levels).unwrap(); + reload(&mut e); + assert!(e.load_table(0, 2, 0, &levels).is_err()); + } + + /// A port whose engine is reloaded while a job runs. + struct ReloadedMidJob(ModelPort); + impl Port for ReloadedMidJob { + fn write(&mut self, a: u16, v: u32) -> Result<(), Error> { + self.0.write(a, v)?; + if a == CONTROL && v & CTL_START != 0 { + self.0 = ModelPort::new(); + } + Ok(()) + } + fn read(&mut self, a: u16) -> Result { + self.0.read(a) + } + fn wait_idle(&mut self, t: Duration) -> Result<(), Error> { + self.0.wait_idle(t) + } + } + + #[test] + fn a_result_read_across_a_reload_is_refused() { + let mut e = Engine::open(ReloadedMidJob(ModelPort::new())).unwrap(); + e.load(&workload()).unwrap(); + assert!(e.run_t0(&[1, 0, -1], 20).is_err()); + let mut e = Engine::open(ReloadedMidJob(ModelPort::new())).unwrap(); + e.load(&workload()).unwrap(); + assert!(e.run_batch(MODE_T0, 20, 1, false, &[(vec![1, 0, -1], 0)]).is_err()); + } + + #[test] + fn the_uptime_counter_wrapping_is_not_a_reload() { + let mut e = Engine::open(ModelPort::new()).unwrap(); + e.uptime = UPTIME_TOP - 5; + e.alive().unwrap(); + e.uptime = UPTIME_TOP / 2; + assert!(e.alive().is_err()); + } + + /// A port that loses the last result of every batch. + struct ShortBatch(ModelPort); + impl Port for ShortBatch { + fn write(&mut self, a: u16, v: u32) -> Result<(), Error> { + self.0.write(a, v) + } + fn read(&mut self, a: u16) -> Result { + self.0.read(a) + } + fn wait_idle(&mut self, t: Duration) -> Result<(), Error> { + self.0.wait_idle(t) + } + fn batch(&mut self, chains: &[ChainWords], t: Duration) -> Result, Error> { + let mut out = crate::port::batch_plain(self, chains, t)?; + out.pop(); + Ok(out) + } + } + + #[test] + fn a_short_batch_is_refused() { + let mut e = Engine::open(ShortBatch(ModelPort::new())).unwrap(); + e.load(&workload()).unwrap(); + let chains = vec![(vec![1, 0, -1], 0), (vec![0, 0, 0], 0)]; + let refused = e.run_batch(MODE_T0, 20, 1, false, &chains).expect_err("a batch that came back short"); + assert!(refused.0.contains("results for a batch"), "{}", refused.0); + } +} diff --git a/wai/wai-quantum-landscape-fpga/src/exact.rs b/wai/wai-quantum-landscape-fpga/src/exact.rs new file mode 100644 index 000000000..e0a4a27f5 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/exact.rs @@ -0,0 +1,492 @@ +//! Joint statistics against exact enumeration. +//! +//! Per-cell frequencies can all be right while the joint law is wrong: a sampler that drew each cell +//! from its correct marginal, independently, would pass every per-cell test. So the sample kernel is +//! also held to the exact law of the whole state. For a workload of `n` cells (3^n states, `n` up to +//! about 10) the law of a chain's final state is computed by enumeration: a vector over every state, +//! pushed through each cell update of each sweep with the update's three probabilities taken from +//! the reference's own cut points (a draw `u` of 53 bits gives −1 below `a`, 0 below `b`, +1 above, +//! so the probabilities are `a/2^53`, `(b−a)/2^53` and `1 − b/2^53`), then through the synchronous +//! sweep at temperature 0 where the schedule ends with one. Nothing is sampled and nothing +//! approximated beyond the f64 sums. +//! +//! Many chains, each with its own seed, then give a histogram of final states, which is held to the +//! exact law by Pearson's chi-square and the G-test over every state (states with fewer than five +//! expected chains pooled), and by every cell's marginal and every pair of cells' joint law (z +//! scores, Bonferroni over all of them). The same histogram is also held to the law that has the +//! exact marginals but independent cells: that law must be rejected, which shows the test sees +//! joint structure that per-cell statistics cannot. + +use crate::engine::Engine; +use crate::member::{lowered, plan, run_schedule}; +use crate::port::Port; +use std::collections::HashMap; +use std::fmt::Write as _; +use wai_quantum::quantum_landscape::energy::Landscape; +use wai_quantum::quantum_landscape::sample::{anneal, chain_seed, cuts, out, pick, temperature}; +use wai_quantum::quantum_landscape::settle::Workload; + +const TWO53: f64 = 9_007_199_254_740_992.0; + +/// The state's index: cell 0 is the least significant base-3 digit, −1, 0, +1 as 0, 1, 2. +pub fn index(s: &[i8]) -> usize { + s.iter().rev().fold(0usize, |a, &v| a * 3 + (v + 1) as usize) +} + +pub fn state_of(mut k: usize, n: usize) -> Vec { + (0..n) + .map(|_| { + let v = (k % 3) as i8 - 1; + k /= 3; + v + }) + .collect() +} + +/// The exact law of the final state: sequential sweeps at the inverse temperatures `betas` from +/// `start`, then, with `final_t0`, one synchronous sweep at temperature 0. +pub fn exact_law(w: &Workload, start: &[i8], betas: &[f64], final_t0: bool) -> Vec { + let n = w.n(); + let m = 3usize.pow(n as u32); + let pow3: Vec = (0..n).map(|i| 3usize.pow(i as u32)).collect(); + let mut p = vec![0.0f64; m]; + p[index(start)] = 1.0; + for &beta in betas { + let mut cache: HashMap = HashMap::new(); + for i in 0..n { + let mut q = vec![0.0f64; m]; + for (k, &pk) in p.iter().enumerate() { + if pk == 0.0 { + continue; + } + let s = state_of(k, n); + let h = w.field(&s, i); + let pr = *cache.entry(h).or_insert_with(|| { + let (a, b) = cuts(h, w.cost(), beta); + [a as f64 / TWO53, (b - a) as f64 / TWO53, (TWO53 - b as f64) / TWO53] + }); + let base = k - (s[i] + 1) as usize * pow3[i]; + q[base] += pk * pr[0]; + q[base + pow3[i]] += pk * pr[1]; + q[base + 2 * pow3[i]] += pk * pr[2]; + } + p = q; + } + } + if final_t0 { + let mut q = vec![0.0f64; m]; + for (k, &pk) in p.iter().enumerate() { + if pk != 0.0 { + q[index(&w.sweep(&state_of(k, n)))] += pk; + } + } + p = q; + } + p +} + +/// The reference's chain through the same schedule, draw for draw: cell `i` of sweep `k` takes +/// `out(chain, k·n + i + 1) >> 11`. For the job's anneal this is `sample::anneal` (a test holds the +/// two equal); at a fixed temperature the schedule is the anneal's inner loop with `beta` fixed. +pub fn reference(w: &Workload, start: &[i8], betas: &[f64], final_t0: bool, chain: u64) -> Vec { + let n = w.n(); + let mut s = start.to_vec(); + for (k, &beta) in betas.iter().enumerate() { + let base = (k as u64).wrapping_mul(n as u64); + for i in 0..n { + let (a, b) = cuts(w.field(&s, i), w.cost(), beta); + s[i] = pick(out(chain, base + i as u64 + 1) >> 11, a, b); + } + } + if final_t0 { w.sweep(&s) } else { s } +} + +fn ln_gamma(x: f64) -> f64 { + const G: [f64; 9] = [ + 0.999_999_999_999_809_9, + 676.520_368_121_885_1, + -1_259.139_216_722_402_8, + 771.323_428_777_653_1, + -176.615_029_162_140_6, + 12.507_343_278_686_905, + -0.138_571_095_265_720_12, + 9.984_369_578_019_572e-6, + 1.505_632_735_149_311_6e-7, + ]; + if x < 0.5 { + return (std::f64::consts::PI / (std::f64::consts::PI * x).sin()).ln() - ln_gamma(1.0 - x); + } + let x = x - 1.0; + let mut a = G[0]; + let t = x + 7.5; + for (i, &g) in G.iter().enumerate().skip(1) { + a += g / (x + i as f64); + } + 0.5 * (2.0 * std::f64::consts::PI).ln() + (x + 0.5) * t.ln() - t + a.ln() +} + +/// The upper regularised incomplete gamma function Q(a, x): the chi-square tail is Q(df/2, x/2). +pub fn gamma_q(a: f64, x: f64) -> f64 { + if x <= 0.0 { + return 1.0; + } + let lead = -x + a * x.ln() - ln_gamma(a); + if x < a + 1.0 { + let (mut ap, mut sum, mut del) = (a, 1.0 / a, 1.0 / a); + for _ in 0..1_000_000 { + ap += 1.0; + del *= x / ap; + sum += del; + if del.abs() < sum.abs() * 1e-15 { + break; + } + } + (1.0 - sum * lead.exp()).max(0.0) + } else { + let tiny = 1e-300; + let mut b = x + 1.0 - a; + let mut c = 1.0 / tiny; + let mut d = 1.0 / b; + let mut h = d; + for i in 1..1_000_000 { + let an = -(i as f64) * (i as f64 - a); + b += 2.0; + d = an * d + b; + if d.abs() < tiny { + d = tiny; + } + c = b + an / c; + if c.abs() < tiny { + c = tiny; + } + d = 1.0 / d; + let del = d * c; + h *= del; + if (del - 1.0).abs() < 1e-15 { + break; + } + } + (lead.exp() * h).clamp(0.0, 1.0) + } +} + +/// erfc, to a relative error under 1.2e-7. +pub fn erfc(x: f64) -> f64 { + let z = x.abs(); + let t = 1.0 / (1.0 + 0.5 * z); + let r = t * (-z * z - 1.265_512_23 + + t * (1.000_023_68 + + t * (0.374_091_96 + t * (0.096_784_18 + t * (-0.186_288_06 + t * (0.278_868_07 + t * (-1.135_203_98 + t * (1.488_515_87 + t * (-0.822_152_23 + t * 0.170_872_77))))))))) + .exp(); + if x >= 0.0 { r } else { 2.0 - r } +} + +/// A histogram held to a law. +#[derive(Clone, Debug)] +pub struct Fit { + pub samples: u64, + pub bins: usize, + pub chi2: f64, + pub p_chi2: f64, + pub g: f64, + pub p_g: f64, + /// Total variation distance between the histogram and the law. + pub tv: f64, + /// The largest |z| over every cell's three marginal frequencies, and its Bonferroni p. + pub z_cell: f64, + pub p_cell: f64, + /// The largest |z| over every pair of cells' nine joint frequencies, and its Bonferroni p. + pub z_pair: f64, + pub p_pair: f64, +} + +fn z_max(obs: &[u64], law: &[f64], total: u64, groups: impl Fn(usize) -> Vec, ngroups: usize) -> (f64, usize) { + let mut o = vec![0u64; ngroups]; + let mut e = vec![0.0f64; ngroups]; + for (k, (&c, &p)) in obs.iter().zip(law).enumerate() { + for gidx in groups(k) { + o[gidx] += c; + e[gidx] += p; + } + } + let nt = total as f64; + let mut zmax = 0.0f64; + let mut tests = 0usize; + for (oi, &pi) in o.iter().zip(&e) { + if pi <= 1e-12 || pi >= 1.0 - 1e-12 { + if (*oi > 0 && pi <= 1e-12) || (*oi < total && pi >= 1.0 - 1e-12) { + zmax = f64::INFINITY; + } + continue; + } + tests += 1; + let z = (*oi as f64 - nt * pi) / (nt * pi * (1.0 - pi)).sqrt(); + zmax = zmax.max(z.abs()); + } + (zmax, tests.max(1)) +} + +pub fn fit(counts: &[u64], law: &[f64], n: usize) -> Fit { + let total: u64 = counts.iter().sum(); + let nt = total as f64; + // bins: every state expected at least 5 times on its own, the rest pooled + let (mut chi2, mut g, mut bins) = (0.0, 0.0, 0usize); + let (mut po, mut pe) = (0u64, 0.0f64); + let mut impossible = false; + for (&c, &p) in counts.iter().zip(law) { + let e = nt * p; + if e >= 5.0 { + chi2 += (c as f64 - e).powi(2) / e; + if c > 0 { + g += 2.0 * c as f64 * (c as f64 / e).ln(); + } + bins += 1; + } else { + po += c; + pe += e; + if p == 0.0 && c > 0 { + impossible = true; + } + } + } + if pe > 0.0 { + chi2 += (po as f64 - pe).powi(2) / pe; + if po > 0 { + g += 2.0 * po as f64 * (po as f64 / pe).ln(); + } + bins += 1; + } + let df = bins.saturating_sub(1).max(1) as f64; + let (mut p_chi2, mut p_g) = (gamma_q(df / 2.0, chi2 / 2.0), gamma_q(df / 2.0, g.max(0.0) / 2.0)); + if impossible { + p_chi2 = 0.0; + p_g = 0.0; + } + let tv = 0.5 * counts.iter().zip(law).map(|(&c, &p)| (c as f64 / nt - p).abs()).sum::(); + let pow3: Vec = (0..n).map(|i| 3usize.pow(i as u32)).collect(); + let digit = |k: usize, i: usize| (k / pow3[i]) % 3; + let (z_cell, t_cell) = z_max(counts, law, total, |k| (0..n).map(|i| 3 * i + digit(k, i)).collect(), 3 * n); + let pairs: Vec<(usize, usize)> = (0..n).flat_map(|i| ((i + 1)..n).map(move |j| (i, j))).collect(); + let (z_pair, t_pair) = z_max(counts, law, total, |k| pairs.iter().enumerate().map(|(q, &(i, j))| 9 * q + 3 * digit(k, i) + digit(k, j)).collect(), 9 * pairs.len().max(1)); + let bonf = |z: f64, t: usize| if z.is_infinite() { 0.0 } else { (t as f64 * erfc(z / std::f64::consts::SQRT_2)).min(1.0) }; + Fit { samples: total, bins, chi2, p_chi2, g, p_g, tv, z_cell, p_cell: bonf(z_cell, t_cell), z_pair, p_pair: bonf(z_pair, t_pair) } +} + +/// The law with the same marginals as `law` and independent cells. +pub fn independent(law: &[f64], n: usize) -> Vec { + let mut marg = vec![[0.0f64; 3]; n]; + for (k, &p) in law.iter().enumerate() { + for (i, s) in state_of(k, n).iter().enumerate() { + marg[i][(s + 1) as usize] += p; + } + } + (0..law.len()).map(|k| state_of(k, n).iter().enumerate().map(|(i, s)| marg[i][(s + 1) as usize]).product()).collect() +} + +/// A pre-registered case: a workload, a start, a schedule, a number of chains. +pub struct Case { + pub name: &'static str, + pub landscape: Landscape, + pub start: Vec, + /// Temperatures of the sampled sweeps, in order. + pub temps: Vec, + /// The job's anneal ends with one synchronous sweep at temperature 0. + pub final_t0: bool, + /// For the anneal cases, the job's (t0, sweeps); the reference chain is then `sample::anneal`. + pub anneal: Option<(f64, u32)>, + pub chains: u64, +} + +/// The cases, as `measurements/2026-11-06/JOINT-PREREG.txt` registers them. `scale` multiplies the +/// number of chains (1 on the board; small for the model). +pub fn cases(scale: f64) -> Vec { + let k = |c: u64| ((c as f64 * scale).round() as u64).max(200); + // ring of 8, frustrated by two chords, with fields and a cost + let mut ring = Landscape::new(8); + for i in 0..8 { + ring.couple(i, (i + 1) % 8, if i % 3 == 0 { -1 } else { 1 }); + } + ring.couple(0, 4, -1).couple(2, 6, 1); + ring.set_field(0, 1).set_field(2, -2).set_field(4, 3).set_field(7, -1).set_cost(1); + // dense 6, every pair coupled, signs from a fixed stream + let mut dense = Landscape::new(6); + let mut z = 0x0D_E5E6u64; + for i in 0..6 { + for j in (i + 1)..6 { + z = z.wrapping_add(0x9E37_79B9_7F4A_7C15); + dense.couple(i, j, if out(z, 1) & 1 == 0 { 1 } else { -1 }); + } + } + // sparse 10: a chain with three long couplings and fields + let mut sparse = Landscape::new(10); + for i in 0..9 { + sparse.couple(i, i + 1, if i % 2 == 0 { 1 } else { -1 }); + } + sparse.couple(0, 9, 1).couple(1, 6, -1).couple(3, 8, 1); + sparse.set_field(1, 2).set_field(5, -1).set_field(8, 1).set_cost(1); + let anneal_temps = |t0: f64, sweeps: u32| (0..sweeps - 1).map(|q| temperature(t0, sweeps, q)).collect::>(); + vec![ + Case { name: "ring 8, fixed T = 1.5, 4 sweeps", landscape: ring.clone(), start: vec![0; 8], temps: vec![1.5; 4], final_t0: false, anneal: None, chains: k(200_000) }, + Case { name: "ring 8, the job's anneal from T = 2.5, 10 sweeps", landscape: ring, start: vec![1, -1, 0, 0, 1, -1, 0, 1], temps: anneal_temps(2.5, 10), final_t0: true, anneal: Some((2.5, 10)), chains: k(200_000) }, + Case { name: "dense 6, fixed T = 4, 2 sweeps", landscape: dense, start: vec![1, 1, 1, -1, -1, -1], temps: vec![4.0; 2], final_t0: false, anneal: None, chains: k(200_000) }, + Case { name: "sparse 10, the job's anneal from T = 1.5, 8 sweeps", landscape: sparse, start: vec![0; 10], temps: anneal_temps(1.5, 8), final_t0: true, anneal: Some((1.5, 8)), chains: k(400_000) }, + ] +} + +/// One case's result. +pub struct Outcome { + pub fit: Fit, + pub control: Fit, + /// Chains whose final state equals the reference's, of all. + pub same: u64, +} + +/// Runs a case on an engine: every chain on the device and on the reference, the histogram held to +/// the exact law and to the independent-cells control. Chain `r` has the seed `chain_seed(seed, r)`. +pub fn run_case(e: &mut Engine

, c: &Case, seed: u64) -> Result { + let w = c.landscape.lower(); + let n = w.n(); + let l = lowered(&w); + e.load(&l).map_err(|x| x.0)?; + let segments = plan(&l, &c.temps)?; + let betas: Vec = c.temps.iter().map(|t| 1.0 / t).collect(); + let law = exact_law(&w, &c.start, &betas, c.final_t0); + let mut counts = vec![0u64; law.len()]; + let mut same = 0u64; + let block = 4096u64; + let mut r0 = 0u64; + while r0 < c.chains { + let r1 = (r0 + block).min(c.chains); + let list: Vec<(Vec, u64)> = (r0..r1).map(|r| (c.start.clone(), chain_seed(seed, r))).collect(); + let got = run_schedule(e, &l, &segments, c.final_t0, &list, 0, crate::regs::MODE_GIBBS)?; + for (st, (_, ch)) in got.iter().zip(&list) { + counts[index(st)] += 1; + let want = match c.anneal { + Some((t0, sweeps)) => anneal(&w, &c.start, t0, sweeps, *ch).state, + None => reference(&w, &c.start, &betas, c.final_t0, *ch), + }; + if *st == want { + same += 1; + } + } + r0 = r1; + } + let fit_law = fit(&counts, &law, n); + let control = fit(&counts, &independent(&law, n), n); + Ok(Outcome { fit: fit_law, control, same }) +} + +/// Every case, as a report: the pre-registered rule is that each case's chi-square, G, cell and +/// pair p are all at least 0.001 against the exact law, every chain requested came back and equals +/// the reference's, and, at the registered number of chains (`scale` 1), the independent-cells +/// control is rejected (chi-square p below 1e-6) while its cell family still passes. +pub fn report(e: &mut Engine

, scale: f64, seed: u64) -> Result { + let mut rep = crate::conform::Report::default(); + rep.line(format!("joint statistics against exact enumeration (chains scaled by {scale}, seed {seed})")); + for c in cases(scale) { + let t = std::time::Instant::now(); + let o = run_case(e, &c, seed)?; + let f = &o.fit; + let mut line = String::new(); + let _ = write!( + line, + " {}: {} chains, {} bins; exact law: chi2 {:.1} (p {:.3}), G {:.1} (p {:.3}), TV {:.4}, cell |z| {:.2} (p {:.3}), pair |z| {:.2} (p {:.3}); same as the reference {}/{}; {:.1} s", + c.name, f.samples, f.bins, f.chi2, f.p_chi2, f.g, f.p_g, f.tv, f.z_cell, f.p_cell, f.z_pair, f.p_pair, o.same, c.chains, t.elapsed().as_secs_f64() + ); + rep.line(line); + rep.line(format!( + " control, the same marginals with independent cells: chi2 {:.1} on {} bins (p {:.2e}), cell |z| {:.2} (p {:.3}), pair |z| {:.1} (p {:.2e})", + o.control.chi2, o.control.bins, o.control.p_chi2, o.control.z_cell, o.control.p_cell, o.control.z_pair, o.control.p_pair + )); + let ok = f.p_chi2 >= 1e-3 && f.p_g >= 1e-3 && f.p_cell >= 1e-3 && f.p_pair >= 1e-3; + rep.check(ok, format!("{}: the joint law is the exact law (every p at least 0.001)", c.name)); + rep.check(o.same == c.chains && f.samples == c.chains, format!("{}: every chain requested came back, its final state the reference's", c.name)); + if scale >= 1.0 { + rep.check(o.control.p_chi2 < 1e-6 && o.control.p_cell >= 1e-3, format!("{}: the independent-cells control is rejected (chi-square p below 1e-6) and its cell family passes", c.name)); + } + } + Ok(rep) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn index_round_trips() { + for k in 0..243 { + assert_eq!(index(&state_of(k, 5)), k); + } + } + + #[test] + fn the_law_sums_to_one_and_the_schedule_is_the_anneal() { + for c in cases(0.0) { + let w = c.landscape.lower(); + let betas: Vec = c.temps.iter().map(|t| 1.0 / t).collect(); + let law = exact_law(&w, &c.start, &betas, c.final_t0); + let s: f64 = law.iter().sum(); + assert!((s - 1.0).abs() < 1e-12, "{}: {s}", c.name); + if let Some((t0, sweeps)) = c.anneal { + for r in 0..50 { + let ch = chain_seed(9, r); + assert_eq!(reference(&w, &c.start, &betas, true, ch), anneal(&w, &c.start, t0, sweeps, ch).state, "{}", c.name); + } + } + } + } + + #[test] + fn the_reference_meets_the_exact_law_and_the_control_fails() { + // the dense case on the CPU reference: 100,000 chains + let c = cases(0.5).remove(2); + let w = c.landscape.lower(); + let betas: Vec = c.temps.iter().map(|t| 1.0 / t).collect(); + let law = exact_law(&w, &c.start, &betas, false); + let mut counts = vec![0u64; law.len()]; + for r in 0..c.chains { + counts[index(&reference(&w, &c.start, &betas, false, chain_seed(3, r)))] += 1; + } + let f = fit(&counts, &law, w.n()); + assert!(f.p_chi2 > 1e-3 && f.p_g > 1e-3 && f.p_cell > 1e-3 && f.p_pair > 1e-3, "{f:?}"); + let ctl = fit(&counts, &independent(&law, w.n()), w.n()); + assert!(ctl.p_chi2 < 1e-6, "{ctl:?}"); + assert!(ctl.p_cell > 1e-3, "the control has the right marginals: {ctl:?}"); + } + + /// Rule 3 counts against the chains requested: a run that lost some is not a pass. + #[test] + fn a_run_that_lost_chains_fails_the_report() { + use crate::engine::Engine; + use crate::model::ModelPort; + use crate::port::{ChainWords, Error, Port, ResultWords, batch_plain}; + use std::time::Duration; + struct Lossy(ModelPort); + impl Port for Lossy { + fn write(&mut self, a: u16, v: u32) -> Result<(), Error> { + self.0.write(a, v) + } + fn read(&mut self, a: u16) -> Result { + self.0.read(a) + } + fn wait_idle(&mut self, t: Duration) -> Result<(), Error> { + self.0.wait_idle(t) + } + fn batch(&mut self, chains: &[ChainWords], t: Duration) -> Result, Error> { + let mut out = batch_plain(self, chains, t)?; + out.pop(); + Ok(out) + } + } + let mut e = Engine::open(Lossy(ModelPort::new())).unwrap(); + assert!(report(&mut e, 0.002, 1).is_err()); + } + + #[test] + fn the_tails_are_right() { + // chi-square with 10 degrees of freedom: P(X > 18.307) = 0.05; with 1000: P(X > 1074.68) = 0.05 + assert!((gamma_q(5.0, 18.307 / 2.0) - 0.05).abs() < 1e-4); + assert!((gamma_q(500.0, 1074.68 / 2.0) - 0.05).abs() < 2e-3); + assert!((erfc(1.959_964 / std::f64::consts::SQRT_2) - 0.05).abs() < 1e-6); + } +} diff --git a/wai/wai-quantum-landscape-fpga/src/latency.rs b/wai/wai-quantum-landscape-fpga/src/latency.rs new file mode 100644 index 000000000..27cf59abe --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/latency.rs @@ -0,0 +1,251 @@ +//! The processor-to-logic latency, measured on the board: no primary source gives it for this part, +//! so it is timed here. Each access is timed alone with the processor's generic timer (CNTVCT_EL0, +//! read behind an ISB), many times, and reported as a distribution with the timer's own cost beside +//! it; the bulk paths (a DMA list, a batch of chains) are timed end to end. + +use crate::engine::Engine; +use crate::exact::cases; +use crate::member::{lowered, plan, run_schedule}; +use crate::port::Port; +use crate::regs::*; +use std::fmt::Write as _; +use std::time::Instant; +use wai_quantum::quantum_landscape::sample::{chain_seed, cuts}; + +#[cfg(target_arch = "aarch64")] +#[inline(always)] +pub fn ticks() -> u64 { + let t: u64; + unsafe { core::arch::asm!("isb", "mrs {0}, cntvct_el0", out(reg) t) }; + t +} +#[cfg(target_arch = "aarch64")] +pub fn tick_hz() -> f64 { + let f: u64; + unsafe { core::arch::asm!("mrs {0}, cntfrq_el0", out(reg) f) }; + f as f64 +} +#[cfg(not(target_arch = "aarch64"))] +pub fn ticks() -> u64 { + use std::sync::OnceLock; + static T0: OnceLock = OnceLock::new(); + T0.get_or_init(Instant::now).elapsed().as_nanos() as u64 +} +#[cfg(not(target_arch = "aarch64"))] +pub fn tick_hz() -> f64 { + 1e9 +} + +/// Waits for every access before it to complete, the response included: a store alone is timed +/// only to its issue. +#[inline(always)] +pub fn dsb() { + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!("dsb sy") + }; +} + +/// A distribution of times, in nanoseconds. +pub struct Dist(pub Vec); + +impl Dist { + fn q(&self, f: f64) -> f64 { + let mut v = self.0.clone(); + v.sort_by(|a, b| a.partial_cmp(b).unwrap()); + v[((v.len() - 1) as f64 * f).round() as usize] + } + pub fn line(&self, what: &str) -> String { + let mean = self.0.iter().sum::() / self.0.len() as f64; + format!( + " {what:58} median {:7.0} ns p10 {:7.0} p90 {:7.0} p99 {:7.0} max {:8.0} mean {:7.0} (n {})", + self.q(0.5), + self.q(0.1), + self.q(0.9), + self.q(0.99), + self.q(1.0), + mean, + self.0.len() + ) + } +} + +/// Times `f` alone, `n` times, after `n / 10` unrecorded warm-up calls. +pub fn time_each(n: usize, mut f: impl FnMut()) -> Dist { + let ns = 1e9 / tick_hz(); + for _ in 0..n / 10 { + f(); + } + let mut v = Vec::with_capacity(n); + for _ in 0..n { + let a = ticks(); + f(); + let b = ticks(); + v.push((b - a) as f64 * ns); + } + Dist(v) +} + +/// The header every latency report starts with. +pub fn header(link: &str) -> String { + let mut s = String::new(); + let _ = writeln!(s, "processor-to-logic latency, {link} link: one board, the engine at its measured clock"); + let _ = writeln!(s, " timer: CNTVCT_EL0 at {:.3} MHz, one tick {:.1} ns", tick_hz() / 1e6, 1e9 / tick_hz()); + s.push_str(&time_each(20_000, || {}).line("the timer alone (two reads, an ISB each)")); + s.push('\n'); + s +} + +/// A 64-level table of 128 fields each, the largest load a job makes: 32,832 register writes. +fn big_table(beta0: f64) -> Vec> { + (0..64).map(|l| (-64..64).map(|h| cuts(h, 1, beta0 + 0.01 * l as f64)).collect()).collect() +} + +/// End-to-end timings that every link has: a full table load, and chains run as a batch. +pub fn bulk_paths(e: &mut Engine

, label: &str, chains: u64) -> Result { + let mut s = String::new(); + let (ta, tb) = (big_table(0.2), big_table(0.3)); + let mut times = Vec::new(); + for k in 0..6 { + let t = Instant::now(); + e.load_table(-64, 7, -64, if k % 2 == 0 { &ta } else { &tb }).map_err(|x| x.0)?; + times.push(t.elapsed().as_secs_f64()); + } + times.sort_by(|a, b| a.partial_cmp(b).unwrap()); + let writes = 64 * (1 + 4 * 128) + 3; + let _ = writeln!(s, " {label}: a full table (64 levels x 128 fields, {writes} register writes): median {:.2} ms of 6, {:.0} ns a write", times[3] * 1e3, times[3] * 1e9 / writes as f64); + // read one entry back: the load is real + let probe = e.table_entry(5 * 128 + 70).map_err(|x| x.0)?; + if probe != tb[5][70] { + return Err(format!("{label}: the table reads back {probe:?}, want {:?}", tb[5][70])); + } + let c = cases(1.0).remove(0); + let w = c.landscape.lower(); + let l = lowered(&w); + e.load(&l).map_err(|x| x.0)?; + let seg = plan(&l, &c.temps)?; + let list: Vec<(Vec, u64)> = (0..chains).map(|r| (c.start.clone(), chain_seed(11, r))).collect(); + run_schedule(e, &l, &seg, false, &list[..list.len().min(256)], 0, MODE_GIBBS)?; + let t = Instant::now(); + run_schedule(e, &l, &seg, false, &list, 0, MODE_GIBBS)?; + let dt = t.elapsed().as_secs_f64(); + let _ = writeln!( + s, + " {label}: {chains} chains of {} cells x {} sweeps: {:.3} s, {:.2} us a chain, {:.0} chains/s", + l.n, + c.temps.len(), + dt, + dt * 1e6 / chains as f64, + chains as f64 / dt + ); + Ok(s) +} + +#[cfg(target_os = "linux")] +pub fn axi(p: &mut crate::axi::BoardAxi, n: usize) -> String { + use crate::axi::*; + let mut s = header("AXI"); + s.push_str(&time_each(n, || { + std::hint::black_box(p.signature()); + }) + .line("EMIO signature read (a processor GPIO register)")); + s.push('\n'); + s.push_str(&time_each(n, || { + std::hint::black_box(p.rd_raw(WRAP_ID)); + }) + .line("AXI-Lite read, a link register")); + s.push('\n'); + s.push_str(&time_each(n, || { + std::hint::black_box(p.rd_raw(ID)); + }) + .line("AXI-Lite read, an engine register")); + s.push('\n'); + s.push_str(&time_each(n, dsb).line("a DSB alone")); + s.push('\n'); + s.push_str(&time_each(n, || { + p.wr_raw(DMA_COUNT, 0); + dsb(); + }) + .line("AXI-Lite write and its response (DSB), a link register")); + s.push('\n'); + s.push_str(&time_each(n, || { + p.wr_raw(SEL, 0); + dsb(); + }) + .line("AXI-Lite write and its response (DSB), an engine register")); + s.push('\n'); + let t = std::time::Instant::now(); + for _ in 0..n { + p.wr_raw(SEL, 0); + } + dsb(); + let _ = writeln!(s, " AXI-Lite writes back to back, no DSB between: {:.0} ns each over {n}", t.elapsed().as_secs_f64() * 1e9 / n as f64); + s.push_str(&time_each(n, || { + p.wr_raw(SEL, 0); + std::hint::black_box(p.rd_raw(FIELD)); + }) + .line("AXI-Lite write then read (select a cell, read its field)")); + s.push('\n'); + s.push_str(&time_each(n, || { + std::hint::black_box(p.rd(ID).ok()); + }) + .line("guarded read, as every job access goes (signature, then read)")); + s.push('\n'); + let one = [(SEL, 0u32)]; + s.push_str(&time_each(n / 20, || { + p.dma_list(&one, std::time::Duration::from_secs(1)).expect("DMA"); + }) + .line("a 1-entry write list by DMA, kick to done (4 writes, polls)")); + s.push('\n'); + let page: Vec<(u16, u32)> = (0..512).map(|k| (SEL, k as u32 & 63)).collect(); + let d = time_each(n / 50, || { + p.dma_list(&page, std::time::Duration::from_secs(1)).expect("DMA"); + }); + let med = d.q(0.5); + s.push_str(&d.line("a 512-entry write list by DMA (one page), kick to done")); + let _ = writeln!(s, "\n = {:.1} ns an entry, {:.1} M register writes/s", med / 512.0, 512.0 / med * 1e3); + let d = time_each(n / 50, || { + p.write_back(128, std::time::Duration::from_secs(1)).expect("write-back"); + }); + s.push_str(&d.line("128 chains' results written back (one page), kick to read")); + let _ = writeln!(s, "\n = {:.0} ns a chain", d.q(0.5) / 128.0); + s +} + +#[cfg(target_os = "linux")] +pub fn emio(p: &mut crate::emio::EmioPort, n: usize) -> String { + let mut s = header("EMIO"); + s.push_str(&time_each(n, || { + std::hint::black_box(p.read(ID).ok()); + }) + .line("EMIO register read (handshake over GPIO)")); + s.push('\n'); + s.push_str(&time_each(n, || { + p.write(SEL, 0).ok(); + }) + .line("EMIO register write (handshake over GPIO)")); + s.push('\n'); + s +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::model::ModelPort; + + /// The chain `bulk_paths` times, in the engine's own clocks: 4 a cell update, 8 cells, 4 sweeps, + /// 9 to prime the draws and 2 to start and end. The model counts them as the logic does: the + /// testbenches hold every read of CYCLES to it. The README's figure for the engine's share of a + /// chain is this count. + #[test] + fn the_timed_chain_keeps_the_engine_busy_this_many_clocks() { + let c = cases(1.0).remove(0); + let l = lowered(&c.landscape.lower()); + let seg = plan(&l, &c.temps).unwrap(); + let mut e = Engine::open(ModelPort::new()).unwrap(); + e.load(&l).unwrap(); + e.port.write(CONTROL, CTL_CLRCNT).unwrap(); + run_schedule(&mut e, &l, &seg, false, &[(c.start.clone(), 1)], 0, MODE_GIBBS).unwrap(); + assert_eq!(e.counter(CYCLES).unwrap(), 4 * 8 * 4 + 9 + 2); + } +} diff --git a/wai/wai-quantum-landscape-fpga/src/lib.rs b/wai/wai-quantum-landscape-fpga/src/lib.rs new file mode 100644 index 000000000..234dc032e --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/lib.rs @@ -0,0 +1,24 @@ +//! An FPGA board as a member of `wai.quantum.landscape/1`: the settle and sample kernels of the +//! energy-landscape job in programmable logic (`rtl/`), the register-level model the logic is +//! tested against, and the host that runs jobs on the board, holds it to the conformance set, +//! and meters its power. Classical throughout: three-state cells and a counter-based random +//! stream, no quantum effect. + +pub mod axi; +pub mod conform; +pub mod engine; +pub mod exact; +pub mod latency; +pub mod member; +pub mod model; +pub mod port; +pub mod regs; +pub mod script; + +pub mod power; + +// The board's own side: Linux's /dev/mem, its constants, and the kernel's FPGA manager. +#[cfg(target_os = "linux")] +pub mod board; +#[cfg(target_os = "linux")] +pub mod emio; diff --git a/wai/wai-quantum-landscape-fpga/src/main.rs b/wai/wai-quantum-landscape-fpga/src/main.rs new file mode 100644 index 000000000..d2fe8bde4 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/main.rs @@ -0,0 +1,437 @@ +//! wai-quantum-landscape-fpga: the command line. Board commands run on the board's own Linux, as root (for +//! /dev/mem). `selftest`, `gen-tb`, `analyze`, `joint --model` and `landscape --model` run anywhere. + +use serde_json::Value; +#[cfg(target_os = "linux")] +use std::fmt::Write as _; +use std::process::exit; +use wai_quantum::quantum_landscape::energy::Landscape; +use wai_quantum::quantum_landscape::job; +use wai_quantum_landscape_fpga::conform::{self, Report}; +use wai_quantum_landscape_fpga::engine::Engine; +#[cfg(target_os = "linux")] +use wai_quantum_landscape_fpga::engine::Loaded; +use wai_quantum_landscape_fpga::member::{BoardInfo, BoardMember, lowered, plan}; +use wai_quantum_landscape_fpga::model::ModelPort; +use wai_quantum_landscape_fpga::port::Port; +#[cfg(target_os = "linux")] +use wai_quantum_landscape_fpga::port::Error; +use wai_quantum_landscape_fpga::regs::*; +use wai_quantum_landscape_fpga::script::ScriptPort; + +fn usage() -> ! { + eprintln!( + "usage: wai-quantum-landscape-fpga \n\ + \x20 selftest [--scale X] [--seeds N] every check against the register-level model (no board)\n\ + \x20 gen-tb the RTL testbench's script, recorded from the model\n\ + \x20 analyze [--predict mW] a power log, summarised\n\ + on the board, as root:\n\ + \x20 load load the bitstream, prove the load, check the engine answers\n\ + \x20 status engine, clock and power\n\ + \x20 conform [--scale X] the conformance set, random settles, field read-back\n\ + \x20 agree [--seeds N] every worked example, board against the CPU reference\n\ + \x20 landscape [--key FILE | --demo-key | --unsealed]\n\ + \x20 a job of wai.quantum.landscape/1 on the board, sealed\n\ + \x20 throughput clocks, jobs and operations a second, from the counters\n\ + \x20 meter [--predict mW] [--null] [--cores K]\n\ + \x20 run/halt board power; classes t0-recall gibbs-recall t0-idle\n\ + \x20 clock pl_clk0 = 1500/div0 MHz, measured back by the engine\n\ + \x20 release the EMIO banks back as the board boots\n\ + board commands take --core C on the multi-core bitstream" + ); + exit(2) +} + +fn flag(args: &[String], name: &str) -> Option { + let i = args.iter().position(|a| a == name)?; + let v = args.get(i + 1).unwrap_or_else(|| die(format!("{name} needs a value"))); + Some(v.parse().unwrap_or_else(|_| die(format!("{name}: `{v}` is not a value it takes")))) +} + +fn die(e: impl std::fmt::Display) -> ! { + eprintln!("wai-quantum-landscape-fpga: {e}"); + exit(1) +} + +fn finish(rep: &Report) -> ! { + print!("{}", rep.text); + println!("{} checks, {} failed", rep.checks, rep.failures.len()); + exit(if rep.failures.is_empty() { 0 } else { 1 }) +} + +/// The dense recall landscape the power classes run: 8 stored patterns on 64 cells, and a cue 30% +/// corrupted. +fn recall() -> (Landscape, Vec) { + let mut z = 0x7EC4u64; + let mut next = || { + z = z.wrapping_add(GOLDEN); + let mut r = z; + r = (r ^ (r >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9); + r = (r ^ (r >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB); + r ^ (r >> 31) + }; + let pats: Vec> = (0..8).map(|_| (0..64).map(|_| if next() & 1 == 0 { 1 } else { -1 }).collect()).collect(); + let mut l = Landscape::new(64); + for i in 0..64 { + for j in (i + 1)..64 { + let s: i64 = pats.iter().map(|p| p[i] * p[j]).sum(); + if s != 0 { + l.couple(i, j, s.signum() as i8); + } + } + } + let mut cue: Vec = pats[0].iter().map(|&x| x as i8).collect(); + for _ in 0..19 { + let i = (next() % 64) as usize; + cue[i] = -cue[i]; + } + (l, cue) +} + +fn model_member() -> BoardMember { + let mut m = BoardMember::new(Engine::open(ModelPort::new()).unwrap_or_else(|e| die(e)), model_info()); + let t = m.earn().unwrap_or_else(|e| die(e)); + print!("{t}"); + m +} + +fn key(args: &[String]) -> Option { + use wai_quantum::ed25519_dalek::SigningKey; + if args.iter().any(|a| a == "--unsealed") { + return None; + } + if args.iter().any(|a| a == "--demo-key") { + return Some(SigningKey::from_bytes(&[42; 32])); + } + let path = flag::(args, "--key") + .or_else(|| std::env::var("WAI_QUANTUM_KEY").ok()) + .unwrap_or_else(|| format!("{}/.config/wai/quantum-key", std::env::var("HOME").unwrap_or_else(|_| "/root".into()))); + let text = match std::fs::read_to_string(&path) { + Ok(t) => t, + Err(_) => { + let mut seed = [0u8; 32]; + use std::io::Read; + std::fs::File::open("/dev/urandom").and_then(|mut f| f.read_exact(&mut seed)).unwrap_or_else(|e| die(format!("no random source for a key: {e}"))); + let t: String = seed.iter().map(|b| format!("{b:02x}")).collect(); + if let Some(d) = std::path::Path::new(&path).parent() { + let _ = std::fs::create_dir_all(d); + } + #[cfg(unix)] + { + use std::io::Write; + use std::os::unix::fs::OpenOptionsExt; + std::fs::OpenOptions::new().write(true).create_new(true).mode(0o600).open(&path).and_then(|mut f| f.write_all(format!("{t}\n").as_bytes())).unwrap_or_else(|e| die(format!("{path}: {e}"))); + } + eprintln!("made a signing key at {path}"); + t + } + }; + let t = text.trim(); + let mut seed = [0u8; 32]; + if t.len() != 64 { + die(format!("{path}: a key file holds 64 hex digits")); + } + for (i, b) in seed.iter_mut().enumerate() { + *b = u8::from_str_radix(&t[2 * i..2 * i + 2], 16).unwrap_or_else(|_| die(format!("{path}: not hex"))); + } + Some(SigningKey::from_bytes(&seed)) +} + +/// The seed the joint-statistics test is registered at (`measurements/2026-11-06/JOINT-PREREG.txt`). +const JOINT_SEED: u64 = 2027; + +fn model_info() -> BoardInfo { + BoardInfo { name: "model".into(), description: "the register-level model of the engine, in software".into() } +} + +/// The board commands, on any port: the whole board, or one core of the multi-core bitstream. +fn on_board(cmd: &str, args: &[String], port: P, info: BoardInfo) { + let engine = Engine::open(port).unwrap_or_else(|e| die(e)); + let mut m = BoardMember::new(engine, info); + match cmd { + "conform" => { + let mut rep = conform::full(&m, flag(args, "--scale").unwrap_or(1.0)).unwrap_or_else(|e| die(e)); + let f = conform::fields(&m, 64).unwrap_or_else(|e| die(e)); + rep.text += &f.text; + rep.checks += f.checks; + rep.failures.extend(f.failures); + let ok = m.engine.borrow_mut().alive().is_ok(); + rep.check(ok, "the engine was not reloaded during the run: no other session replaced it"); + finish(&rep) + } + "agree" => { + let t = m.earn().unwrap_or_else(|e| die(e)); + print!("{t}"); + println!("parity earned on this board: settle {}, sample {}", m.settle_parity.label(), m.sample_parity.label()); + let rep = conform::agree(&m, flag(args, "--seeds").unwrap_or(200)).unwrap_or_else(|e| die(e)); + finish(&rep) + } + "landscape" => { + let op = args.get(1).cloned().unwrap_or_else(|| usage()); + let file = args.get(2).cloned().unwrap_or_else(|| usage()); + let text = if file == "-" { + let mut s = String::new(); + std::io::Read::read_to_string(&mut std::io::stdin(), &mut s).unwrap_or_else(|e| die(e)); + s + } else { + std::fs::read_to_string(&file).unwrap_or_else(|e| die(e)) + }; + let request: Value = serde_json::from_str(&text).unwrap_or_else(|e| die(format!("the request is not JSON: {e}"))); + let c = wai_quantum::quantum_landscape::member::certify(&m).unwrap_or_else(|e| die(e)); + let answer = match job::call_certified(&c, &op, &request, wai_quantum::quantum_landscape::MAX_JOB_BYTES) { + Ok(a) => a, + Err(r) => die(r.plain()), + }; + let out = match key(args) { + Some(k) if op != "examples" => job::seal(&request, answer, &k), + _ => answer, + }; + println!("{}", serde_json::to_string_pretty(&out).unwrap()); + } + "joint" => { + let mut e = m.engine.borrow_mut(); + let rep = wai_quantum_landscape_fpga::exact::report(&mut e, flag(args, "--scale").unwrap_or(1.0), flag(args, "--seed").unwrap_or(JOINT_SEED)).unwrap_or_else(|x| die(x)); + drop(e); + let ok = m.engine.borrow_mut().alive().is_ok(); + let mut rep = rep; + rep.check(ok, "the engine was not reloaded during the run: no other session replaced it"); + finish(&rep) + } + "status" => { + let mut e = m.engine.borrow_mut(); + let t0 = std::time::Instant::now(); + let u0 = e.counter(UPTIME).unwrap_or_else(|x| die(x)); + std::thread::sleep(std::time::Duration::from_millis(500)); + let u1 = e.counter(UPTIME).unwrap_or_else(|x| die(x)); + println!("engine answers: ID and version {VERSION_VALUE:#010x}; measured clock {:.3} MHz", (u1 - u0) as f64 / t0.elapsed().as_secs_f64() / 1e6); + } + "throughput" => { + let (l, cue) = recall(); + let w = l.lower(); + let lw = lowered(&w); + let seg = plan(&lw, &[0.25]).unwrap_or_else(|x| die(x)).remove(0); + let mut e = m.engine.borrow_mut(); + e.load(&lw).unwrap_or_else(|x| die(x)); + e.load_table(seg.win_lo, seg.wbits, seg.first, &seg.levels).unwrap_or_else(|x| die(x)); + e.chain(1).unwrap_or_else(|x| die(x)); + for (name, mode, bound) in [("settle, dense 64 (recall cue)", MODE_T0, 60u32), ("sample, sequential, 64 cells, 8 sweeps at T = 0.25", MODE_GIBBS, 8)] { + e.set_boundary(&cue).unwrap_or_else(|x| die(x)); + e.run_repeat(mode, bound, 8, false).unwrap_or_else(|x| die(x)); + std::thread::sleep(std::time::Duration::from_millis(200)); + let (t0, j0, u0, c0, y0) = (std::time::Instant::now(), e.counter(JOBS).unwrap(), e.counter(UPDATES).unwrap(), e.counter(UPTIME).unwrap(), e.counter(CYCLES).unwrap()); + std::thread::sleep(std::time::Duration::from_secs(2)); + let (dt, j1, u1, c1, y1) = (t0.elapsed().as_secs_f64(), e.counter(JOBS).unwrap(), e.counter(UPDATES).unwrap(), e.counter(UPTIME).unwrap(), e.counter(CYCLES).unwrap()); + e.halt().unwrap(); + let jobs = (j1 - j0) as f64 / dt; + let acc = if mode == MODE_T0 { w.settle(&cue, bound).accumulates as f64 * jobs } else { jobs * f64::from(bound) * lw.nonzeros() as f64 }; + println!("{name}: clock {:.3} MHz, {:.1} clocks a job, {jobs:.0} jobs/s, {:.3e} cell updates/s, {acc:.3e} accumulates/s", (c1 - c0) as f64 / dt / 1e6, (y1 - y0) as f64 / (j1 - j0).max(1) as f64, (u1 - u0) as f64 / dt); + } + } + _ => usage(), + } +} + +#[cfg(target_os = "linux")] +fn meter_class(e: &mut Engine

, class: &str, plan_m: &wai_quantum_landscape_fpga::power::Plan, log: &mut String) -> Vec { + let (l, cue) = recall(); + let lw = lowered(&l.lower()); + let seg = plan(&lw, &[0.25]).unwrap_or_else(|x| die(x)).remove(0); + let class = class.to_string(); + let mut start = move |e: &mut Engine

| -> Result<(), Error> { + match class.as_str() { + "t0-recall" => { + e.load(&lw)?; + e.set_boundary(&cue)?; + e.run_repeat(MODE_T0, 60, 1, false) + } + "gibbs-recall" => { + e.load(&lw)?; + e.load_table(seg.win_lo, seg.wbits, seg.first, &seg.levels)?; + e.chain(1)?; + e.set_boundary(&cue)?; + e.run_repeat(MODE_GIBBS, 8, 8, true) + } + "t0-idle" => { + e.load(&Loaded { n: 64, rows: vec![vec![]; 64], fields: vec![0; 64], cost: 0 })?; + e.set_boundary(&[0; 64])?; + e.run_repeat(MODE_T0, 0, 1, false) + } + other => Err(Error(format!("unknown class {other}"))), + } + }; + wai_quantum_landscape_fpga::power::meter(e, plan_m, &mut start, log).unwrap_or_else(|x| die(x)) +} + +#[cfg(target_os = "linux")] +enum Link { + Axi(wai_quantum_landscape_fpga::axi::BoardAxi), + Emio(wai_quantum_landscape_fpga::emio::EmioPort), +} + +/// The loaded design's link: AXI if its signature is on EMIO bank 3 (a GPIO read, safe whatever is +/// loaded), else EMIO; `--link` insists on one. +#[cfg(target_os = "linux")] +fn open_link(args: &[String]) -> Link { + let axi = match flag::(args, "--link").as_deref() { + Some("axi") => true, + Some("emio") => false, + Some(o) => die(format!("--link {o}: axi or emio")), + None => wai_quantum_landscape_fpga::axi::signature_present(), + }; + if axi { + Link::Axi(wai_quantum_landscape_fpga::axi::open().unwrap_or_else(|e| die(e))) + } else { + Link::Emio(wai_quantum_landscape_fpga::emio::EmioPort::open().unwrap_or_else(|e| die(e))) + } +} + +#[cfg(target_os = "linux")] +macro_rules! with_link { + ($args:expr, $p:ident => $body:expr) => { + match open_link($args) { + Link::Axi($p) => $body, + Link::Emio($p) => $body, + } + }; +} + +fn main() { + let args: Vec = std::env::args().skip(1).collect(); + let cmd = args.first().map(|s| s.as_str()).unwrap_or_else(|| usage()); + match cmd { + "selftest" => { + let scale = flag(&args, "--scale").unwrap_or(0.02); + let m = model_member(); + let mut rep = conform::full(&m, scale).unwrap_or_else(|e| die(e)); + let joint = wai_quantum_landscape_fpga::exact::report(&mut m.engine.borrow_mut(), 0.002, JOINT_SEED).unwrap_or_else(|e| die(e)); + for r in [conform::fields(&m, 4).unwrap_or_else(|e| die(e)), conform::agree(&m, flag(&args, "--seeds").unwrap_or(3)).unwrap_or_else(|e| die(e)), joint] { + rep.text += &r.text; + rep.checks += r.checks; + rep.failures.extend(r.failures); + } + finish(&rep) + } + "gen-tb" => { + let out = args.get(1).unwrap_or_else(|| usage()); + let port = if args.iter().any(|a| a == "--axi") { ScriptPort::axi() } else { ScriptPort::new() }; + let m = BoardMember::new(Engine::open(port).unwrap_or_else(|e| die(e)), BoardInfo::default()); + conform::tb_session(&m).unwrap_or_else(|e| die(e)); + let e = m.engine.borrow(); + std::fs::write(out, &e.port.text).unwrap_or_else(|e| die(e)); + println!("{} lines, {} checked reads -> {out}", e.port.text.lines().count(), e.port.reads); + } + "landscape" if args.iter().any(|a| a == "--model") => on_board(cmd, &args, ModelPort::new(), model_info()), + "joint" if args.iter().any(|a| a == "--model") => { + let mut e = Engine::open(ModelPort::new()).unwrap_or_else(|e| die(e)); + let rep = wai_quantum_landscape_fpga::exact::report(&mut e, flag(&args, "--scale").unwrap_or(1.0), flag(&args, "--seed").unwrap_or(JOINT_SEED)).unwrap_or_else(|e| die(e)); + finish(&rep) + } + "analyze" => { + let f = args.get(1).unwrap_or_else(|| usage()); + let text = std::fs::read_to_string(f).unwrap_or_else(|e| die(e)); + let pts = wai_quantum_landscape_fpga::power::parse_log(&text); + print!("{}", wai_quantum_landscape_fpga::power::summarise(&pts, flag(&args, "--predict")).text); + } + #[cfg(target_os = "linux")] + "load" => { + let f = args.get(1).unwrap_or_else(|| usage()); + // the lock first: a reload waits for the job that holds the board + let l = wai_quantum_landscape_fpga::board::lock().unwrap_or_else(|e| die(e)); + println!("{}", wai_quantum_landscape_fpga::board::load_bitstream(f, &l).unwrap_or_else(|e| die(e))); + let link = with_link!(&args, p => { let name = p.name(); Engine::open(p).unwrap_or_else(|e| die(e)); name }); + println!("the engine answers with its ID and version, over its {link} link"); + } + #[cfg(target_os = "linux")] + "foreign" => { + // for the scripts: this tool and its parents are left out, so a script need not know its own + let f = wai_quantum_landscape_fpga::board::foreign_sessions(); + if !f.is_empty() { + println!("{f}"); + exit(3); + } + } + #[cfg(target_os = "linux")] + "ps-ports" => { + let (ok, text) = wai_quantum_landscape_fpga::axi::ps_ports().unwrap_or_else(|e| die(e)); + println!("{text}: {}", if ok { "they match" } else { "they do not match" }); + } + #[cfg(target_os = "linux")] + "release" => { + wai_quantum_landscape_fpga::emio::EmioPort::release_to_boot_state().unwrap_or_else(|e| die(e)); + println!("EMIO banks 3-5: inputs, outputs disabled, data 0"); + } + #[cfg(target_os = "linux")] + "clock" => { + let d: u32 = args.get(1).and_then(|v| v.parse().ok()).unwrap_or_else(|| usage()); + let _l = wai_quantum_landscape_fpga::board::lock().unwrap_or_else(|e| die(e)); + with_link!(&args, p => { + let mut e = Engine::open(p).unwrap_or_else(|e| die(e)); + let old = wai_quantum_landscape_fpga::board::set_pl0_div(d).unwrap_or_else(|e| die(e)); + std::thread::sleep(std::time::Duration::from_millis(100)); + let t0 = std::time::Instant::now(); + let u0 = e.counter(UPTIME).unwrap_or_else(|e| die(e)); + std::thread::sleep(std::time::Duration::from_secs(1)); + let u1 = e.counter(UPTIME).unwrap_or_else(|e| die(e)); + println!("PL0_REF_CTRL was {old:#x}; nominal {:.2} MHz; measured {:.4} MHz", 1500.0 / f64::from(d), (u1 - u0) as f64 / t0.elapsed().as_secs_f64() / 1e6); + }); + } + #[cfg(target_os = "linux")] + "meter" => { + let class = args.get(1).cloned().unwrap_or_else(|| usage()); + let passes: u32 = args.get(2).and_then(|v| v.parse().ok()).unwrap_or_else(|| usage()); + let settle_s: u64 = args.get(3).and_then(|v| v.parse().ok()).unwrap_or_else(|| usage()); + let samples: u32 = args.get(4).and_then(|v| v.parse().ok()).unwrap_or_else(|| usage()); + let plan_m = wai_quantum_landscape_fpga::power::Plan { passes, settle_s, samples, null: args.iter().any(|a| a == "--null") }; + let cores: u16 = flag(&args, "--cores").unwrap_or(1); + let _l = wai_quantum_landscape_fpga::board::lock().unwrap_or_else(|e| die(e)); + let mut log = String::new(); + let pts = with_link!(&args, port => { + let _ = writeln!(log, "# class {class} cores {cores} link {}", port.name()); + if cores > 1 { + let mut e = Engine::open(wai_quantum_landscape_fpga::port::BroadcastPort { inner: port, k: cores }).unwrap_or_else(|x| die(x)); + meter_class(&mut e, &class, &plan_m, &mut log) + } else { + let mut e = Engine::open(port).unwrap_or_else(|x| die(x)); + meter_class(&mut e, &class, &plan_m, &mut log) + } + }); + print!("{log}"); + for l in wai_quantum_landscape_fpga::power::summarise(&pts, flag(&args, "--predict")).text.lines() { + println!("# {l}"); + } + } + #[cfg(target_os = "linux")] + "latency" => { + let n: usize = args.get(1).and_then(|v| v.parse().ok()).unwrap_or(100_000); + let _l = wai_quantum_landscape_fpga::board::lock().unwrap_or_else(|e| die(e)); + use wai_quantum_landscape_fpga::latency; + match open_link(&args) { + Link::Axi(mut p) => { + print!("{}", latency::axi(&mut p, n)); + let mut e = Engine::open(p).unwrap_or_else(|x| die(x)); + print!("{}", latency::bulk_paths(&mut e, "AXI, DMA and sequencer", 65_536).unwrap_or_else(|x| die(x))); + e.port.sequencer = false; + e.port.dma_min = usize::MAX; + print!("{}", latency::bulk_paths(&mut e, "AXI, plain register accesses", 16_384).unwrap_or_else(|x| die(x))); + println!(" AXI accesses {}, DMA lists {}, sequencer batches {}, write-backs {}", e.port.accesses, e.port.dma_lists, e.port.batches, e.port.write_backs); + } + Link::Emio(mut p) => { + print!("{}", latency::emio(&mut p, n / 4)); + let mut e = Engine::open(p).unwrap_or_else(|x| die(x)); + print!("{}", latency::bulk_paths(&mut e, "EMIO, plain register accesses", 4_096).unwrap_or_else(|x| die(x))); + } + } + } + #[cfg(target_os = "linux")] + "conform" | "agree" | "landscape" | "status" | "throughput" | "joint" => { + let _l = wai_quantum_landscape_fpga::board::lock().unwrap_or_else(|e| die(e)); + match (open_link(&args), flag::(&args, "--core")) { + (Link::Emio(mut port), Some(core)) => on_board(cmd, &args, wai_quantum_landscape_fpga::port::CorePort { inner: &mut port, core }, BoardInfo::default()), + (Link::Axi(_), Some(_)) => die("--core is for the multi-core EMIO build"), + (Link::Axi(p), None) => on_board(cmd, &args, p, BoardInfo::default()), + (Link::Emio(p), None) => on_board(cmd, &args, p, BoardInfo::default()), + } + } + _ => usage(), + } +} diff --git a/wai/wai-quantum-landscape-fpga/src/member.rs b/wai/wai-quantum-landscape-fpga/src/member.rs new file mode 100644 index 000000000..c0ea2f027 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/member.rs @@ -0,0 +1,493 @@ +//! The board as a member of `wai.quantum.landscape/1` (`extensions/quantum-landscape.md` §5): it +//! runs the two kernels and nothing else. The reader, the truth, the energy of what it returns, the +//! verdict, the replay digest and the seal stay on the host (`wai_quantum::quantum_landscape`). +//! +//! **The settle kernel** is the engine's T0 mode, whole-number arithmetic, so it gives the +//! reference's bits by construction; the conformance set's `settle` vectors hold it to them. +//! +//! **The sample kernel** takes the reference's draws: the engine counts `chain + j·GOLDEN` and mixes +//! it in logic, so the draw of cell `i` in sweep `k` is the top 53 bits of `out(chain, k·n + i + 1)`, +//! the reference's. The host gives it the cut points, computed with the reference's `cuts`, so the +//! fabric needs no exponential: per temperature level, a window of fields from `WIN_LO`. A field +//! outside the window takes the threshold, which equals the reference's draw only where that draw is +//! certain, so the host puts the window over every field a cell can reach whose draw is not certain +//! at any of the segment's temperatures, and refuses a job for which no window fits. The `chains` +//! vectors hold the result to the reference's bits. +//! +//! **A schedule** is one temperature a sweep, as the job gives it. The chains of a job run as one +//! batch ([`Engine::run_batch`]): on the AXI link the engine's sequencer runs them one after another +//! in fabric. A run of sweeps above 0 longer than the table holds goes in segments: the table is +//! rewritten, and every chain starts the next segment from where it ended with its draw counter at +//! the draw the reference takes next (sweep `k`'s draws are `k·n + i + 1`, whatever the sweeps +//! before it were). A sweep at 0 directly after sweeps above 0 is the engine's final synchronous +//! sweep; other sweeps at 0 run in its T0 mode, every sweep, as the reference's do: the engine stops +//! at a fixed point or a two-cycle, and past a two-cycle the state alternates, so one more sweep is +//! taken when the count left is odd. +//! +//! The ending, sweeps, accumulates and draws of a chain's `Outcome` come from the schedule and the +//! state, as the reference's do (`check_chain` fixes them for every member); the engine's own count +//! of sweeps is held to its segment here. +//! +//! What it has earned is not assumed, and not said by the member: the host certifies it +//! (`wai_quantum::quantum_landscape::member::certify`) by running the conformance set's `settle` +//! and `chains` vectors on the device, and, where those miss, the statistical battery. + +use crate::engine::{Engine, Loaded}; +use crate::port::Port; +use crate::regs::*; +use std::cell::RefCell; +use wai_quantum::quantum_landscape::conformance::MUST_TAKE_FIELD_BOUND; +use wai_quantum::quantum_landscape::member::{Chain, KERNEL_SAMPLE, KERNEL_SETTLE, Member, Parity, certify}; +use wai_quantum::quantum_landscape::sample::cuts; +use wai_quantum::quantum_landscape::settle::{Outcome, Term, Workload, threshold}; + +/// The conformance set a member is held to, as the repository holds it. +pub const VECTORS: &str = include_str!("../../quantum-conformance/landscape/vectors.json"); + +/// What the board is, as data: the member's name and its answers' label carry it. +#[derive(Clone, Debug)] +pub struct BoardInfo { + /// A short board name for the member id, `fpga:-landscape-64`. + pub name: String, + /// The board and part, in words, for the label. + pub description: String, +} + +impl Default for BoardInfo { + fn default() -> Self { + BoardInfo { name: "kv260".into(), description: "a KV260 board (xck26 programmable logic, four Cortex-A53 cores)".into() } + } +} + +pub struct BoardMember { + pub engine: RefCell>, + pub info: BoardInfo, + /// What the host's certification found, kept for display; the trait says nothing of parity. + pub settle_parity: Parity, + pub sample_parity: Parity, + /// Sample with every cell moved at once (JACOBI): not a kernel of the spec, only the negative + /// control the statistical battery must catch. + pub jacobi_control: std::cell::Cell, +} + +/// One segment of a sampling chain: up to `levels.len()` sweeps on one table. +#[derive(Clone, Debug)] +pub struct Segment { + pub sweeps: usize, + pub win_lo: i64, + pub wbits: u32, + pub first: i64, + pub levels: Vec>, +} + +fn certain(h: i64, cost: i64) -> (u64, u64) { + match threshold(h, cost) { + 1 => (0, 0), + -1 => (TWO53, TWO53), + _ => (0, TWO53), + } +} + +/// The workload as the engine holds it. +pub fn lowered(w: &Workload) -> Loaded { + let n = w.n(); + let zero = vec![0i8; n]; + Loaded { + n, + rows: (0..n).map(|i| w.row(i).map(|(j, v)| (j, v as i8)).collect()).collect(), + fields: (0..n).map(|i| w.field(&zero, i)).collect(), + cost: w.cost(), + } +} + +/// The workload as the engine holds it for sweeps at temperature 0 only, where fields and the cost +/// may exceed the engine's registers. A cell at temperature 0 compares its coupling sum `S`, which +/// lies in `[-d, d]` (`d` its couplings, at most 63), with two thresholds, `c - b` and `-c - b`: it +/// takes +1 above the first, -1 below the second, 0 between. Only where a threshold falls in +/// `[-d - 1, d + 1]` does it matter where; elsewhere only which side. So a field or a cost too large +/// for the engine is replaced by one that puts every threshold on the same side of every `S` the +/// cell can see, and the settle is the same, bit for bit. With a cost above `d + 1`, at most one of +/// a cell's thresholds can fall in that range, and the cost becomes `d + 1` with each field moved +/// to keep that threshold where it was. +pub fn lowered_settle(w: &Workload) -> Loaded { + let mut l = lowered(w); + if l.cost <= COST_MAX && l.fields.iter().all(|f| f.abs() <= FIELD_MAX) { + return l; + } + let d: i128 = 63; + let c = i128::from(l.cost); + let inside = |x: i128| (-d - 1..=d + 1).contains(&x); + if c <= d + 1 { + for b in l.fields.iter_mut() { + *b = (i128::from(*b)).clamp(-(c + d + 1), c + d + 1) as i64; + } + } else { + let t = d + 1; + l.cost = t as i64; + for b in l.fields.iter_mut() { + let (up, down) = (c - i128::from(*b), -c - i128::from(*b)); + *b = if inside(up) { + t - up + } else if inside(down) { + -t - down + } else if up < -d - 1 { + t + d + 1 + } else if down > d + 1 { + -(t + d + 1) + } else { + 0 + } as i64; + } + } + l +} + +/// Why the engine cannot hold a workload under a schedule, if it cannot: more variables than its 64 +/// cells, or, for sweeps above 0, a field or cost beyond its registers or uncertain fields wider +/// than its table's window. Sweeps at 0 it holds at any field ([`lowered_settle`]). The member +/// fails such a workload with a sentence, never with wrong bits; the checks hold it to that. +pub fn beyond(w: &Workload, temperatures: &[f64]) -> Option { + if w.n() > CELLS { + return Some(format!("{} variables, and the engine has {CELLS} cells", w.n())); + } + if temperatures.iter().all(|&t| t <= 0.0) { + return None; + } + let l = lowered(w); + if let Some(f) = l.fields.iter().find(|f| f.abs() > FIELD_MAX) { + return Some(format!("a field of {f} to sample, and the engine's field registers hold ±{FIELD_MAX}")); + } + if l.cost > COST_MAX { + return Some(format!("a cost of {} to sample, and the engine's cost register holds {COST_MAX}", l.cost)); + } + let mut k = 0; + while k < temperatures.len() { + let hot = temperatures[k] > 0.0; + let m = temperatures[k..].iter().take_while(|&&t| (t > 0.0) == hot).count(); + if hot { + if let Err(e) = plan(&l, &temperatures[k..k + m]) { + return Some(e); + } + } + k += m; + } + None +} + +/// The fields cell `i` can reach: its own field plus or minus its number of couplings. +fn reach(l: &Loaded) -> Vec { + let mut hs: Vec = Vec::new(); + for i in 0..l.n { + let d = l.rows[i].len() as i64; + hs.extend((l.fields[i] - d)..=(l.fields[i] + d)); + } + hs.sort_unstable(); + hs.dedup(); + hs +} + +/// The tables for a run at temperatures `temps` (each above 0), one segment per table. +pub fn plan(l: &Loaded, temps: &[f64]) -> Result, String> { + let hs = reach(l); + let (lo_r, hi_r) = (*hs.first().unwrap_or(&0), *hs.last().unwrap_or(&0)); + let mut out = Vec::new(); + let mut k = 0; + while k < temps.len() { + let mut take = (temps.len() - k).min(LEVELS); + loop { + let betas: Vec = temps[k..k + take].iter().map(|t| 1.0 / t).collect(); + // the fields whose draw is not certain at some temperature of the segment + let open: Vec = hs.iter().copied().filter(|&h| betas.iter().any(|&b| cuts(h, l.cost, b) != certain(h, l.cost))).collect(); + let (lo, hi) = match (open.first(), open.last()) { + (Some(&a), Some(&b)) => (a, b), + _ => (lo_r, lo_r), + }; + let span = (hi - lo + 1) as u64; + let wbits = 64 - (span - 1).leading_zeros().min(64); + let wbits = if span <= 1 { 0 } else { wbits }; + if wbits > MAX_WBITS { + return Err(format!( + "the fields whose draw is uncertain run from {lo} to {hi}, {span} of them, and the engine's table holds {TABLE} a temperature" + )); + } + let fit = (TABLE >> wbits).min(LEVELS); + if take > fit { + take = fit; + continue; + } + // every reachable field inside the window gets its exact pair + let (first, last) = (lo.max(lo_r), (lo + (1i64 << wbits) - 1).min(hi_r)); + let levels = betas.iter().map(|&b| if first <= last { (first..=last).map(|h| cuts(h, l.cost, b)).collect() } else { Vec::new() }).collect(); + out.push(Segment { sweeps: take, win_lo: lo, wbits, first, levels }); + break; + } + k += take; + } + Ok(out) +} + +/// Sampling chains through sweeps planned by [`plan`], the first of them sweep `first_sweep` of the +/// chain's schedule: segment by segment, every chain through each, a segment starting from where the +/// chain left the last one with its draw counter at the draw the reference takes next +/// (`out(seed, k·n + i + 1)` for cell `i` of sweep `k`). With `final_t0`, one synchronous sweep at +/// temperature 0 ends the last segment. `chains` are (start, seed); the result is each chain's +/// final state. `mode` is MODE_GIBBS, or MODE_JACOBI for the negative control. +pub fn run_schedule(e: &mut Engine

, l: &Loaded, segments: &[Segment], final_t0: bool, chains: &[(Vec, u64)], first_sweep: u64, mode: u32) -> Result>, String> { + let mut states: Vec> = chains.iter().map(|c| c.0.clone()).collect(); + let mut done = first_sweep; + for (s, seg) in segments.iter().enumerate() { + let last = s + 1 == segments.len(); + e.load_table(seg.win_lo, seg.wbits, seg.first, &seg.levels).map_err(|e| e.0)?; + let first_draw = done * l.n as u64 + 1; + let list: Vec<(Vec, u64)> = chains.iter().zip(&states).map(|(c, st)| (st.clone(), c.1.wrapping_add(GOLDEN.wrapping_mul(first_draw)))).collect(); + let runs = e.run_batch(mode, seg.sweeps as u32, 1, last && final_t0, &list).map_err(|e| e.0)?; + // a sampling job has no early end: the engine reports every sweep it was asked for + if let Some(r) = runs.iter().find(|r| r.steps != seg.sweeps as u32) { + return Err(format!("a chain ran {} sweeps of a segment of {}", r.steps, seg.sweeps)); + } + states = runs.into_iter().map(|r| r.state).collect(); + done += seg.sweeps as u64; + } + Ok(states) +} + +/// `sweeps` synchronous sweeps at temperature 0 from each state, every sweep run. +fn quench(e: &mut Engine

, states: &[Vec], sweeps: u32) -> Result>, String> { + let mut out = states.to_vec(); + if sweeps == 0 { + return Ok(out); + } + let runs = e.run_batch(MODE_T0, sweeps, 1, false, &states.iter().map(|s| (s.clone(), 0)).collect::>()).map_err(|e| e.0)?; + let mut odd = Vec::new(); + for (k, r) in runs.into_iter().enumerate() { + if r.term == TERM_2C && (sweeps - r.steps) % 2 == 1 { + odd.push(k); + } + out[k] = r.state; + } + if !odd.is_empty() { + let more = e.run_batch(MODE_T0, 1, 1, false, &odd.iter().map(|&k| (out[k].clone(), 0)).collect::>()).map_err(|e| e.0)?; + for (&k, r) in odd.iter().zip(more) { + out[k] = r.state; + } + } + Ok(out) +} + +impl BoardMember

{ + pub fn new(engine: Engine

, info: BoardInfo) -> Self { + BoardMember { engine: RefCell::new(engine), info, settle_parity: Parity::Uncertified, sample_parity: Parity::Uncertified, jacobi_control: std::cell::Cell::new(false) } + } + + /// Has the host certify the member, and keeps what it found for display. + pub fn earn(&mut self) -> Result { + let (settle, sample) = { + let c = certify(&*self)?; + (c.parity(KERNEL_SETTLE), c.parity(KERNEL_SAMPLE)) + }; + self.settle_parity = settle; + self.sample_parity = sample; + Ok(format!("certified by the host on the conformance set: settle {}, sample {}\n", settle.label(), sample.label())) + } + +} + +impl Member for BoardMember

{ + fn id(&self) -> String { + format!("fpga:{}-landscape-64", self.info.name) + } + + fn class(&self) -> &'static str { + "fpga" + } + + fn label(&self) -> String { + format!( + "A classical FPGA board running the settling model's two kernels: {}, up to 64 three-state cells in programmable logic, driven by the board's own processor. Energies are computed exactly on the host. The joule line is priced, as on every member; a reading of the board's power, where one is taken, stands beside it. No photonic hardware, custom chip or quantum effect is involved in this run.", + self.info.description + ) + } + + /// Declines only what `extensions/quantum-landscape.md` §5 lets a member decline: sampling a + /// workload whose field bound is above 2^31 − 1. (Sweeps at 0 it takes at any field: the host + /// maps them exactly, `lowered_settle`.) Everything else it takes, and what the engine cannot + /// hold, more than 64 variables or sampling fields beyond its 20-bit registers, it then fails + /// with a sentence: the spec does not let a member decline those. + fn takes(&self, w: &Workload, sampling: bool) -> Result<(), String> { + if sampling && w.field_bound() > MUST_TAKE_FIELD_BOUND { + return Err(format!( + "its fields reach {}, past 2^31 - 1, and the engine samples fields of at most ±{FIELD_MAX}", + w.field_bound() + )); + } + Ok(()) + } + + fn settle(&self, w: &Workload, start: &[i8], bound: u32) -> Result { + let l = lowered_settle(w); + self.engine.borrow_mut().load(&l).map_err(|e| e.0)?; + let r = self.engine.borrow_mut().run_t0(start, bound).map_err(|e| e.0)?; + let term = match r.term { + TERM_FP => Term::FixedPoint, + TERM_2C => Term::TwoCycle, + _ => Term::Bound, + }; + Ok(Outcome { state: r.state, sweeps: r.steps, term, accumulates: u64::from(r.steps) * l.nonzeros(), draws: 0 }) + } + + fn chains(&self, w: &Workload, chains: &[Chain], temperatures: &[f64]) -> Result, String> { + let l = if temperatures.iter().all(|&t| t <= 0.0) { lowered_settle(w) } else { lowered(w) }; + self.engine.borrow_mut().load(&l).map_err(|e| e.0)?; + let n = l.n; + if let Some(c) = chains.iter().find(|c| c.start.len() != n) { + return Err(format!("a start of {} cells for {n} variables", c.start.len())); + } + if temperatures.iter().any(|t| !t.is_finite()) { + return Err("a temperature that is not a number".into()); + } + let len = temperatures.len(); + let mut states: Vec> = chains.iter().map(|c| c.start.clone()).collect(); + let mut e = self.engine.borrow_mut(); + let mode = if self.jacobi_control.get() { MODE_JACOBI } else { MODE_GIBBS }; + let mut k = 0usize; + while k < len { + let cold = temperatures[k] <= 0.0; + let m = temperatures[k..].iter().take_while(|&&t| (t <= 0.0) == cold).count(); + if cold { + states = quench(&mut e, &states, m as u32)?; + k += m; + } else { + // the sweep at 0 that follows, if one does, is the engine's final sweep + let then_cold = k + m < len; + let segments = plan(&l, &temperatures[k..k + m])?; + let list: Vec<(Vec, u64)> = chains.iter().zip(&states).map(|(c, st)| (st.clone(), c.seed)).collect(); + states = run_schedule(&mut e, &l, &segments, then_cold, &list, k as u64, mode)?; + k += m + usize::from(then_cold); + } + } + let hot = temperatures.iter().filter(|&&t| t > 0.0).count() as u64; + Ok(states + .into_iter() + .map(|state| { + let term = if w.rests(&state) { Term::FixedPoint } else { Term::Bound }; + Outcome { state, sweeps: len as u32, term, accumulates: len as u64 * l.nonzeros(), draws: n as u64 * hot } + }) + .collect()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::model::ModelPort; + use wai_quantum::quantum_landscape::energy::Landscape; + + fn model() -> BoardMember { + BoardMember::new(Engine::open(ModelPort::new()).unwrap(), BoardInfo { name: "model".into(), description: "the model".into() }) + } + + /// Held to the reference on the model, and every field and the cost inside the registers. + fn same_as_reference(m: &BoardMember, l: &Landscape, start: &[i8]) { + let w = l.lower(); + let e = lowered_settle(&w); + assert!(e.cost <= COST_MAX && e.fields.iter().all(|f| f.abs() <= FIELD_MAX), "{e:?}"); + assert_eq!(m.settle(&w, start, 40).unwrap(), w.settle(start, 40)); + } + + fn pair(b0: i64, b1: i64, c: i64) -> Landscape { + let mut l = Landscape::new(4); + l.couple(0, 1, 1).couple(1, 2, -1).couple(2, 3, 1); + l.set_field(0, b0).set_field(1, b1).set_cost(c); + l + } + + #[test] + fn a_cost_too_large_keeps_each_threshold_where_it_matters() { + let m = model(); + let c = 1 << 40; + same_as_reference(&m, &pair(c, 0, c), &[1, 0, -1, 1]); // the upper threshold in reach + same_as_reference(&m, &pair(-c + 1, 0, c), &[1, 0, -1, 1]); // the lower one in reach + same_as_reference(&m, &pair(0, 3, c), &[1, 0, -1, 1]); // neither: always 0 + same_as_reference(&m, &pair(3 * c, 0, c), &[0, 0, 0, 0]); // both below: always +1 + same_as_reference(&m, &pair(-3 * c, 0, c), &[0, 0, 0, 0]); // both above: always -1 + same_as_reference(&m, &pair(2097152, -2097152, 1048576), &[0, 0, 0, 0]); + } + + #[test] + fn a_small_cost_with_a_field_too_large_is_clamped() { + let m = model(); + for c in [0, 1, 7, 64] { + same_as_reference(&m, &pair(1_000_000, -1_000_000, c), &[1, 0, -1, 1]); + same_as_reference(&m, &pair(c + 64 + 1, -1_000_000, c), &[0, 0, 0, 0]); + } + } + + #[test] + fn every_threshold_case_settles_as_the_reference_does() { + let m = model(); + let mut z = 0x001A_46E5u64; + let mut next = move || { + z = z.wrapping_add(GOLDEN); + crate::model::mix(z) + }; + for _ in 0..300 { + let n = 2 + (next() % 63) as usize; + let scale = 1i64 << (next() % 41); + let cost = if next() & 1 == 0 { (next() % 70) as i64 } else { (next() as i64 & i64::MAX) % scale }; + let mut l = Landscape::new(n); + for i in 0..n { + for j in (i + 1)..n { + if next() % 4 == 0 { + l.couple(i, j, if next() & 1 == 0 { 1 } else { -1 }); + } + } + // near a threshold, or anywhere + let b = match next() % 3 { + 0 => cost + (next() % 130) as i64 - 65, + 1 => -cost + (next() % 130) as i64 - 65, + _ => (next() as i64) % scale, + }; + l.set_field(i, b); + } + l.set_cost(cost); + let start: Vec = (0..n).map(|_| (next() % 3) as i8 - 1).collect(); + same_as_reference(&m, &l, &start); + } + } + + #[test] + fn a_workload_inside_the_registers_is_left_alone() { + let w = pair(5, -3, 2).lower(); + assert_eq!(lowered_settle(&w), lowered(&w)); + } + + #[test] + fn sampling_beyond_the_registers_is_refused() { + let m = model(); + let w = pair(1_000_000, 0, 1).lower(); + assert!(m.chains(&w, &[Chain { start: vec![0; 4], seed: 1 }], &[1.0, 0.0]).is_err()); + } + + /// A port that runs every sampled job one sweep short, by what it reports. + struct ShortSweeps(ModelPort); + impl Port for ShortSweeps { + fn write(&mut self, a: u16, v: u32) -> Result<(), crate::port::Error> { + self.0.write(a, v) + } + fn read(&mut self, a: u16) -> Result { + let v = self.0.read(a)?; + Ok(if a == STEPS { v.saturating_sub(1) } else { v }) + } + fn wait_idle(&mut self, t: std::time::Duration) -> Result<(), crate::port::Error> { + self.0.wait_idle(t) + } + } + + #[test] + fn a_chain_that_ran_the_wrong_number_of_sweeps_is_refused() { + let m = BoardMember::new(Engine::open(ShortSweeps(ModelPort::new())).unwrap(), BoardInfo::default()); + let w = pair(1, 0, 1).lower(); + let refused = m.chains(&w, &[Chain { start: vec![0; 4], seed: 1 }], &[1.5, 1.0, 0.5]).expect_err("the count of sweeps"); + assert!(refused.contains("sweeps of a segment"), "{refused}"); + } +} diff --git a/wai/wai-quantum-landscape-fpga/src/model.rs b/wai/wai-quantum-landscape-fpga/src/model.rs new file mode 100644 index 000000000..7124fa631 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/model.rs @@ -0,0 +1,379 @@ +//! A software model of `rtl/landscape_core.v` at the register port: the same bits, the same draw +//! order, the same cycle counts. The testbench replays a recording of this model against the RTL +//! and compares every read, so where the two disagree it is the RTL or this file, and the test says +//! which register. Fields are computed from the raw bits exactly as the RTL's cone does. + +use crate::port::{Error, Port}; +use crate::regs::*; +use std::time::Duration; + +/// SplitMix64's mix(), as the draw pipeline computes it. +pub fn mix(mut x: u64) -> u64 { + x ^= x >> 30; + x = x.wrapping_mul(0xBF58_476D_1CE4_E5B9); + x ^= x >> 27; + x = x.wrapping_mul(0x94D0_49BB_1331_11EB); + x ^ (x >> 31) +} + +#[derive(Clone)] +pub struct ModelPort { + mode: u32, + rep: bool, + final_t0: bool, + n_m1: u32, + cost: i64, + bound: u32, + spl: u32, + levels_m1: u32, + boundary: [u32; 4], + rows: Vec<[u32; 4]>, + fields: [i64; 64], + state: [u32; 4], + prev: [u32; 4], + tbl: Vec<(u64, u64)>, + tbl_addr: u32, + wa: u64, + wb_lo: u32, + tbl_q: (u64, u64), + x0: u64, + x_next: u64, + primed: bool, + win_lo: i64, + wbits: u32, + sel: u32, + done: bool, + term: u32, + steps: u32, + uptime: u64, + cycles: u64, + updates: u64, + jobs: u64, + rd_hi: u32, +} + +impl Default for ModelPort { + fn default() -> Self { + ModelPort { + mode: 0, + rep: false, + final_t0: false, + n_m1: 0, + cost: 0, + bound: 0, + spl: 1, + levels_m1: 0, + boundary: [0; 4], + rows: vec![[0; 4]; 64], + fields: [0; 64], + state: [0; 4], + prev: [0; 4], + tbl: vec![(0, 0); TABLE], + tbl_addr: 0, + wa: 0, + wb_lo: 0, + tbl_q: (0, 0), + x0: 0, + x_next: 0, + primed: false, + win_lo: 0, + wbits: 7, + sel: 0, + done: false, + term: 0, + steps: 0, + uptime: 0, + cycles: 0, + updates: 0, + jobs: 0, + rd_hi: 0, + } + } +} + +#[inline] +fn bit(words: &[u32; 4], b: usize) -> u32 { + (words[b >> 5] >> (b & 31)) & 1 +} +#[inline] +fn set2(words: &mut [u32; 4], cell: usize, v: u32) { + let b = 2 * cell; + words[b >> 5] = (words[b >> 5] & !(3 << (b & 31))) | ((v & 3) << (b & 31)); +} + +fn sext(v: u64, bits: u32) -> i64 { + let s = 64 - bits; + ((v << s) as i64) >> s +} + +impl ModelPort { + pub fn new() -> Self { + Self::default() + } + + /// The cone: h_i = sum_j (p_j - n_j) + b_i on the raw bits. + fn field(&self, st: &[u32; 4], i: usize) -> i64 { + let w = &self.rows[i]; + let mut h = 0i64; + for j in 0..64 { + let (wp, wn) = (bit(w, 2 * j), bit(w, 2 * j + 1)); + let (sp, sn) = (bit(st, 2 * j), bit(st, 2 * j + 1)); + h += ((wp & sp) | (wn & sn)) as i64 - ((wp & sn) | (wn & sp)) as i64; + } + h + self.fields[i] + } + + fn t0_next(&self, st: &[u32; 4]) -> [u32; 4] { + let mut ns = [0u32; 4]; + for i in 0..64 { + let h = self.field(st, i); + set2(&mut ns, i, (((h < -self.cost) as u32) << 1) | (h > self.cost) as u32); + } + ns + } + + fn draw(&self) -> u64 { + mix(self.x_next) >> 11 + } + + /// One cell's update: the S_IDX, S_TBL and S_COMMIT clocks. + fn sample(&mut self, h: i64, level: u32) -> u32 { + let d = h - self.win_lo; + let w = 1i64 << self.wbits; + let in_win = d >= 0 && d < w; + let lbase = ((level as u64) << self.wbits) & 0x1FFF; + let idx = (lbase + (d as u64 & 0x1FFF)) & 0x1FFF; + self.tbl_q = self.tbl[idx as usize]; + let u = self.draw(); + let s = if in_win { + let (a, b) = self.tbl_q; + if u < a { 0b10 } else if u < b { 0b00 } else { 0b01 } + } else { + (((h < -self.cost) as u32) << 1) | (h > self.cost) as u32 + }; + self.x_next = self.x_next.wrapping_add(GOLDEN); + s + } + + fn run_job(&mut self, load: bool) { + self.done = false; + self.term = TERM_NONE; + let mut cyc = 0u64; + let sampling = self.mode == MODE_GIBBS || self.mode == MODE_JACOBI; + if load { + cyc += 1; // S_LOAD + self.state = self.boundary; + self.prev = self.boundary; + if sampling { + cyc += PRIME; // S_PRIME + self.x_next = self.x0; + self.primed = true; + } + } + let mut prev = self.prev; + let mut prev2 = [0u32; 4]; + self.steps = 0; + self.sel = 0; + if self.mode == MODE_T0 { + let (mut have1, mut have2) = (false, false); + loop { + cyc += 1; + if have1 && self.state == prev { + self.term = TERM_FP; + break; + } + if have2 && self.state == prev2 { + self.term = TERM_2C; + break; + } + if self.steps == self.bound { + self.term = TERM_BOUND; + break; + } + let ns = self.t0_next(&self.state); + prev2 = prev; + prev = self.state; + self.state = ns; + self.prev = prev; + self.steps += 1; + have2 = have1; + have1 = true; + } + } else { + let jac = self.mode == MODE_JACOBI; + let (mut level, mut spl_cnt) = (0u32, 0u32); + if self.bound != 0 { + loop { + for i in 0..=(self.n_m1 as usize) { + cyc += 4; + let h = self.field(&self.state, i); + let s = self.sample(h, level); + if jac { set2(&mut prev, i, s) } else { set2(&mut self.state, i, s) } + self.updates += 1; + } + if jac { + cyc += 1; + self.state = prev; + } + self.steps += 1; + if self.steps == self.bound { + break; + } + if spl_cnt + 1 == self.spl { + spl_cnt = 0; + if level != self.levels_m1 { + level += 1; + } + } else { + spl_cnt += 1; + } + } + } + if self.final_t0 { + cyc += 1; + self.prev = self.state; + self.state = self.t0_next(&self.state); + } else { + self.prev = prev; + } + } + cyc += 1; // S_END + self.cycles += cyc; + self.uptime += cyc + 16; + self.jobs += 1; + self.done = true; + } +} + +impl Port for ModelPort { + fn write(&mut self, addr: u16, val: u32) -> Result<(), Error> { + self.uptime += 8; + match addr { + CONTROL => { + if val & CTL_CLRCNT != 0 { + self.cycles = 0; + self.updates = 0; + self.jobs = 0; + } + if val & CTL_CLEARW != 0 { + self.rows = vec![[0; 4]; 64]; + self.fields = [0; 64]; + } + if val & CTL_LOADSTATE != 0 { + self.state = self.boundary; + self.prev = self.boundary; + } + if val & CTL_START != 0 { + if self.rep { + return Err(Error("the model does not run repeat mode".into())); + } + self.run_job(true); + } else if val & CTL_CONT != 0 { + if self.rep || self.bound == 0 { + return Err(Error("CONT needs repeat off and a bound above 0".into())); + } + self.run_job(false); + } + if val & CTL_STOP != 0 { + self.done = false; + } + } + MODE => { + self.mode = val & 3; + self.rep = val & MODE_REPEAT != 0; + self.final_t0 = val & MODE_FINAL_T0 != 0; + } + N_M1 => self.n_m1 = val & 63, + COST => self.cost = (val & 0xF_FFFF) as i64, + BOUND => self.bound = val, + SPL => self.spl = val & 0xFFFF, + LEVELS_M1 => self.levels_m1 = val & 63, + X0_LO => self.x0 = (self.x0 & !0xFFFF_FFFF) | val as u64, + X0_HI => self.x0 = (self.x0 & 0xFFFF_FFFF) | ((val as u64) << 32), + WIN_LO => self.win_lo = sext(val as u64 & 0x3F_FFFF, 22), + WBITS => self.wbits = val & 15, + SEL => self.sel = val & 63, + TBL_ADDR => { + self.tbl_addr = val & 0x1FFF; + self.tbl_q = self.tbl[self.tbl_addr as usize]; + } + TBL_A_LO => self.wa = (self.wa & !0xFFFF_FFFF) | val as u64, + TBL_A_HI => self.wa = (self.wa & 0xFFFF_FFFF) | (((val & 0x3F_FFFF) as u64) << 32), + TBL_B_LO => self.wb_lo = val, + TBL_B_HI => { + let b = (((val & 0x3F_FFFF) as u64) << 32) | self.wb_lo as u64; + self.tbl[self.tbl_addr as usize] = (self.wa, b); + self.tbl_addr = (self.tbl_addr + 1) & 0x1FFF; + } + a if (BOUNDARY..BOUNDARY + 4).contains(&a) => self.boundary[(a - BOUNDARY) as usize] = val, + a if (FIELDS..FIELDS + 64).contains(&a) => self.fields[(a - FIELDS) as usize] = sext(val as u64 & 0xF_FFFF, 20), + a if (W..W + 256).contains(&a) => { + let k = (a - W) as usize; + self.rows[k >> 2][k & 3] = val; + } + _ => {} + } + Ok(()) + } + + fn read(&mut self, addr: u16) -> Result { + self.uptime += 8; + let lo_hi = |v: u64, s: &mut u32| { + *s = (v >> 32) as u32 & 0xFFFF; + v as u32 + }; + Ok(match addr { + ID => ID_VALUE, + VERSION => VERSION_VALUE, + STATUS => (self.term << 2) | ((self.done as u32) << 1), + MODE => ((self.final_t0 as u32) << 9) | ((self.rep as u32) << 8) | self.mode, + N_M1 => self.n_m1, + COST => self.cost as u32, + BOUND => self.bound, + WIN_LO => self.win_lo as i32 as u32, + WBITS => self.wbits, + FIELD => (self.field(&self.state, self.sel as usize) as i32) as u32, + TBL_ADDR => self.tbl_addr, + TBL_A_LO => self.tbl_q.0 as u32, + TBL_A_HI => (self.tbl_q.0 >> 32) as u32 & 0x3F_FFFF, + TBL_B_LO => self.tbl_q.1 as u32, + TBL_B_HI => (self.tbl_q.1 >> 32) as u32 & 0x3F_FFFF, + DRAW_LO => { + let u = self.draw(); + self.rd_hi = (u >> 32) as u32; + u as u32 + } + DRAW_HI => self.rd_hi, + UPTIME => { let u = self.uptime; lo_hi(u, &mut self.rd_hi) } + CYCLES => { let u = self.cycles; lo_hi(u, &mut self.rd_hi) } + UPDATES => { let u = self.updates; lo_hi(u, &mut self.rd_hi) } + JOBS => { let u = self.jobs; lo_hi(u, &mut self.rd_hi) } + 0x0021 | 0x0023 | 0x0025 | 0x0027 => self.rd_hi, + STEPS => self.steps, + a if (STATE..STATE + 4).contains(&a) => self.state[(a - STATE) as usize], + _ => 0xDEAD_BEEF, + }) + } + + fn wait_idle(&mut self, _timeout: Duration) -> Result<(), Error> { + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// The model's draws are the reference's: the engine's counter starts at chain + GOLDEN and + /// the j-th draw of a chain is out(chain, j) >> 11. + #[test] + fn the_draw_is_the_reference_s() { + use wai_quantum::quantum_landscape::sample::out; + let chain = 0x1234_5678_9ABC_DEF0u64; + let mut x = chain.wrapping_add(GOLDEN); + for j in 1..=1000u64 { + assert_eq!(mix(x), out(chain, j)); + x = x.wrapping_add(GOLDEN); + } + } +} diff --git a/wai/wai-quantum-landscape-fpga/src/port.rs b/wai/wai-quantum-landscape-fpga/src/port.rs new file mode 100644 index 000000000..7153442ed --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/port.rs @@ -0,0 +1,135 @@ +//! A register port. The board's is the AXI link (`axi.rs`) or the EMIO lines (`emio.rs`); the +//! model's is software (`model.rs`); the testbench script records one (`script.rs`). Everything +//! above this trait is shared by all of them. +//! +//! Two operations have a plain meaning in register accesses and a faster one on the AXI link: +//! [`Port::bulk`], a list of writes in order (the AXI link reads it from DDR by DMA), and +//! [`Port::batch`], a run of chains (the AXI link's sequencer runs them in fabric). The defaults +//! here are the plain meaning, and the fast forms must give the same bits. + +use crate::regs::{BOUNDARY, CONTROL, CTL_START, STATE, STATUS, STEPS, X0_HI, X0_LO}; +use std::fmt; +use std::time::Duration; + +/// One chain for [`Port::batch`]: BOUNDARY 0-3, X0_LO, X0_HI. +pub type ChainWords = [u32; 6]; +/// What a chain leaves: STATE 0-3, STEPS, STATUS. +pub type ResultWords = [u32; 6]; + +#[derive(Debug, Clone, PartialEq)] +pub struct Error(pub String); +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&self.0) + } +} +impl std::error::Error for Error {} +pub fn err(s: impl Into) -> Result { + Err(Error(s.into())) +} + +pub trait Port { + fn write(&mut self, addr: u16, val: u32) -> Result<(), Error>; + fn read(&mut self, addr: u16) -> Result; + /// Poll until the engine is idle. Errs on timeout rather than waiting forever. + fn wait_idle(&mut self, timeout: Duration) -> Result<(), Error>; + + /// Writes, in order. + fn bulk(&mut self, list: &[(u16, u32)]) -> Result<(), Error> { + bulk_plain(self, list) + } + + /// For each chain: its start and draw counter written, the job started with the mode, bound and + /// table already set, waited for, and its state, sweeps and status read back. + fn batch(&mut self, chains: &[ChainWords], timeout: Duration) -> Result, Error> { + batch_plain(self, chains, timeout) + } +} + +/// [`Port::bulk`] as plain register writes. +pub fn bulk_plain(p: &mut P, list: &[(u16, u32)]) -> Result<(), Error> { + for &(a, v) in list { + p.write(a, v)?; + } + Ok(()) +} + +/// [`Port::batch`] as plain register accesses: what the AXI link's sequencer does, from the host. +pub fn batch_plain(p: &mut P, chains: &[ChainWords], timeout: Duration) -> Result, Error> { + let mut out = Vec::with_capacity(chains.len()); + for c in chains { + for (k, &w) in c[..4].iter().enumerate() { + p.write(BOUNDARY + k as u16, w)?; + } + p.write(X0_LO, c[4])?; + p.write(X0_HI, c[5])?; + p.write(CONTROL, CTL_START)?; + p.wait_idle(timeout)?; + let mut r = [0u32; 6]; + for (k, w) in r[..4].iter_mut().enumerate() { + *w = p.read(STATE + k as u16)?; + } + r[4] = p.read(STEPS)?; + r[5] = p.read(STATUS)?; + out.push(r); + } + Ok(out) +} + +/// One core of the multi-core bitstream (`rtl/landscape_multi.v`): address bits 15:13 pick it. +pub struct CorePort<'a, P: Port> { + pub inner: &'a mut P, + pub core: u16, +} + +impl Port for CorePort<'_, P> { + fn write(&mut self, addr: u16, val: u32) -> Result<(), Error> { + self.inner.write((self.core << 13) | (addr & 0x1FFF), val) + } + fn read(&mut self, addr: u16) -> Result { + self.inner.read((self.core << 13) | (addr & 0x1FFF)) + } + fn wait_idle(&mut self, timeout: Duration) -> Result<(), Error> { + self.inner.wait_idle(timeout) + } +} + +/// Every write goes to all `k` cores, reads come from core 0: the same job on every core at once. +/// For power, where K identical copies amplify a signal the one-core meter cannot resolve. +pub struct BroadcastPort { + pub inner: P, + pub k: u16, +} + +impl Port for BroadcastPort

{ + fn write(&mut self, addr: u16, val: u32) -> Result<(), Error> { + for c in 0..self.k { + self.inner.write((c << 13) | (addr & 0x1FFF), val)?; + } + Ok(()) + } + fn read(&mut self, addr: u16) -> Result { + self.inner.read(addr & 0x1FFF) + } + fn wait_idle(&mut self, timeout: Duration) -> Result<(), Error> { + self.inner.wait_idle(timeout) + } +} + +impl Port for &mut P { + fn write(&mut self, addr: u16, val: u32) -> Result<(), Error> { + (**self).write(addr, val) + } + fn read(&mut self, addr: u16) -> Result { + (**self).read(addr) + } + fn wait_idle(&mut self, timeout: Duration) -> Result<(), Error> { + (**self).wait_idle(timeout) + } + fn bulk(&mut self, list: &[(u16, u32)]) -> Result<(), Error> { + (**self).bulk(list) + } + fn batch(&mut self, chains: &[ChainWords], timeout: Duration) -> Result, Error> { + (**self).batch(chains, timeout) + } +} diff --git a/wai/wai-quantum-landscape-fpga/src/power.rs b/wai/wai-quantum-landscape-fpga/src/power.rs new file mode 100644 index 000000000..d15f86655 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/power.rs @@ -0,0 +1,250 @@ +//! Run/halt power on one bitstream, by the board's written rules: +//! +//! * no reload between the two states, so placement, routing and clock tree are identical and the +//! difference is the job's dynamic power; +//! * the order of run and halt is randomised in every pass, so a monotonic drift cannot alias onto it; +//! * sampling happens on the board, in this process, with nothing else running: a bare read of the +//! sensor and a sleep (the PS is inside the measurement); +//! * every point checks for a reload by another session two ways: the engine's uptime counter must +//! have kept counting (a reload resets it, even of the same file), and the dmesg count of FPGA +//! writes must not have moved. A flagged pass is dropped, never averaged in; +//! * the statistic is the mean of per-pass differences of medians, its error the standard error +//! across passes (n = passes, not samples); +//! * `--predict` prints a figure beside the result. It is only what the command line said: what +//! makes a prediction pre-registered is the file committed before the run, `measurements/*/`. + +#[cfg(target_os = "linux")] +use crate::board; +#[cfg(target_os = "linux")] +use crate::engine::Engine; +#[cfg(target_os = "linux")] +use crate::port::{Error, Port}; +#[cfg(target_os = "linux")] +use crate::regs::*; +use std::fmt::Write as _; +#[cfg(target_os = "linux")] +use std::time::{Duration, Instant, SystemTime}; + +pub struct Plan { + pub passes: u32, + pub settle_s: u64, + pub samples: u32, + /// "halt" for an A/A null control: both slots halted, one of them labelled run. + pub null: bool, +} + +pub struct Point { + pub pass: u32, + pub run: bool, + pub samples: Vec, // mW + pub jobs_per_s: f64, + pub updates_per_s: f64, + pub clock_hz: f64, + pub flagged: Option, +} + +#[cfg(target_os = "linux")] +fn urandom_bit() -> bool { + let mut b = [0u8; 1]; + use std::io::Read; + if let Ok(mut f) = std::fs::File::open("/dev/urandom") { + let _ = f.read_exact(&mut b); + } + b[0] & 1 == 1 +} + +/// `start` puts the engine into repeat mode on the prepared job; the meter halts it for the halt slot. +#[cfg(target_os = "linux")] +pub fn meter(edge: &mut Engine

, plan: &Plan, start: &mut dyn FnMut(&mut Engine

) -> Result<(), Error>, log: &mut String) -> Result, Error> { + let sensor = board::find_power_sensor()?; + let mut pts = vec![]; + let _ = writeln!(log, "# wai-quantum-landscape-fpga meter passes={} settle={}s samples={} null={} sensor={sensor} started={:?}", plan.passes, plan.settle_s, plan.samples, plan.null, SystemTime::now()); + let _ = writeln!(log, "# pass state sample power_uW"); + for pass in 1..=plan.passes { + let order = if urandom_bit() { [true, false] } else { [false, true] }; + for run in order { + if run && !plan.null { + start(edge)?; + } else { + edge.halt()?; + } + let w0 = board::dmesg_fpga_writes()?.len(); + let id0 = edge.port.read(ID)?; + let up0 = edge.counter(UPTIME)?; + std::thread::sleep(Duration::from_secs(plan.settle_s)); + // the window: counters read just before and just after, sensor only in between + let j0 = edge.counter(JOBS)?; + let u0 = edge.counter(UPDATES)?; + let c0 = edge.counter(UPTIME)?; + let t0 = Instant::now(); + let mut s = Vec::with_capacity(plan.samples as usize); + for _ in 0..plan.samples { + s.push(board::read_uw(&sensor)? as f64 / 1000.0); + std::thread::sleep(Duration::from_secs(1)); + } + let dt = t0.elapsed().as_secs_f64(); + let c1 = edge.counter(UPTIME)?; + let j1 = edge.counter(JOBS)?; + let u1 = edge.counter(UPDATES)?; + let id1 = edge.port.read(ID)?; + let w1 = board::dmesg_fpga_writes()?.len(); + let mut flagged = None; + if id0 != ID_VALUE || id1 != ID_VALUE { + flagged = Some(format!("ID {id0:#x}/{id1:#x}")); + } else if !(up0 <= c0 && c0 < c1) { + flagged = Some(format!("uptime went {up0} -> {c0} -> {c1}: the PL was reconfigured")); + } else if w1 != w0 { + flagged = Some(format!("dmesg FPGA writes {w0} -> {w1}")); + } + let label = if run { "run" } else { "halt" }; + for (k, v) in s.iter().enumerate() { + let _ = writeln!(log, "{pass} {label} {} {}", k + 1, (v * 1000.0).round() as u64); + } + let clock = (c1 - c0) as f64 / dt; + let _ = writeln!(log, "# point pass={pass} state={label} jobs_per_s={:.1} updates_per_s={:.1} clock_hz={clock:.0}{}", (j1 - j0) as f64 / dt, (u1 - u0) as f64 / dt, + flagged.as_ref().map(|f| format!(" FLAGGED {f}")).unwrap_or_default()); + pts.push(Point { pass, run, samples: s, jobs_per_s: (j1 - j0) as f64 / dt, updates_per_s: (u1 - u0) as f64 / dt, clock_hz: clock, flagged }); + } + } + edge.halt()?; + let _ = writeln!(log, "# done {:?}", SystemTime::now()); + Ok(pts) +} + +pub struct Summary { + pub text: String, + pub delta_mw: f64, + pub se_mw: f64, + pub passes_used: usize, + pub jobs_per_s: f64, + pub updates_per_s: f64, + pub clock_hz: f64, + pub p_run_mw: f64, +} + +fn excursions(s: &[f64]) -> usize { + let m = median(s); + let mad = median(&s.iter().map(|x| (x - m).abs()).collect::>()).max(5.0); + s.iter().filter(|x| (*x - m).abs() > 6.0 * mad).count() +} + +pub fn summarise(pts: &[Point], predicted_mw: Option) -> Summary { + let mut t = String::new(); + let passes: Vec = { + let mut v: Vec = pts.iter().map(|p| p.pass).collect(); + v.dedup(); + v + }; + let mut diffs = vec![]; + let mut dropped = vec![]; + let (mut jps, mut ups, mut clk, mut prun) = (vec![], vec![], vec![], vec![]); + let mut exc = 0; + for &p in &passes { + let r = pts.iter().find(|x| x.pass == p && x.run); + let h = pts.iter().find(|x| x.pass == p && !x.run); + if let (Some(r), Some(h)) = (r, h) { + if let Some(f) = r.flagged.as_ref().or(h.flagged.as_ref()) { + dropped.push(format!("pass {p}: {f}")); + continue; + } + exc += excursions(&r.samples) + excursions(&h.samples); + let d = median(&r.samples) - median(&h.samples); + diffs.push(d); + jps.push(r.jobs_per_s); + ups.push(r.updates_per_s); + clk.push(r.clock_hz); + prun.push(median(&r.samples)); + } + } + let (m, sd) = mean_sd(&diffs); + let se = sd / (diffs.len() as f64).sqrt(); + let pos = diffs.iter().filter(|&&d| d > 0.0).count(); + let _ = writeln!(t, "passes used {} of {} (dropped: {:?})", diffs.len(), passes.len(), dropped); + let _ = writeln!(t, "run - halt = {m:.1} +/- {se:.1} mW (per-pass sd {sd:.1}); {pos}/{} passes positive; {exc} sample excursions beyond 6 MAD", diffs.len()); + let _ = writeln!(t, "per-pass differences (mW): {}", diffs.iter().map(|d| format!("{d:.1}")).collect::>().join(" ")); + let (j, _) = mean_sd(&jps); + let (u, _) = mean_sd(&ups); + let (c, _) = mean_sd(&clk); + let (pr, _) = mean_sd(&prun); + let _ = writeln!(t, "board power while running {pr:.0} mW; jobs/s {j:.1}; updates/s {u:.1}; measured PL clock {:.3} MHz", c / 1e6); + if let Some(p) = predicted_mw { + let _ = writeln!(t, "prediction given {p:.1} mW: measured/predicted = {:.2}, {:.1} sigma from it", m / p, (m - p) / se); + } + Summary { text: t, delta_mw: m, se_mw: se, passes_used: diffs.len(), jobs_per_s: j, updates_per_s: u, clock_hz: c, p_run_mw: pr } +} + +/// Parses a meter log back into points (so a run can be re-analysed anywhere). +pub fn parse_log(text: &str) -> Vec { + let mut pts: Vec = vec![]; + // kv_runhalt.sh (the September known-answer vehicle's script) flags interference this way + let mut foreign: Vec = vec![]; + for line in text.lines() { + for tag in ["# FOREIGN-LOAD pass=", "# NOT-OURS pass="] { + if let Some(r) = line.strip_prefix(tag) { + if let Some(p) = r.split_whitespace().next().and_then(|t| t.parse().ok()) { + foreign.push(p); + } + } + } + } + for line in text.lines() { + if let Some(rest) = line.strip_prefix("# point ") { + let get = |k: &str| rest.split_whitespace().find_map(|t| t.strip_prefix(&format!("{k}="))).unwrap_or("").to_string(); + let pass: u32 = get("pass").parse().unwrap_or(0); + let run = get("state") == "run"; + if let Some(p) = pts.iter_mut().rev().find(|p| p.pass == pass && p.run == run) { + p.jobs_per_s = get("jobs_per_s").parse().unwrap_or(0.0); + p.updates_per_s = get("updates_per_s").parse().unwrap_or(0.0); + p.clock_hz = get("clock_hz").parse().unwrap_or(0.0); + if rest.contains("FLAGGED") { + p.flagged = Some(rest.split("FLAGGED").nth(1).unwrap_or("").trim().to_string()); + } + } + continue; + } + if line.starts_with('#') || line.trim().is_empty() { + continue; + } + let f: Vec<&str> = line.split_whitespace().collect(); + if f.len() < 4 { + continue; + } + let (Ok(pass), Ok(uw)) = (f[0].parse::(), f[3].parse::()) else { continue }; + let run = f[1] == "run"; + match pts.iter_mut().find(|p| p.pass == pass && p.run == run) { + Some(p) => p.samples.push(uw / 1000.0), + None => pts.push(Point { pass, run, samples: vec![uw / 1000.0], jobs_per_s: 0.0, updates_per_s: 0.0, clock_hz: 0.0, flagged: None }), + } + } + for p in pts.iter_mut() { + if foreign.contains(&p.pass) && p.flagged.is_none() { + p.flagged = Some("foreign FPGA load in this pass (kv_runhalt.sh)".into()); + } + } + pts +} + +pub fn mean_sd(v: &[f64]) -> (f64, f64) { + let n = v.len() as f64; + if v.is_empty() { + return (f64::NAN, f64::NAN); + } + let m = v.iter().sum::() / n; + if v.len() < 2 { + return (m, f64::NAN); + } + (m, (v.iter().map(|x| (x - m) * (x - m)).sum::() / (n - 1.0)).sqrt()) +} + +pub fn median(v: &[f64]) -> f64 { + let mut s = v.to_vec(); + s.sort_by(|a, b| a.partial_cmp(b).unwrap()); + let n = s.len(); + if n == 0 { + f64::NAN + } else if n % 2 == 1 { + s[n / 2] + } else { + 0.5 * (s[n / 2 - 1] + s[n / 2]) + } +} diff --git a/wai/wai-quantum-landscape-fpga/src/regs.rs b/wai/wai-quantum-landscape-fpga/src/regs.rs new file mode 100644 index 000000000..66b9bb24c --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/regs.rs @@ -0,0 +1,69 @@ +//! The engine's register map. Word addresses; `rtl/landscape_core.v` is the other half of this file. + +pub const ID: u16 = 0x0000; +pub const ID_VALUE: u32 = 0x4C41_4E44; // "LAND" +pub const VERSION: u16 = 0x0001; +pub const VERSION_VALUE: u32 = 0x0040_4002; // 64 cells, 64 levels, rtl 2 +pub const STATUS: u16 = 0x0002; // [0] busy [1] done [3:2] term +pub const CONTROL: u16 = 0x0003; +pub const MODE: u16 = 0x0004; // [1:0] mode [8] repeat [9] final T0 sweep +pub const N_M1: u16 = 0x0005; +pub const COST: u16 = 0x0006; // 20 bits +pub const BOUND: u16 = 0x0007; // T0 sweep bound, or sweeps +pub const SPL: u16 = 0x0008; // sweeps per temperature level +pub const LEVELS_M1: u16 = 0x0009; +pub const X0_LO: u16 = 0x0010; // the draw counter's start, chain seed + GOLDEN +pub const X0_HI: u16 = 0x0011; +pub const WIN_LO: u16 = 0x0012; // the table window's first field, signed +pub const WBITS: u16 = 0x0013; // the window holds 2^WBITS fields +pub const SEL: u16 = 0x0014; +pub const FIELD: u16 = 0x0015; +pub const TBL_ADDR: u16 = 0x0016; +pub const TBL_A_LO: u16 = 0x0017; +pub const TBL_A_HI: u16 = 0x0018; +pub const TBL_B_LO: u16 = 0x0019; +pub const TBL_B_HI: u16 = 0x001A; // writing it commits the pair and steps the address +pub const DRAW_LO: u16 = 0x001B; // the draw the next cell would take (53 bits) +pub const DRAW_HI: u16 = 0x001C; +pub const UPTIME: u16 = 0x0020; +pub const CYCLES: u16 = 0x0022; +pub const UPDATES: u16 = 0x0024; +pub const JOBS: u16 = 0x0026; +pub const STEPS: u16 = 0x0028; +pub const BOUNDARY: u16 = 0x0100; +pub const STATE: u16 = 0x0110; +pub const FIELDS: u16 = 0x0200; // one per cell, 20 bits signed +pub const W: u16 = 0x1000; + +pub const CTL_START: u32 = 1; +pub const CTL_CONT: u32 = 2; +pub const CTL_STOP: u32 = 4; +pub const CTL_LOADSTATE: u32 = 8; +pub const CTL_CLEARW: u32 = 16; +pub const CTL_CLRCNT: u32 = 32; + +pub const MODE_T0: u32 = 0; +pub const MODE_GIBBS: u32 = 1; +pub const MODE_JACOBI: u32 = 2; +pub const MODE_REPEAT: u32 = 1 << 8; +pub const MODE_FINAL_T0: u32 = 1 << 9; + +pub const CELLS: usize = 64; +pub const LEVELS: usize = 64; +pub const TABLE: usize = 8192; +pub const MAX_WBITS: u32 = 13; +/// The draw pipeline's depth: a job that samples spends this many clocks priming it. +pub const PRIME: u64 = 9; +/// The largest field a cell's register holds, either sign. +pub const FIELD_MAX: i64 = (1 << 19) - 1; +/// The largest cost the register holds. +pub const COST_MAX: i64 = (1 << 20) - 1; +/// SplitMix64's increment. +pub const GOLDEN: u64 = 0x9E37_79B9_7F4A_7C15; +/// The edge of the 53-bit scale: a cut point of this size means "always below". +pub const TWO53: u64 = 1 << 53; + +pub const TERM_NONE: u32 = 0; +pub const TERM_FP: u32 = 1; +pub const TERM_2C: u32 = 2; +pub const TERM_BOUND: u32 = 3; diff --git a/wai/wai-quantum-landscape-fpga/src/script.rs b/wai/wai-quantum-landscape-fpga/src/script.rs new file mode 100644 index 000000000..d9df51a21 --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/src/script.rs @@ -0,0 +1,114 @@ +//! Records a session against the model as a script the RTL testbench replays: every write, every read +//! with the value the model returned (the RTL must return the same), and every wait. +//! +//! W aaaa dddddddd write +//! R aaaa dddddddd mmmmmmmm read, expect (value & mask) == (d & mask) +//! I wait until not busy +//! +//! In AXI form (`tb/tb_landscape_axi.v`) a bulk list and a batch of chains go as the AXI link +//! carries them, so the testbench drives the DMA and the sequencer: +//! +//! D n the next n lines, `aaaa dddddddd`, are a write list: put it in memory +//! and run the DMA over it +//! Q n run the sequencer over n chains (their words already in the chain RAM) +//! and wait for it +//! K n write the batch's n results back to memory; the next 6n lines are the +//! words each must hold +//! +//! and a batch's results are also checked as reads of the result RAM. + +use crate::axi::{CHAIN_RAM, RESULT_RAM, WRAP_DROPS}; +use crate::model::ModelPort; +use crate::port::{ChainWords, Error, Port, ResultWords}; +use crate::regs; +use std::fmt::Write as _; +use std::time::Duration; + +pub struct ScriptPort { + pub model: ModelPort, + pub text: String, + pub reads: usize, + /// Record bulk lists and batches in the AXI form. + pub axi: bool, +} + +impl ScriptPort { + pub fn new() -> Self { + ScriptPort { model: ModelPort::new(), text: String::new(), reads: 0, axi: false } + } + pub fn axi() -> Self { + ScriptPort { axi: true, ..Self::new() } + } + fn expect(&mut self, addr: u16, v: u32, mask: u32) { + let _ = writeln!(self.text, "R {addr:04x} {v:08x} {mask:08x}"); + self.reads += 1; + } +} + +impl Default for ScriptPort { + fn default() -> Self { + Self::new() + } +} + +impl Port for ScriptPort { + fn write(&mut self, addr: u16, val: u32) -> Result<(), Error> { + let _ = writeln!(self.text, "W {addr:04x} {val:08x}"); + self.model.write(addr & 0x1FFF, val) + } + fn read(&mut self, addr: u16) -> Result { + let v = self.model.read(addr & 0x1FFF)?; + let a = addr & 0x1FFF; + // uptime counts real clocks, which the model cannot know + let mask = if a == regs::UPTIME || a == regs::UPTIME + 1 { 0u32 } else { 0xFFFF_FFFFu32 }; + self.expect(addr, v, mask); + Ok(v) + } + fn wait_idle(&mut self, t: Duration) -> Result<(), Error> { + self.text.push_str("I\n"); + self.model.wait_idle(t) + } + fn bulk(&mut self, list: &[(u16, u32)]) -> Result<(), Error> { + if !self.axi { + return crate::port::bulk_plain(self, list); + } + let _ = writeln!(self.text, "D {}", list.len()); + for &(a, v) in list { + let _ = writeln!(self.text, "{a:04x} {v:08x}"); + self.model.write(a & 0x1FFF, v)?; + } + Ok(()) + } + fn batch(&mut self, chains: &[ChainWords], t: Duration) -> Result, Error> { + if !self.axi { + return crate::port::batch_plain(self, chains, t); + } + let mut out = Vec::with_capacity(chains.len()); + for group in chains.chunks(crate::axi::SEQ_MAX) { + // the chain words by DMA, the sequencer, then every result word checked + let _ = writeln!(self.text, "D {}", group.len() * 6); + for (k, c) in group.iter().enumerate() { + for (i, &w) in c.iter().enumerate() { + let _ = writeln!(self.text, "{:04x} {w:08x}", CHAIN_RAM + (8 * k + i) as u16); + } + } + let _ = writeln!(self.text, "Q {}", group.len()); + let res = self.model.batch(group, t)?; + for (k, r) in res.iter().enumerate() { + for (i, &w) in r.iter().enumerate() { + self.expect(RESULT_RAM + (8 * k + i) as u16, w, 0xFFFF_FFFF); + } + } + self.expect(WRAP_DROPS, 0, 0xFFFF_FFFF); + let _ = writeln!(self.text, "K {}", group.len()); + for r in &res { + for &w in r { + let _ = writeln!(self.text, "{w:08x}"); + } + self.reads += r.len(); + } + out.extend(res); + } + Ok(out) + } +} diff --git a/wai/wai-quantum-landscape-fpga/tb/tb_landscape.v b/wai/wai-quantum-landscape-fpga/tb/tb_landscape.v new file mode 100644 index 000000000..e7553e77b --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/tb/tb_landscape.v @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: Apache-2.0 +// Replays a session recorded from the host's software model (`wai-quantum-landscape-fpga gen-tb landscape_tb.script`) against the RTL, +// through the EMIO port and its synchroniser, with the PS side deliberately off the PL clock. +// Every read must return what the model returned. A mismatch names the script line. +`timescale 1ns/1ps +module tb; + reg clk = 0; + always #5 clk = ~clk; // pl_clk0, 100 MHz + reg [94:0] emio_o = 95'd0; + wire [94:0] emio_i; +`ifdef MULTI + landscape_multi #(.K(4)) dut (.clk(clk), .emio_o(emio_o), .emio_i(emio_i)); +`else + landscape_port dut (.clk(clk), .emio_o(emio_o), .emio_i(emio_i)); +`endif + + integer fd, r, errors, reads, line, t; + reg [31:0] op, a, d, m, got; + reg req; + + task txn(input we, input [15:0] addr, input [31:0] wdata, output [31:0] rdata); + reg ack0; + begin + ack0 = emio_i[82]; + emio_o[31:0] = wdata; + #37; // a PS bus write, some time before the next + req = ~req; + emio_o[81] = we; + emio_o[79:64] = addr; + emio_o[80] = req; + t = 0; + while (emio_i[82] == ack0) begin + #13; + t = t + 1; + if (t > 20000) begin + $display("TIMEOUT waiting for ack at script line %0d", line); + $finish; + end + end + rdata = emio_i[63:32]; + #29; + end + endtask + + initial begin + errors = 0; reads = 0; line = 0; req = 0; + #3000; // past the port's power-on hold-off + fd = $fopen("landscape_tb.script", "r"); + if (fd == 0) begin $display("no script"); $finish; end + r = $fscanf(fd, "%s", op); + while (r == 1) begin + line = line + 1; + if (op == "W") begin + r = $fscanf(fd, " %h %h", a, d); + txn(1'b1, a[15:0], d, got); + end else if (op == "R") begin + r = $fscanf(fd, " %h %h %h", a, d, m); + txn(1'b0, a[15:0], 32'd0, got); + reads = reads + 1; + if ((got & m) !== (d & m)) begin + errors = errors + 1; + if (errors <= 25) $display("MISMATCH line %0d: R %h got %h want %h", line, a[15:0], got, d); + end + end else if (op == "I") begin + t = 0; + while (emio_i[83]) begin + #50; + t = t + 1; + if (t > 2000000) begin $display("TIMEOUT busy at line %0d", line); $finish; end + end + #20; + end else begin + $display("bad op at line %0d", line); + $finish; + end + r = $fscanf(fd, "%s", op); + end + $display("TB DONE: %0d lines, %0d checked reads, %0d mismatches, sim time %0t", line, reads, errors, $time); + $finish; + end +endmodule diff --git a/wai/wai-quantum-landscape-fpga/tb/tb_landscape_axi.v b/wai/wai-quantum-landscape-fpga/tb/tb_landscape_axi.v new file mode 100644 index 000000000..ca395091c --- /dev/null +++ b/wai/wai-quantum-landscape-fpga/tb/tb_landscape_axi.v @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: Apache-2.0 +// Replays a session recorded from the host's software model in its AXI form (`gen-tb --axi`) +// against the AXI link (rtl/landscape_axi.v) and the engine behind it: register accesses over +// AXI-Lite, write lists through the DMA from a memory model that answers with irregular delays and +// several bursts outstanding, and batches of chains through the sequencer, whose results are read +// from the result RAM and written back to the memory model. Every read and every word written back +// must be what the model returned. A mismatch names the line. +`timescale 1ns/1ps +module tb; + reg clk = 0; + always #5 clk = ~clk; // pl_clk0, 100 MHz + reg rstn = 0; + + // AXI-Lite master + reg [31:0] awaddr = 0, wdata = 0, araddr = 0; + reg awvalid = 0, wvalid = 0, bready = 0, arvalid = 0, rready = 0; + wire awready, wready, bvalid, arready, rvalid; + wire [1:0] bresp, rresp; + wire [31:0] rdata; + // DMA read port + wire [48:0] m_araddr; + wire [7:0] m_arlen; + wire [2:0] m_arsize, m_arprot; + wire [1:0] m_arburst; + wire [3:0] m_arcache; + wire m_arvalid, m_rready; + reg m_arready = 0, m_rvalid = 0, m_rlast = 0; + reg [63:0] m_rdata = 0; + reg [1:0] m_rresp = 0; + // DMA write port + wire [48:0] m_awaddr; + wire [7:0] m_awlen, m_wstrb; + wire [2:0] m_awsize, m_awprot; + wire [1:0] m_awburst; + wire [3:0] m_awcache; + wire [63:0] m_wdata; + wire m_awvalid, m_wlast, m_wvalid, m_bready; + reg m_awready = 0, m_wready = 0, m_bvalid = 0; + reg [1:0] m_bresp = 0; + wire [94:0] emio_i; + + landscape_axi dut ( + .clk(clk), .rstn(rstn), + .s_awaddr(awaddr), .s_awvalid(awvalid), .s_awready(awready), .s_wdata(wdata), .s_wvalid(wvalid), + .s_wready(wready), .s_bresp(bresp), .s_bvalid(bvalid), .s_bready(bready), + .s_araddr(araddr), .s_arvalid(arvalid), .s_arready(arready), .s_rdata(rdata), .s_rresp(rresp), + .s_rvalid(rvalid), .s_rready(rready), + .m_araddr(m_araddr), .m_arlen(m_arlen), .m_arsize(m_arsize), .m_arburst(m_arburst), .m_arcache(m_arcache), + .m_arprot(m_arprot), .m_arvalid(m_arvalid), .m_arready(m_arready), .m_rdata(m_rdata), .m_rresp(m_rresp), + .m_rlast(m_rlast), .m_rvalid(m_rvalid), .m_rready(m_rready), + .m_awaddr(m_awaddr), .m_awlen(m_awlen), .m_awsize(m_awsize), .m_awburst(m_awburst), .m_awcache(m_awcache), + .m_awprot(m_awprot), .m_awvalid(m_awvalid), .m_awready(m_awready), .m_wdata(m_wdata), .m_wstrb(m_wstrb), + .m_wlast(m_wlast), .m_wvalid(m_wvalid), .m_wready(m_wready), .m_bresp(m_bresp), .m_bvalid(m_bvalid), .m_bready(m_bready), + .emio_i(emio_i) + ); + + // ---- DDR: a memory model behind the high-performance port -------------------------------------- + localparam [48:0] BASE = 49'h0_1000_0000; + reg [63:0] mem [0:65535]; + reg [48:0] q_addr [0:15]; + reg [7:0] q_len [0:15]; + reg [4:0] q_head = 0, q_tail = 0; + reg [8:0] beat = 0; + integer seed = 7; + wire [4:0] q_used = q_tail - q_head; + always @(posedge clk) begin + // address channel: accept when there is room, sometimes late + m_arready <= 1'b0; + if (m_arvalid && !m_arready && q_used < 5'd8 && ($random(seed) & 3) != 0) begin + m_arready <= 1'b1; + q_addr[q_tail[3:0]] <= m_araddr; + q_len[q_tail[3:0]] <= m_arlen; + q_tail <= q_tail + 5'd1; + if (m_arsize != 3'd3 || m_arburst != 2'b01) begin $display("DMA: bad size or burst"); $finish; end + if ((m_araddr[11:0] + ({4'd0, m_arlen} + 12'd1) * 12'd8) > 13'h1000 && m_araddr[11:0] != 12'd0) begin + $display("DMA: a burst crosses a 4 KiB page at %h", m_araddr); $finish; + end + end + // data channel: one beat at a time, with gaps + if (m_rvalid && m_rready) begin + m_rvalid <= 1'b0; + if (m_rlast) begin q_head <= q_head + 5'd1; beat <= 0; end + else beat <= beat + 9'd1; + end else if (!m_rvalid && q_used != 5'd0 && ($random(seed) % 5) != 0) begin + m_rvalid <= 1'b1; + m_rdata <= mem[(q_addr[q_head[3:0]] - BASE) / 8 + beat]; + m_rlast <= (beat == {1'b0, q_len[q_head[3:0]]}); + m_rresp <= 2'b00; + end + end + + // ---- the write side of the memory model: one burst at a time, with gaps ------------------------ + localparam [48:0] WB_BASE = 49'h0_2000_0000; + reg [63:0] wmem [0:4095]; + reg [48:0] w_addr = 0; + reg w_open = 0; + always @(posedge clk) begin + m_awready <= 1'b0; + m_wready <= 1'b0; + if (m_bvalid && m_bready) m_bvalid <= 1'b0; + if (m_awvalid && !m_awready && !w_open && ($random(seed) & 1) != 0) begin + m_awready <= 1'b1; + w_addr <= m_awaddr; + w_open <= 1'b1; + if (m_awsize != 3'd3 || m_awburst != 2'b01) begin $display("write-back: bad size or burst"); $finish; end + if ({1'b0, m_awaddr[11:0]} + ({5'd0, m_awlen} + 13'd1) * 13'd8 > 13'h1000) begin + $display("write-back: a burst crosses a 4 KiB page at %h", m_awaddr); $finish; + end + end + if (m_wvalid && !m_wready && w_open && ($random(seed) & 3) != 0) m_wready <= 1'b1; + if (m_wvalid && m_wready) begin + if (m_wstrb != 8'hFF) begin $display("write-back: bad strobes"); $finish; end + wmem[(w_addr - WB_BASE) / 8] <= m_wdata; + w_addr <= w_addr + 49'd8; + if (m_wlast) begin w_open <= 1'b0; m_bvalid <= 1'b1; m_bresp <= 2'b00; end + end + end + + // ---- AXI-Lite master tasks -------------------------------------------------------------------- + // The master drives just after a clock edge and samples the slave's outputs at the edge, as + // they were before it: a handshake completes on the edge where valid and ready were both high. + integer line, t; + reg a_ok, w_ok, done_hs; + task axi_write(input [15:0] word, input [31:0] d); + begin + @(posedge clk); #1; + awaddr = 32'hA000_0000 | ({16'd0, word} << 2); wdata = d; awvalid = 1; wvalid = 1; + t = 0; + while (awvalid || wvalid) begin + @(posedge clk); + a_ok = awready; w_ok = wready; + #1; + if (a_ok) awvalid = 0; + if (w_ok) wvalid = 0; + t = t + 1; + if (t > 1000) begin $display("TIMEOUT write %h at line %0d", word, line); $finish; end + end + bready = 1; + done_hs = 0; t = 0; + while (!done_hs) begin + @(posedge clk); + done_hs = bvalid; + #1; + t = t + 1; + if (t > 1000) begin $display("TIMEOUT b at line %0d", line); $finish; end + end + bready = 0; + end + endtask + task axi_read(input [15:0] word, output [31:0] d); + begin + @(posedge clk); #1; + araddr = 32'hA000_0000 | ({16'd0, word} << 2); arvalid = 1; + t = 0; + while (arvalid) begin + @(posedge clk); + a_ok = arready; + #1; + if (a_ok) arvalid = 0; + t = t + 1; + if (t > 1000) begin $display("TIMEOUT ar %h at line %0d", word, line); $finish; end + end + rready = 1; + done_hs = 0; t = 0; + while (!done_hs) begin + @(posedge clk); + done_hs = rvalid; + d = rdata; + #1; + t = t + 1; + if (t > 1000) begin $display("TIMEOUT r at line %0d", line); $finish; end + end + rready = 0; + end + endtask + + integer fd, r, errors, reads, k, n, i, polls, longest; + reg [31:0] op, a, d, m, got, word; + reg [63:0] ent_a, ent_d; + + initial begin + errors = 0; reads = 0; line = 0; longest = 0; + repeat (20) @(posedge clk); + rstn = 1; + repeat (5) @(posedge clk); + if (emio_i[7:0] !== 8'hA5) begin $display("no signature"); $finish; end + axi_read(16'h8000, got); + if (got !== 32'h4C415849) begin $display("wrapper ID %h", got); $finish; end + fd = $fopen("landscape_axi_tb.script", "r"); + if (fd == 0) begin $display("no script"); $finish; end + r = $fscanf(fd, "%s", op); + while (r == 1) begin + line = line + 1; + if (op == "W") begin + r = $fscanf(fd, " %h %h", a, d); + axi_write(a[15:0], d); + end else if (op == "R") begin + r = $fscanf(fd, " %h %h %h", a, d, m); + axi_read(a[15:0], got); + reads = reads + 1; + if ((got & m) !== (d & m)) begin + errors = errors + 1; + if (errors <= 25) $display("MISMATCH line %0d: R %h got %h want %h", line, a[15:0], got, d); + end + end else if (op == "I") begin + got = 1; polls = 0; + while (got[0]) begin + axi_read(16'h0002, got); + polls = polls + 1; + if (polls > 200000) begin $display("TIMEOUT busy at line %0d", line); $finish; end + end + end else if (op == "D") begin + r = $fscanf(fd, " %d", n); + for (k = 0; k < n; k = k + 1) begin + r = $fscanf(fd, " %h %h", ent_a, ent_d); + mem[k] = {16'd0, ent_a[15:0], ent_d[31:0]}; + line = line + 1; + end + axi_write(16'h8002, BASE[31:0]); + axi_write(16'h8003, {15'd0, BASE[48:32]}); + axi_write(16'h8004, n); + axi_write(16'h8005, 1); + got = 2; polls = 0; + while (got[1]) begin + axi_read(16'h8001, got); + polls = polls + 1; + if (polls > 200000) begin $display("TIMEOUT DMA at line %0d", line); $finish; end + end + if (got[2]) begin $display("DMA error at line %0d", line); errors = errors + 1; end + end else if (op == "Q") begin + r = $fscanf(fd, " %d", n); + axi_write(16'h8010, n); + axi_write(16'h8011, 1); + // an engine access while the sequencer holds the engine: answered at once, dropped + axi_read(16'h0000, got); + if (got !== 32'hDEADBEEF) begin $display("an engine read during a batch returned %h at line %0d", got, line); errors = errors + 1; end + axi_read(16'h8008, got); + if (got !== 32'd1) begin $display("DROPS %0d after one dropped read, line %0d", got, line); errors = errors + 1; end + axi_write(16'h8008, 0); + got = 1; polls = 0; + while (got[0]) begin + axi_read(16'h8001, got); + polls = polls + 1; + if (polls > 2000000) begin $display("TIMEOUT sequencer at line %0d", line); $finish; end + end + if (polls > longest) longest = polls; + end else if (op == "K") begin + // the results of the last batch, written back: n chains, six words each, to check + r = $fscanf(fd, " %d", n); + axi_read(16'h8025, d); + axi_write(16'h8020, WB_BASE[31:0]); + axi_write(16'h8021, {15'd0, WB_BASE[48:32]}); + axi_write(16'h8022, 0); + axi_write(16'h8023, n); + axi_write(16'h8024, 1); + got = 8; polls = 0; + while (got[3]) begin + axi_read(16'h8001, got); + polls = polls + 1; + if (polls > 200000) begin $display("TIMEOUT write-back at line %0d", line); $finish; end + end + if (got[4]) begin $display("write-back error at line %0d", line); errors = errors + 1; end + axi_read(16'h8025, got); + if (got !== d + 1) begin $display("write-back did not run at line %0d", line); errors = errors + 1; end + for (k = 0; k < n; k = k + 1) begin + for (i = 0; i < 6; i = i + 1) begin + r = $fscanf(fd, " %h", d); + line = line + 1; + word = (i % 2) ? wmem[k * 4 + i / 2][63:32] : wmem[k * 4 + i / 2][31:0]; + reads = reads + 1; + if (word !== d) begin + errors = errors + 1; + if (errors <= 25) $display("MISMATCH line %0d: written back chain %0d word %0d got %h want %h", line, k, i, word, d); + end + end + end + end else begin + $display("bad op at line %0d", line); + $finish; + end + r = $fscanf(fd, "%s", op); + end + $display("TB DONE: %0d lines, %0d checked reads, %0d mismatches, sim time %0t", line, reads, errors, $time); + $finish; + end +endmodule