From cfe7916cc7083a58ce46cffb03c9c1c5856e227d Mon Sep 17 00:00:00 2001 From: Ethan Uppal <113849268+ethanuppal@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:44:47 -0500 Subject: [PATCH 1/6] Split up #2181 --- Cargo.lock | 82 +- Cargo.toml | 2 + interp/src/lib.rs | 3 + tools/calyx-ffi-macro/Cargo.lock | 554 +++++++ tools/calyx-ffi-macro/Cargo.toml | 24 + tools/calyx-ffi-macro/src/calyx.rs | 51 + tools/calyx-ffi-macro/src/lib.rs | 404 ++++++ tools/calyx-ffi-macro/src/parse.rs | 111 ++ tools/calyx-ffi-macro/src/util.rs | 6 + tools/calyx-ffi/Cargo.lock | 1841 ++++++++++++++++++++++++ tools/calyx-ffi/Cargo.toml | 23 + tools/calyx-ffi/src/backend.rs | 2 + tools/calyx-ffi/src/backend/cider.rs | 109 ++ tools/calyx-ffi/src/backend/useless.rs | 35 + tools/calyx-ffi/src/lib.rs | 82 ++ tools/calyx-ffi/src/prelude.rs | 41 + tools/calyx-ffi/tests/adder.futil | 23 + tools/calyx-ffi/tests/arith_fuzz.rs | 74 + tools/calyx-ffi/tests/fifo.futil | 130 ++ tools/calyx-ffi/tests/fifo.rs | 69 + tools/calyx-ffi/tests/stack.futil | 70 + tools/calyx-ffi/tests/stack.rs | 61 + tools/calyx-ffi/tests/subber.futil | 21 + 23 files changed, 3792 insertions(+), 26 deletions(-) create mode 100644 tools/calyx-ffi-macro/Cargo.lock create mode 100644 tools/calyx-ffi-macro/Cargo.toml create mode 100644 tools/calyx-ffi-macro/src/calyx.rs create mode 100644 tools/calyx-ffi-macro/src/lib.rs create mode 100644 tools/calyx-ffi-macro/src/parse.rs create mode 100644 tools/calyx-ffi-macro/src/util.rs create mode 100644 tools/calyx-ffi/Cargo.lock create mode 100644 tools/calyx-ffi/Cargo.toml create mode 100644 tools/calyx-ffi/src/backend.rs create mode 100644 tools/calyx-ffi/src/backend/cider.rs create mode 100644 tools/calyx-ffi/src/backend/useless.rs create mode 100644 tools/calyx-ffi/src/lib.rs create mode 100644 tools/calyx-ffi/src/prelude.rs create mode 100644 tools/calyx-ffi/tests/adder.futil create mode 100644 tools/calyx-ffi/tests/arith_fuzz.rs create mode 100644 tools/calyx-ffi/tests/fifo.futil create mode 100644 tools/calyx-ffi/tests/fifo.rs create mode 100644 tools/calyx-ffi/tests/stack.futil create mode 100644 tools/calyx-ffi/tests/stack.rs create mode 100644 tools/calyx-ffi/tests/subber.futil diff --git a/Cargo.lock b/Cargo.lock index 7eba776379..70c55dcc13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -91,7 +91,7 @@ dependencies = [ "argh_shared", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -127,7 +127,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -158,7 +158,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -267,7 +267,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -335,6 +335,30 @@ dependencies = [ "vast", ] +[[package]] +name = "calyx-ffi" +version = "0.7.1" +dependencies = [ + "calyx-ffi-macro", + "calyx-frontend", + "calyx-ir", + "interp", + "paste", + "rand 0.8.5", +] + +[[package]] +name = "calyx-ffi-macro" +version = "0.0.0" +dependencies = [ + "calyx-frontend", + "calyx-ir", + "calyx-utils", + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "calyx-frontend" version = "0.7.1" @@ -839,7 +863,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -861,7 +885,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -1201,7 +1225,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -1615,7 +1639,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -1850,6 +1874,12 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pathdiff" version = "0.2.1" @@ -1918,7 +1948,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -1959,7 +1989,7 @@ checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -2028,9 +2058,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -2073,9 +2103,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -2284,7 +2314,7 @@ checksum = "59aecf17969c04b9c0c5d21f6bc9da9fec9dd4980e64d1871443a476589d8c86" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -2395,7 +2425,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -2417,7 +2447,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -2488,7 +2518,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -2668,7 +2698,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -2711,9 +2741,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.58" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -2806,7 +2836,7 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -2909,7 +2939,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -3011,7 +3041,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -3039,7 +3069,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] [[package]] @@ -3535,5 +3565,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.87", ] diff --git a/Cargo.toml b/Cargo.toml index be30dce2d8..ee7dc2efbb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,8 @@ members = [ "tools/component_cells", "tools/yxi", "tools/calyx-writer", + "tools/calyx-ffi", + "tools/calyx-ffi-macro", ] exclude = ["site"] diff --git a/interp/src/lib.rs b/interp/src/lib.rs index 34b3d98a9d..6c6afe53be 100644 --- a/interp/src/lib.rs +++ b/interp/src/lib.rs @@ -8,3 +8,6 @@ pub mod serialization; mod tests; pub mod flatten; + +// ethan: griffin ok'd this +pub use baa::{BitVecOps, BitVecValue}; diff --git a/tools/calyx-ffi-macro/Cargo.lock b/tools/calyx-ffi-macro/Cargo.lock new file mode 100644 index 0000000000..4d7d0901f2 --- /dev/null +++ b/tools/calyx-ffi-macro/Cargo.lock @@ -0,0 +1,554 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[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 = "calyx-ffi-macro" +version = "0.0.0" +dependencies = [ + "calyx-frontend", + "calyx-ir", + "calyx-utils", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "calyx-frontend" +version = "0.7.1" +dependencies = [ + "atty", + "calyx-utils", + "itertools", + "lazy_static", + "linked-hash-map", + "log", + "pest", + "pest_consume", + "pest_derive", + "smallvec", + "strum", + "strum_macros", +] + +[[package]] +name = "calyx-ir" +version = "0.7.1" +dependencies = [ + "calyx-frontend", + "calyx-utils", + "itertools", + "linked-hash-map", + "log", + "petgraph", + "smallvec", + "string-interner", +] + +[[package]] +name = "calyx-utils" +version = "0.7.1" +dependencies = [ + "atty", + "itertools", + "petgraph", + "serde_json", + "string-interner", + "symbol_table", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[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 = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[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.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.1", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "pest" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_consume" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79447402d15d18e7142e14c72f2e63fa3d155be1bc5b70b3ccbb610ac55f536b" +dependencies = [ + "pest", + "pest_consume_macros", + "pest_derive", +] + +[[package]] +name = "pest_consume_macros" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d8630a7a899cb344ec1c16ba0a6b24240029af34bdc0a21f84e411d7f793f29" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pest_derive" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "pest_meta" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.214" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.214" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "serde_json" +version = "1.0.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "string-interner" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e2531d8525b29b514d25e275a43581320d587b86db302b9a7e464bac579648" +dependencies = [ + "cfg-if", + "hashbrown 0.11.2", + "serde", +] + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.87", +] + +[[package]] +name = "symbol_table" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "828f672b631c220bf6ea8a1d3b82c7d0fc998e5ba8373383d8604bc1e2a6245a" +dependencies = [ + "ahash", + "hashbrown 0.12.3", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/tools/calyx-ffi-macro/Cargo.toml b/tools/calyx-ffi-macro/Cargo.toml new file mode 100644 index 0000000000..e9d1eddc15 --- /dev/null +++ b/tools/calyx-ffi-macro/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "calyx-ffi-macro" +authors.workspace = true +license-file.workspace = true +keywords.workspace = true +repository.workspace = true +readme.workspace = true +description.workspace = true +categories.workspace = true +homepage.workspace = true +edition.workspace = true +rust-version.workspace = true + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.86" +quote = "1.0.36" +syn = { version = "2.0.69", features = ["full", "visit"] } +calyx-utils.workspace = true +calyx-frontend.workspace = true +calyx-ir.workspace = true +# bigint = "4.4.3" diff --git a/tools/calyx-ffi-macro/src/calyx.rs b/tools/calyx-ffi-macro/src/calyx.rs new file mode 100644 index 0000000000..4039321976 --- /dev/null +++ b/tools/calyx-ffi-macro/src/calyx.rs @@ -0,0 +1,51 @@ +use std::{env, path::PathBuf, rc::Rc}; + +use proc_macro::TokenStream; + +use crate::{parse::CalyxFFIMacroArgs, util}; + +pub struct CalyxComponent { + ctx: Rc, + index: usize, +} + +impl CalyxComponent { + pub fn get(&self) -> &calyx_ir::Component { + &self.ctx.components[self.index] + } +} + +pub fn parse_calyx_file( + args: &CalyxFFIMacroArgs, + file: PathBuf, +) -> Result { + // there has to be a better way to find lib + let home_dir = env::var("HOME").expect("user home not set"); + let mut lib_path = PathBuf::from(home_dir); + lib_path.push(".calyx"); + let ws = + calyx_frontend::Workspace::construct(&Some(file.clone()), &lib_path) + .map_err(|err| { + util::compile_error(&args.src_attr_span, err.message()) + })?; + let ctx = calyx_ir::from_ast::ast_to_ir(ws).map_err(|err| { + util::compile_error(&args.src_attr_span, err.message()) + })?; + + let comp_index = ctx + .components + .iter() + .position(|comp| comp.name == args.comp) + .ok_or(util::compile_error( + &args.comp_attr_span, + format!( + "component '{}' does not exist in '{}'", + args.comp, + args.src.to_string_lossy() + ), + ))?; + Ok(CalyxComponent { + ctx: Rc::new(ctx), + index: comp_index, + }) +} diff --git a/tools/calyx-ffi-macro/src/lib.rs b/tools/calyx-ffi-macro/src/lib.rs new file mode 100644 index 0000000000..a4c7c76948 --- /dev/null +++ b/tools/calyx-ffi-macro/src/lib.rs @@ -0,0 +1,404 @@ +use std::{env, path::PathBuf}; + +use parse::{CalyxFFIMacroArgs, CalyxPortDeclaration}; +use proc_macro::TokenStream; +use quote::{format_ident, quote}; +use syn::{parse_macro_input, spanned::Spanned}; + +mod calyx; +mod parse; +mod util; + +#[proc_macro_attribute] +pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { + let source_manifest_dir = PathBuf::from( + env::vars() + .find(|(name, _)| name == "CARGO_MANIFEST_DIR") + .expect("caller of calyx_ffi did not use cargo to build project") + .1, + ); + + let args = parse_macro_input!(attrs as CalyxFFIMacroArgs); + let item_struct = parse_macro_input!(item as syn::ItemStruct); + let name = item_struct.ident; + let given_path = args.src.to_string_lossy().to_string(); + + let mut path = source_manifest_dir; + path.push(given_path); + let path = path; + + // + let comp = calyx::parse_calyx_file(&args, path.clone()); + if let Err(error) = comp { + return error; + } + let comp = comp.unwrap(); + let comp = comp.get(); + // + + let comp_name = + syn::parse_str::(&format!("\"{}\"", comp.name)) + .expect("failed to turn quoted name into string"); + let comp_path = syn::parse_str::(&format!( + "\"{}\"", + path.to_string_lossy() + )) + .expect("failed to turn quoted path into string"); + + let backend_macro = args.backend; + let mut input_names = Vec::new(); + let mut output_names = Vec::new(); + let mut fields = vec![]; + let mut default_field_inits = vec![]; + let mut getters = vec![]; + let mut setters = vec![]; + let mut width_getters = vec![]; + let mut port_names = vec![]; + + for port in comp.signature.borrow().ports() { + let port_name_str = port.borrow().name.to_string(); + let port_name = syn::parse_str::(&port_name_str) + .expect("failed to turn port name into identifier"); + + port_names.push(port_name.clone()); + + let port_width = port.borrow().width; + let width_getter = format_ident!("{}_width", port_name); + width_getters.push(quote! { + pub const fn #width_getter() -> u64 { + #port_width + } + }); + + default_field_inits.push(quote! { + #port_name: calyx_ffi::value_from_u64::<#port_width>(0) + }); + + // idk why input output ports are being flipped?? + match port.borrow().direction.reverse() { + calyx_ir::Direction::Input => { + let setter = format_ident!("set_{}", port_name); + fields.push(quote! { + pub #port_name: calyx_ffi::Value<#port_width> + }); + setters.push(quote! { + pub fn #setter(&mut self, value: u64) { + self.#port_name = calyx_ffi::value_from_u64::<#port_width>(value); + } + }); + input_names.push(port_name); + } + calyx_ir::Direction::Output => { + fields.push(quote! { + #port_name: calyx_ffi::Value<#port_width> + + }); + + let bitvec_getter = format_ident!("{}_bits", port_name); + + getters.push(quote! { + pub fn #port_name(&self) -> u64 { + interp::BitVecOps::to_u64(&self.#port_name).expect("port value wider than 64 bits") + } + + pub const fn #bitvec_getter(&self) -> &calyx_ffi::Value<#port_width> { + &self.#port_name + } + }); + output_names.push(port_name); + } + calyx_ir::Direction::Inout => { + todo!("inout ports not supported yet") + } + } + } + + let struct_def = quote! { + struct #name { + #(#fields,)* + user_data: std::mem::MaybeUninit<#backend_macro!(@user_data_type)> + } + }; + + let impl_block = quote! { + impl #name { + #(#width_getters)* + #(#getters)* + #(#setters)* + } + + impl std::default::Default for #name { + fn default() -> Self { + Self { + #(#default_field_inits),*, + user_data: unsafe { std::mem::MaybeUninit::zeroed() } + } + } + } + + impl std::clone::Clone for #name { + fn clone(&self) -> Self { + Self { + #(#port_names: self.#port_names.clone()),*, + user_data: unsafe { std::mem::MaybeUninit::new(self.user_data.assume_init_ref().clone()) } + } + } + } + + impl CalyxFFIComponent for #name { + fn path(&self) -> &'static str { + #comp_path + } + + fn name(&self) -> &'static str { + #comp_name + } + + fn init(&mut self, context: &calyx_ir::Context) { + #backend_macro!(@init self, context; #(#input_names),*; #(#output_names),*); + } + + fn reset(&mut self) { + #backend_macro!(@reset self; #(#input_names),*; #(#output_names),*); + } + + fn can_tick(&self) -> bool { + #backend_macro!(@can_tick self; #(#input_names),*; #(#output_names),*) + } + + fn tick(&mut self) { + #backend_macro!(@tick self; #(#input_names),*; #(#output_names),*); + } + + fn go(&mut self) { + #backend_macro!(@go self; #(#input_names),*; #(#output_names),*); + } + } + }; + + let mut derive_impls = Vec::new(); + + for derive in args.derives { + let trait_name = derive.name; + + let mut getters = Vec::new(); + for CalyxPortDeclaration(name, width) in derive.outputs { + let name_bits = format_ident!("{}_bits", &name); + + getters.push(quote! { + fn #name_bits(&self) -> &calyx_ffi::Value<#width> { + &self.#name + } + + fn #name(&self) -> u64 { + Self::#name(self) + } + }); + } + + let mut setters = Vec::new(); + for CalyxPortDeclaration(name, width) in derive.inputs { + let name_bits = format_ident!("{}_bits", name); + let setter = format_ident!("set_{}", name); + + setters.push(quote! { + fn #name_bits(&mut self) -> &mut calyx_ffi::Value<#width> { + &mut self.#name + } + + fn #setter(&mut self, value: u64) { + Self::#setter(self, value); + } + }); + } + + derive_impls.push(quote! { + impl #trait_name for #name { + #(#getters)* + #(#setters)* + } + }); + } + + quote! { + #struct_def + #impl_block + #(#derive_impls)* + } + .into() +} + +#[derive(Default)] +struct CalyxFFITestModuleVisitor { + pub wrappers: Vec, + pub tests: Vec, +} + +impl syn::visit::Visit<'_> for CalyxFFITestModuleVisitor { + fn visit_item_fn(&mut self, i: &syn::ItemFn) { + let has_calyx_ffi_test = i + .attrs + .iter() + .any(|attr| attr.path().is_ident("calyx_ffi_test")); + if has_calyx_ffi_test { + let fn_name = &i.sig.ident; + let dut_type = get_ffi_test_dut_type(i) + .expect("calyx_ffi_test should enforce this invariant"); + + self.wrappers.push(syn::parse_quote! { + pub(crate) unsafe fn #fn_name(ffi: &mut CalyxFFI) { + let dut = ffi.new_comp::<#dut_type>(); + let dut_ref = &mut *dut.borrow_mut(); + let dut_pointer = dut_ref as *mut dyn CalyxFFIComponent as *mut _ as *mut #dut_type; + let dut_concrete: &mut #dut_type = &mut *dut_pointer; + super::#fn_name(dut_concrete); + } + }); + self.tests.push(syn::parse_quote! { + #[test] + pub(crate) fn #fn_name() { + let mut ffi = CalyxFFI::new(); + unsafe { + super::calyx_ffi_generated_wrappers::#fn_name(&mut ffi); + } + } + }); + } + } +} + +#[proc_macro_attribute] +pub fn calyx_ffi_tests(args: TokenStream, item: TokenStream) -> TokenStream { + if !args.is_empty() { + return util::compile_error( + &args.into_iter().next().unwrap().span().into(), + "#[calyx_ffi_tests] takes no arguments".into(), + ); + } + + let mut module = parse_macro_input!(item as syn::ItemMod); + let module_name = &module.ident; + + let mut visitor = CalyxFFITestModuleVisitor::default(); + syn::visit::visit_item_mod(&mut visitor, &module); + let wrappers = visitor.wrappers; + let tests = visitor.tests; + + let test_names = wrappers.iter().map(|test| test.sig.ident.clone()); + let generated_wrappers = quote! { + pub(crate) mod calyx_ffi_generated_wrappers { + use super::*; + + pub(crate) const CALYX_FFI_TESTS: &'static [unsafe fn(&mut CalyxFFI) -> ()] = &[ + #(#test_names),* + ]; + + #(#wrappers)* + } + }; + let generated_wrappers_item: syn::Item = + syn::parse2(generated_wrappers).unwrap(); + + let generated_tests = quote! { + pub(crate) mod calyx_ffi_generated_tests { + use super::*; + + #(#tests)* + } + }; + let generated_tests_item: syn::Item = syn::parse2(generated_tests).unwrap(); + + let items_to_add = vec![generated_wrappers_item, generated_tests_item]; + if let Some((_, ref mut items)) = module.content { + items.extend(items_to_add); + } else { + module.content = Some((syn::token::Brace::default(), items_to_add)); + } + + quote! { + #module + + pub mod calyx_ffi_generated_top { + use super::*; + + pub unsafe fn run_tests(ffi: &mut CalyxFFI) { + for test in #module_name::calyx_ffi_generated_wrappers::CALYX_FFI_TESTS { + test(ffi); + } + } + } + } + .into() +} + +#[proc_macro_attribute] +pub fn calyx_ffi_test(args: TokenStream, item: TokenStream) -> TokenStream { + if !args.is_empty() { + return util::compile_error( + &args.into_iter().next().unwrap().span().into(), + "#[calyx_ffi_test] takes no arguments".into(), + ); + } + + let mut func = parse_macro_input!(item as syn::ItemFn); + let dut_type = get_ffi_test_dut_type(&func); + let Ok(dut_type) = dut_type else { + return dut_type.err().unwrap(); + }; + + let check_trait_impl = quote! { + { + fn assert_is_calyx_ffi_component() {} + assert_is_calyx_ffi_component::<#dut_type>(); + } + }; + + let check_trait_impl_stmts: syn::Block = syn::parse2(check_trait_impl) + .expect("Failed to parse check_trait_impl as a block"); + + let new_stmts: Vec = check_trait_impl_stmts + .stmts + .iter() + .chain(func.block.stmts.iter()) + .cloned() + .collect(); + + let new_block = syn::Block { + brace_token: func.block.brace_token, + stmts: new_stmts, + }; + func.block = Box::new(new_block); + + quote! { + #func + } + .into() +} + +fn get_ffi_test_dut_type( + func: &syn::ItemFn, +) -> Result<&syn::Type, TokenStream> { + let inputs: Vec<&syn::FnArg> = func.sig.inputs.iter().collect(); + + let bad_sig_msg = "#[calyx_ffi_test] tests must take exactly one argument, namely, a mutable reference to the DUT".into(); + + if inputs.len() != 1 { + return Err(util::compile_error(&func.span(), bad_sig_msg)); + } + let input = inputs.first().unwrap(); + + let syn::FnArg::Typed(pat_ty) = input else { + return Err(util::compile_error(&func.span(), bad_sig_msg)); + }; + + let syn::Type::Reference(syn::TypeReference { + mutability: Some(syn::token::Mut { span: _ }), + ref elem, + .. + }) = *pat_ty.ty + else { + return Err(util::compile_error(&func.span(), bad_sig_msg)); + }; + + Ok(elem) +} diff --git a/tools/calyx-ffi-macro/src/parse.rs b/tools/calyx-ffi-macro/src/parse.rs new file mode 100644 index 0000000000..422b03cea3 --- /dev/null +++ b/tools/calyx-ffi-macro/src/parse.rs @@ -0,0 +1,111 @@ +use std::path::PathBuf; + +use proc_macro2::{Span, TokenTree}; +use syn::{ + bracketed, parenthesized, + parse::{Parse, ParseStream}, +}; + +pub struct CalyxPortDeclaration(pub syn::Ident, pub syn::LitInt); + +impl Parse for CalyxPortDeclaration { + fn parse(input: ParseStream) -> syn::Result { + let name = input.parse::()?; + input.parse::()?; + let width = input.parse::()?; + Ok(Self(name, width)) + } +} + +pub struct CalyxInterface { + pub name: syn::Ident, + pub inputs: Vec, + pub outputs: Vec, +} + +impl Parse for CalyxInterface { + fn parse(input: ParseStream) -> syn::Result { + let name = input.parse::()?; + let inputs; + let outputs; + parenthesized!(inputs in input); + let inputs = inputs + .parse_terminated(CalyxPortDeclaration::parse, syn::Token![,])? + .into_iter() + .collect(); + input.parse::]>()?; + parenthesized!(outputs in input); + let outputs = outputs + .parse_terminated(CalyxPortDeclaration::parse, syn::Token![,])? + .into_iter() + .collect(); + Ok(Self { + name, + inputs, + outputs, + }) + } +} + +pub struct CalyxFFIMacroArgs { + pub src_attr_span: Span, + pub src: PathBuf, + pub comp_attr_span: Span, + pub comp: String, + pub backend: syn::Path, + pub derives: Vec, +} + +impl Parse for CalyxFFIMacroArgs { + fn parse(input: ParseStream) -> syn::Result { + syn::custom_keyword!(src); + syn::custom_keyword!(comp); + syn::custom_keyword!(backend); + syn::custom_keyword!(derive); + + let src_ident = input.parse::()?; + input.parse::()?; + let src_lit = input.parse::()?.value(); + + input.parse::()?; + + let comp_ident = input.parse::()?; + input.parse::()?; + let comp_lit = input.parse::()?.value(); + + input.parse::()?; + input.parse::()?; + input.parse::()?; + let backend_path = input.parse::()?; + + let _ = input.parse::(); + + let derives = if input.parse::().is_ok() { + input.parse::()?; + let content; + bracketed!(content in input); + content + .parse_terminated(CalyxInterface::parse, syn::Token![,])? + .into_iter() + .collect() + } else { + vec![] + }; + + if !input.is_empty() { + return Err(syn::Error::new_spanned( + input.parse::()?, + "Invalid `calyx_ffi` argument syntax: expected 'src = \"...\", comp = \"...\", extern = ...", + )); + } + + Ok(Self { + src_attr_span: src_ident.span, + src: src_lit.into(), + comp_attr_span: comp_ident.span, + comp: comp_lit, + backend: backend_path, + derives, + }) + } +} diff --git a/tools/calyx-ffi-macro/src/util.rs b/tools/calyx-ffi-macro/src/util.rs new file mode 100644 index 0000000000..882a9e0e6b --- /dev/null +++ b/tools/calyx-ffi-macro/src/util.rs @@ -0,0 +1,6 @@ +use proc_macro::TokenStream; +use proc_macro2::Span; + +pub fn compile_error(span: &Span, msg: String) -> TokenStream { + syn::Error::new(*span, msg).to_compile_error().into() +} diff --git a/tools/calyx-ffi/Cargo.lock b/tools/calyx-ffi/Cargo.lock new file mode 100644 index 0000000000..b980509297 --- /dev/null +++ b/tools/calyx-ffi/Cargo.lock @@ -0,0 +1,1841 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + +[[package]] +name = "argh" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7af5ba06967ff7214ce4c7419c7d185be7ecd6cc4965a8f6e1d8ce0398aad219" +dependencies = [ + "argh_derive", + "argh_shared", +] + +[[package]] +name = "argh_derive" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56df0aeedf6b7a2fc67d06db35b09684c3e8da0c95f8f27685cb17e08413d87a" +dependencies = [ + "argh_shared", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "argh_shared" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5693f39141bda5760ecc4111ab08da40565d1771038c4a0250f03457ec707531" +dependencies = [ + "serde", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "bindgen" +version = "0.68.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.87", + "which", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[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 = "btor2i" +version = "0.1.0" +dependencies = [ + "bitvec", + "btor2tools", + "clap", + "num-bigint", + "num-integer", + "num-traits", + "tempfile", + "thiserror", +] + +[[package]] +name = "btor2tools" +version = "1.1.0" +source = "git+https://github.com/obhalerao/btor2tools.rs#8d34a0dc96b447fb008ffbb6f15d1ec947eaefb8" +dependencies = [ + "btor2tools-sys", + "thiserror", +] + +[[package]] +name = "btor2tools-sys" +version = "1.1.0" +source = "git+https://github.com/obhalerao/btor2tools-sys#e5d1c44220cb5a02b30b538c5ade70102109904a" +dependencies = [ + "bindgen", + "copy_dir", +] + +[[package]] +name = "calyx-ffi" +version = "0.0.0" +dependencies = [ + "calyx-ffi-macro", + "calyx-frontend", + "calyx-ir", + "interp", +] + +[[package]] +name = "calyx-ffi-macro" +version = "0.0.0" +dependencies = [ + "calyx-frontend", + "calyx-ir", + "calyx-utils", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "calyx-frontend" +version = "0.7.1" +dependencies = [ + "atty", + "calyx-utils", + "itertools", + "lazy_static", + "linked-hash-map", + "log", + "pest", + "pest_consume", + "pest_derive", + "smallvec", + "strum", + "strum_macros", +] + +[[package]] +name = "calyx-ir" +version = "0.7.1" +dependencies = [ + "calyx-frontend", + "calyx-utils", + "itertools", + "linked-hash-map", + "log", + "petgraph", + "smallvec", + "string-interner", +] + +[[package]] +name = "calyx-opt" +version = "0.7.1" +dependencies = [ + "calyx-ir", + "calyx-utils", + "itertools", + "lazy_static", + "linked-hash-map", + "log", + "petgraph", + "serde", + "serde_json", + "smallvec", +] + +[[package]] +name = "calyx-utils" +version = "0.7.1" +dependencies = [ + "atty", + "itertools", + "petgraph", + "serde", + "serde_json", + "string-interner", + "symbol_table", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim 0.11.1", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "clipboard-win" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362" +dependencies = [ + "error-code", + "str-buf", + "winapi", +] + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "copy_dir" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "543d1dd138ef086e2ff05e3a48cf9da045da2033d16f8538fd76b86cd49b2ca3" +dependencies = [ + "walkdir", +] + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[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 = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "error-code" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" +dependencies = [ + "libc", + "str-buf", +] + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "fd-lock" +version = "3.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" +dependencies = [ + "cfg-if", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fraction" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad18174c73e668720cf9961281ea94a10a8c4003c2b2ad7117252109e5423a3f" +dependencies = [ + "lazy_static", + "num", + "serde", + "serde_derive", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[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.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "ibig" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1fcc7f316b2c079dde77564a1360639c1a956a23fa96122732e416cb10717bb" +dependencies = [ + "cfg-if", + "num-traits", + "rand", + "serde", + "static_assertions", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.1", +] + +[[package]] +name = "interp" +version = "0.1.1" +dependencies = [ + "ahash 0.8.11", + "argh", + "base64", + "bitvec", + "btor2i", + "calyx-frontend", + "calyx-ir", + "calyx-opt", + "calyx-utils", + "ciborium", + "fraction", + "ibig", + "itertools", + "lazy_static", + "once_cell", + "owo-colors", + "pest", + "pest_consume", + "pest_derive", + "petgraph", + "rustyline", + "serde", + "serde_json", + "serde_with", + "slog", + "slog-async", + "slog-term", + "smallvec", + "thiserror", +] + +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "nix" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", + "serde", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pest" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_consume" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79447402d15d18e7142e14c72f2e63fa3d155be1bc5b70b3ccbb610ac55f536b" +dependencies = [ + "pest", + "pest_consume_macros", + "pest_derive", +] + +[[package]] +name = "pest_consume_macros" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d8630a7a899cb344ec1c16ba0a6b24240029af34bdc0a21f84e411d7f793f29" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pest_derive" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "pest_meta" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "prettyplease" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +dependencies = [ + "proc-macro2", + "syn 2.0.87", +] + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + +[[package]] +name = "rustyline" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1cd5ae51d3f7bf65d7969d579d502168ef578f289452bd8ccc91de28fda20e" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "clipboard-win", + "dirs-next", + "fd-lock", + "libc", + "log", + "memchr", + "nix", + "radix_trie", + "scopeguard", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "winapi", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.214" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.214" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "serde_json" +version = "1.0.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +dependencies = [ + "serde", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "slog" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" + +[[package]] +name = "slog-async" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c8038f898a2c79507940990f05386455b3a317d8f18d4caea7cbc3d5096b84" +dependencies = [ + "crossbeam-channel", + "slog", + "take_mut", + "thread_local", +] + +[[package]] +name = "slog-term" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6e022d0b998abfe5c3782c1f03551a596269450ccd677ea51c56f8b214610e8" +dependencies = [ + "is-terminal", + "slog", + "term", + "thread_local", + "time", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "str-buf" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" + +[[package]] +name = "string-interner" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e2531d8525b29b514d25e275a43581320d587b86db302b9a7e464bac579648" +dependencies = [ + "cfg-if", + "hashbrown 0.11.2", + "serde", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.87", +] + +[[package]] +name = "symbol_table" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "828f672b631c220bf6ea8a1d3b82c7d0fc998e5ba8373383d8604bc1e2a6245a" +dependencies = [ + "ahash 0.7.8", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] diff --git a/tools/calyx-ffi/Cargo.toml b/tools/calyx-ffi/Cargo.toml new file mode 100644 index 0000000000..16e87525df --- /dev/null +++ b/tools/calyx-ffi/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "calyx-ffi" +authors.workspace = true +license-file.workspace = true +keywords.workspace = true +repository.workspace = true +readme.workspace = true +description.workspace = true +categories.workspace = true +homepage.workspace = true +edition.workspace = true +version.workspace = true +rust-version.workspace = true + +[dependencies] +calyx-ffi-macro = { path = "../calyx-ffi-macro" } +calyx-frontend.workspace = true +calyx-ir.workspace = true +interp = { path = "../../interp" } +paste = "1.0.15" + +[dev-dependencies] +rand = "0.8.5" diff --git a/tools/calyx-ffi/src/backend.rs b/tools/calyx-ffi/src/backend.rs new file mode 100644 index 0000000000..759f64d89b --- /dev/null +++ b/tools/calyx-ffi/src/backend.rs @@ -0,0 +1,2 @@ +pub mod cider; +pub mod useless; diff --git a/tools/calyx-ffi/src/backend/cider.rs b/tools/calyx-ffi/src/backend/cider.rs new file mode 100644 index 0000000000..a1b98a19e9 --- /dev/null +++ b/tools/calyx-ffi/src/backend/cider.rs @@ -0,0 +1,109 @@ +use calyx_ir::Context; +use interp::{ + configuration::RuntimeConfig, + flatten::{ + flat_ir, + structures::{ + context::Context as CiderContext, + environment::{BaseSimulator, Environment}, + }, + }, + BitVecValue, +}; +use std::rc::Rc; + +#[derive(Clone)] +pub struct CiderFFIBackend { + simulator: BaseSimulator>, +} + +impl CiderFFIBackend { + pub fn from(ctx: &Context, _name: &'static str) -> Self { + // TODO(ethan, maybe griffin): use _name to select the component somehow + let ctx = flat_ir::translate(ctx); + let config = RuntimeConfig::default(); + let enviroment = Environment::new( + Rc::new(ctx), + None, + false, + config.get_logging_config(), + ); + let simulator = BaseSimulator::new(enviroment, config); + Self { simulator } + } + + pub fn write_port(&mut self, name: &'static str, value: &BitVecValue) { + if name == "go" || name == "reset" { + return; + } + self.simulator.pin_value(name, value.clone()); + } + + pub fn read_port(&self, name: &'static str) -> BitVecValue { + self.simulator + .lookup_port_from_string(&String::from(name)) + .expect("wrong port name") + } + + pub fn step(&mut self) { + self.simulator.step().expect( + "this function isn't documented so don't know what went wrong", + ); + } + + pub fn go(&mut self) { + self.simulator + .run_program_inner(None) + .expect("failed to run program"); + self.step(); // since griffin said so + } +} + +/// Runs the component using cider2. +#[macro_export] +macro_rules! cider_ffi_backend { + (@user_data_type) => { + $crate::backend::cider::CiderFFIBackend + }; + (@init $dut:ident, $ctx:expr; $($input:ident),*; $($output:ident),*) => { + $dut.user_data + .write($crate::backend::cider::CiderFFIBackend::from( + $ctx, + $dut.name(), + )); + }; + (@reset $dut:ident; $($input:ident),*; $($output:ident),*) => { + println!("cider_ffi_backend reset. doesn't work LOL"); + // $dut.done = 0; + // $dut.reset = 1; + // for i in 0..5 { + // $dut.tick(); + // } + // $dut.reset = 0; + }; + (@can_tick $dut:ident; $($input:ident),*; $($output:ident),*) => { + true + }; + (@tick $dut:ident; $($input:ident),*; $($output:ident),*) => { + // println!("cider_ffi_backend tick"); + let cider = unsafe { $dut.user_data.assume_init_mut() }; + $( + cider.write_port(stringify!($input), &$dut.$input); + )* + cider.step(); + $( + $dut.$output = cider.read_port(stringify!($output)); + )* + }; + (@go $dut:ident; $($input:ident),*; $($output:ident),*) => { + // println!("cider_ffi_backend go"); + let cider = unsafe { $dut.user_data.assume_init_mut() }; + $( + cider.write_port(stringify!($input), &$dut.$input); + )* + cider.go(); + $( + $dut.$output = cider.read_port(stringify!($output)); + )* + }; +} diff --git a/tools/calyx-ffi/src/backend/useless.rs b/tools/calyx-ffi/src/backend/useless.rs new file mode 100644 index 0000000000..4bc32c4264 --- /dev/null +++ b/tools/calyx-ffi/src/backend/useless.rs @@ -0,0 +1,35 @@ +/// Example FFI backend. +#[macro_export] +macro_rules! useless_ffi_backend { + (@user_data_type) => { + () // unit type + }; + (@init $dut:ident, $ctx:expr; $($input:ident),*; $($output:ident),*) => { + println!("useless_ffi_backend init"); + }; + (@reset $dut:ident; $($input:ident),*; $($output:ident),*) => { + println!("useless_ffi_backend reset"); + $dut.done = interp::BitVecValue::from_u64(0, $dut.done_width() as u32); + $dut.set_reset(1); + for i in 0..5 { + $dut.tick(); + } + $dut.set_reset(0); + }; + (@can_tick $dut:ident; $($input:ident),*; $($output:ident),*) => { + true + }; + (@tick $dut:ident; $($input:ident),*; $($output:ident),*) => { + println!("useless_ffi_backend tick"); + if $dut.done() == 1 { + $dut.set_reset(0); + } + }; + (@go $dut:ident; $($input:ident),*; $($output:ident),*) => { + println!("useless_ffi_backend go"); + $dut.set_go(1); + $dut.set_go(0); + $dut.done = interp::BitVecValue::from_u64(1, $dut.done_width() as u32); + $dut.tick(); + }; +} diff --git a/tools/calyx-ffi/src/lib.rs b/tools/calyx-ffi/src/lib.rs new file mode 100644 index 0000000000..9ba180bc89 --- /dev/null +++ b/tools/calyx-ffi/src/lib.rs @@ -0,0 +1,82 @@ +use calyx_ir::Context; +use std::{ + any, cell::RefCell, collections::HashMap, env, path::PathBuf, rc::Rc, +}; + +pub mod backend; +pub mod prelude; + +/// A non-combinational calyx component. +pub trait CalyxFFIComponent: any::Any { + /// The path to the component source file. Must be a constant expression. + fn path(&self) -> &'static str; + + /// The in-source name of this component. Must be a constant expression. + fn name(&self) -> &'static str; + + /// Internal initialization routine. Do not call! + fn init(&mut self, context: &Context); + + /// Resets this component. + fn reset(&mut self); + + /// Whether this component's backend supports ticking. + fn can_tick(&self) -> bool; + + /// Advances this component by one clock cycle. May not always be available, so check [`has_tick`]([CalyxFFIComponent::has_tick]). + fn tick(&mut self); + + /// Calls this component, blocking until it is done executing. + fn go(&mut self); +} + +pub type CalyxFFIComponentRef = Rc>; + +fn box_calyx_ffi_component( + comp: T, +) -> CalyxFFIComponentRef { + Rc::new(RefCell::new(comp)) +} + +#[derive(Default)] +pub struct CalyxFFI { + contexts: HashMap<&'static str, Context>, +} + +impl CalyxFFI { + pub fn new() -> Self { + Self::default() + } + + /// Constructs a new calyx component of the given type. + /// + /// The `path` implementation for `CalyxFFIComponent` must be a constant + /// expression and should derived via the `calyx_ffi` procedural macro. + pub fn new_comp( + &mut self, + ) -> CalyxFFIComponentRef { + let mut comp = T::default(); + let path = comp.path(); + let context = self.contexts.entry(path).or_insert_with_key(|path| { + // there has to be a better way to find lib + let home_dir = env::var("HOME").expect("user home not set"); + let mut lib_path = PathBuf::from(home_dir); + lib_path.push(".calyx"); + let ws = calyx_frontend::Workspace::construct( + &Some(path.into()), + &lib_path, + ) + .expect("couldn't parse calyx"); + calyx_ir::from_ast::ast_to_ir(ws) + .expect("couldn't construct calyx ir") + }); + comp.init(context); + box_calyx_ffi_component(comp) + } +} + +pub type Value = interp::BitVecValue; + +pub fn value_from_u64(value: u64) -> Value { + Value::from_u64(value, N as u32) +} diff --git a/tools/calyx-ffi/src/prelude.rs b/tools/calyx-ffi/src/prelude.rs new file mode 100644 index 0000000000..425a29c2ec --- /dev/null +++ b/tools/calyx-ffi/src/prelude.rs @@ -0,0 +1,41 @@ +pub use super::{ + value_from_u64, CalyxFFI, CalyxFFIComponent, CalyxFFIComponentRef, Value, +}; +pub use calyx_ffi_macro::{calyx_ffi, calyx_ffi_test, calyx_ffi_tests}; +pub use calyx_ir; +pub use interp; +pub use paste; + +#[macro_export] +macro_rules! declare_interface { + ($name:ident($($input:ident: $input_width:literal),*) + -> ($($output:ident: $output_width:literal),*) + $(impl { + $(fn $fn2:ident(& $self2:ident $(, $arg2:ident: $argty2:ty)* $(,)?) $(-> $ret2:ty)? $body2:block)* + })? + $(mut impl { + $(fn $fn:ident(&mut $self:ident $(, $arg:ident: $argty:ty)* $(,)?) $(-> $ret:ty)? $body:block)* + })? + ) => { + calyx_ffi::prelude::paste::paste! { + pub trait $name: CalyxFFIComponent { + $( + fn [<$input _bits>](&mut self) -> &mut calyx_ffi::Value<$input_width>; + + fn [](&mut self, value: u64); + )* + $( + fn [<$output _bits>](&self) -> &calyx_ffi::Value<$output_width>; + + fn $output(&self) -> u64; + )* + $($( + fn $fn2(&$self2, $($arg2: $argty2),*) $(-> $ret2)* {$body2} + )*)* + $($( + fn $fn(&mut $self, $($arg: $argty),*) $(-> $ret)* {$body} + )*)* + } + } + }; +} diff --git a/tools/calyx-ffi/tests/adder.futil b/tools/calyx-ffi/tests/adder.futil new file mode 100644 index 0000000000..1730a7c5fd --- /dev/null +++ b/tools/calyx-ffi/tests/adder.futil @@ -0,0 +1,23 @@ +import "primitives/core.futil"; + +component main(lhs: 64, rhs: 64) -> (result: 64) { + cells { + adder = std_add(64); + temp = std_reg(64); + } + wires { + group add { + adder.left = lhs; + adder.right = rhs; + temp.in = adder.out; + temp.write_en = 1'b1; + add[done] = temp.done; + } + result = temp.out; + } + control { + add; + } +} + + diff --git a/tools/calyx-ffi/tests/arith_fuzz.rs b/tools/calyx-ffi/tests/arith_fuzz.rs new file mode 100644 index 0000000000..9bc7cdb427 --- /dev/null +++ b/tools/calyx-ffi/tests/arith_fuzz.rs @@ -0,0 +1,74 @@ +use calyx_ffi::prelude::*; + +use calyx_ffi::cider_ffi_backend; + +// not necessary, just to show it off +calyx_ffi::declare_interface! { + In2Out1(lhs: 64, rhs: 64) -> (result: 64) +} + +#[calyx_ffi( + src = "tests/adder.futil", + comp = "main", + backend = cider_ffi_backend, + derive = [ + In2Out1(lhs: 64, rhs: 64) -> (result: 64) + ] +)] +struct Adder; + +#[calyx_ffi( + src = "tests/subber.futil", + comp = "main", + backend = cider_ffi_backend, + derive = [ + In2Out1(lhs: 64, rhs: 64) -> (result: 64) + ] +)] +struct Subber; + +#[cfg(test)] +#[calyx_ffi_tests] +mod tests { + use std::mem; + + use super::*; + use rand::Rng; + + // inv: the left argument will always be greater than the right + fn fuzz_in2out1 u64>( + comp: &mut I, + oracle: &F, + ) { + comp.reset(); + let mut rng = rand::thread_rng(); + for (mut x, mut y) in (0..100).map(|_| (rng.gen(), rng.gen())) { + if y > x { + mem::swap(&mut x, &mut y); + } + comp.set_lhs(x); + comp.set_rhs(y); + comp.go(); + assert_eq!( + oracle(x, y), + comp.result(), + "component did not evaluate f({}, {}) = {} correctly", + x, + y, + oracle(x, y) + ); + } + } + + #[calyx_ffi_test] + fn test_add(adder: &mut Adder) { + println!("testing adder"); + fuzz_in2out1(adder, &|x, y| x.wrapping_add(y)) + } + + #[calyx_ffi_test] + fn test_sub(subber: &mut Subber) { + println!("testing subber"); + fuzz_in2out1(subber, &|x, y| x - y) + } +} diff --git a/tools/calyx-ffi/tests/fifo.futil b/tools/calyx-ffi/tests/fifo.futil new file mode 100644 index 0000000000..6bc65ba106 --- /dev/null +++ b/tools/calyx-ffi/tests/fifo.futil @@ -0,0 +1,130 @@ +import "primitives/core.futil"; +import "primitives/memories/seq.futil"; +import "primitives/binary_operators.futil"; +component fifo(cmd: 1, value: 32) -> () { + cells { + mem = seq_mem_d1(32, 16, 4); + reg_1 = std_reg(4); + reg_2 = std_reg(4); + ref ans = std_reg(32); + ref err = std_reg(1); + reg_3 = std_reg(5); + eq_4 = std_eq(5); + reg_2_incr_1_5 = std_add(4); + reg_3_decr_1_6 = std_sub(5); + eq_7 = std_eq(5); + reg_1_incr_1_8 = std_add(4); + reg_3_incr_1_9 = std_add(5); + cmd_eq_0_10 = std_eq(1); + cmd_eq_1_11 = std_eq(1); + } + wires { + group raise_err { + err.in = 1'd1; + err.write_en = 1'd1; + raise_err[done] = err.done; + } + comb group eq_4_group { + eq_4.left = reg_3.out; + eq_4.right = 5'd0; + } + group read_payload_from_mem_pop { + mem.addr0 = reg_2.out; + mem.content_en = 1'd1; + ans.write_en = mem.done ? 1'd1; + ans.in = mem.done ? mem.read_data; + read_payload_from_mem_pop[done] = ans.done; + } + group reg_2_incr_1_5_group { + reg_2_incr_1_5.left = reg_2.out; + reg_2_incr_1_5.right = 4'd1; + reg_2.write_en = 1'd1; + reg_2.in = reg_2_incr_1_5.out; + reg_2_incr_1_5_group[done] = reg_2.done; + } + group reg_3_decr_1_6_group { + reg_3_decr_1_6.left = reg_3.out; + reg_3_decr_1_6.right = 5'd1; + reg_3.write_en = 1'd1; + reg_3.in = reg_3_decr_1_6.out; + reg_3_decr_1_6_group[done] = reg_3.done; + } + comb group eq_7_group { + eq_7.left = reg_3.out; + eq_7.right = 5'd16; + } + group write_payload_to_mem { + mem.addr0 = reg_1.out; + mem.write_en = 1'd1; + mem.write_data = value; + write_payload_to_mem[done] = mem.done; + mem.content_en = 1'd1; + } + group reg_1_incr_1_8_group { + reg_1_incr_1_8.left = reg_1.out; + reg_1_incr_1_8.right = 4'd1; + reg_1.write_en = 1'd1; + reg_1.in = reg_1_incr_1_8.out; + reg_1_incr_1_8_group[done] = reg_1.done; + } + group reg_3_incr_1_9_group { + reg_3_incr_1_9.left = reg_3.out; + reg_3_incr_1_9.right = 5'd1; + reg_3.write_en = 1'd1; + reg_3.in = reg_3_incr_1_9.out; + reg_3_incr_1_9_group[done] = reg_3.done; + } + cmd_eq_0_10.left = cmd; + cmd_eq_0_10.right = 1'd0; + cmd_eq_1_11.left = cmd; + cmd_eq_1_11.right = 1'd1; + } + control { + par { + if cmd_eq_0_10.out { + if eq_4.out with eq_4_group { + raise_err; + } else { + seq { + read_payload_from_mem_pop; + reg_2_incr_1_5_group; + reg_3_decr_1_6_group; + } + } + } + if cmd_eq_1_11.out { + if eq_7.out with eq_7_group { + raise_err; + } else { + seq { + write_payload_to_mem; + reg_1_incr_1_8_group; + reg_3_incr_1_9_group; + } + } + } + } + } +} +component main(cmd: 1, value: 32) -> (ans: 32, err: 1) { + cells { + ans_reg = std_reg(32); + err_reg = std_reg(1); + queue = fifo(); + } + wires { + ans = ans_reg.out; + err = err_reg.out; + group dummy { + ans_reg.in = ans_reg.out; + ans_reg.write_en = 1'b1; + dummy[done] = ans_reg.done; + } + } + control { + seq { + invoke queue[ans = ans_reg, err = err_reg](cmd = cmd, value = value)(); + dummy; + } + } +} diff --git a/tools/calyx-ffi/tests/fifo.rs b/tools/calyx-ffi/tests/fifo.rs new file mode 100644 index 0000000000..f1199f5406 --- /dev/null +++ b/tools/calyx-ffi/tests/fifo.rs @@ -0,0 +1,69 @@ +use calyx_ffi::cider_ffi_backend; +use calyx_ffi::prelude::*; + +enum QueueCommand { + Pop = 0, + Push = 1, +} + +#[derive(PartialEq, Eq, Debug)] +enum QueueStatus { + Ok = 0, + Err = 1, +} + +calyx_ffi::declare_interface! { + Queue(cmd: 1, value: 32) -> (ans: 32, err: 1) impl { + fn status(&self) -> QueueStatus { + if self.err() == 0 { QueueStatus::Ok } else { QueueStatus::Err } + } + } mut impl { + fn assert_no_error(&mut self) { + assert_eq!(QueueStatus::Ok, self.status(), "queue underflowed or overflowed"); + } + + fn push(&mut self, value: u32) { + self.reset(); + self.set_cmd(QueueCommand::Push as u64); + self.set_value(value as u64); + self.go(); + self.assert_no_error(); + } + + fn pop(&mut self) -> u32 { + self.reset(); + self.set_cmd(QueueCommand::Pop as u64); + self.go(); + self.assert_no_error(); + self.ans() as u32 + } + } +} + +#[calyx_ffi( + src = "tests/fifo.futil", + comp = "main", + backend = cider_ffi_backend, + derive = [ + Queue(cmd: 1, value: 32) -> (ans: 32, err: 1) + ] +)] +struct Fifo; + +#[cfg(test)] +#[calyx_ffi_tests] +mod tests { + use super::*; + + #[calyx_ffi_test] + fn test_fifo(fifo: &mut Fifo) { + println!("testing fifo"); + + fifo.push(1); + fifo.push(2); + assert_eq!(1, fifo.pop()); + fifo.push(3); + assert_eq!(2, fifo.pop()); + assert_eq!(3, fifo.pop()); + } +} diff --git a/tools/calyx-ffi/tests/stack.futil b/tools/calyx-ffi/tests/stack.futil new file mode 100644 index 0000000000..11575c4c0c --- /dev/null +++ b/tools/calyx-ffi/tests/stack.futil @@ -0,0 +1,70 @@ +import "primitives/core.futil"; +import "primitives/memories/seq.futil"; +import "primitives/binary_operators.futil"; + +component main(cmd: 1, value: 32) -> (out: 32, length: 4) { + cells { + store = seq_mem_d1(32, 16, 4); + next = std_reg( 4); + incr = std_add( 4); + decr = std_sub( 4); + last = std_reg(32); + test = std_eq(1); + } + wires { + out = last.out; + length = next.out; + + comb group check_cmd { + test.left = cmd; + test.right = 1'b0; + } + + group write_at_next { + store.addr0 = next.out; + store.write_data = value; + store.write_en = 1'b1; + store.content_en = 1'b1; + write_at_next[done] = store.done; + } + group read_from_next { + store.addr0 = next.out; + store.content_en = 1'b1; + last.in = store.read_data; + last.write_en = store.done; + read_from_next[done] = last.done; + } + group increment_next { + incr.left = next.out; + incr.right = 4'd1; + next.in = incr.out; + next.write_en = 1'b1; + increment_next[done] = next.done; + } + group decrement_next { + decr.left = next.out; + decr.right = 4'd1; + next.in = decr.out; + next.write_en = 1'b1; + decrement_next[done] = next.done; + } + } + control { + // if-else is buggy in cider2 + par { + if test.out with check_cmd { + seq { + write_at_next; + increment_next; + } + } + if cmd { + seq { + decrement_next; + read_from_next; + } + } + } + } +} + diff --git a/tools/calyx-ffi/tests/stack.rs b/tools/calyx-ffi/tests/stack.rs new file mode 100644 index 0000000000..8e5b0d60a8 --- /dev/null +++ b/tools/calyx-ffi/tests/stack.rs @@ -0,0 +1,61 @@ +use calyx_ffi::cider_ffi_backend; +use calyx_ffi::prelude::*; + +enum StackCommand { + Push = 0, + Pop = 1, +} + +const STACK_CAPACITY: u64 = 16; + +calyx_ffi::declare_interface! { + Stack(cmd: 1, value: 32) -> (out: 32, length: 4) mut impl { + fn push(&mut self, value: u32,) { + assert!(self.length() < STACK_CAPACITY, "tried to push when length={}", STACK_CAPACITY); + println!("stack has length {} before push", self.length()); + let old_length = self.length(); + self.set_cmd(StackCommand::Push as u64); + self.set_value(value as u64); + self.go(); + assert_eq!(old_length + 1, self.length(), "stack length should increase by 1 on push"); + } + + fn pop(&mut self) -> u32 { + assert!(self.length() > 0, "tried to pop when stack empty"); + println!("stack has length {} before pop", self.length()); + let old_length = self.length(); + self.set_cmd(StackCommand::Pop as u64); + self.go(); + assert_eq!(old_length - 1, self.length(), "stack length should decrease by 1 on pop"); + self.out() as u32 + } + } +} + +#[calyx_ffi( + src = "tests/stack.futil", + comp = "main", + backend = cider_ffi_backend, + derive = [ + Stack(cmd: 1, value: 32) -> (out: 32, length: 4) + ] +)] +struct ReallyBadStack; + +#[cfg(test)] +#[calyx_ffi_tests] +mod tests { + use super::*; + + #[calyx_ffi_test] + fn test_stack(stack: &mut ReallyBadStack) { + println!("testing stack"); + + stack.push(1); + stack.push(2); + assert_eq!(2, stack.pop()); + stack.push(3); + assert_eq!(3, stack.pop()); + assert_eq!(1, stack.pop()); + } +} diff --git a/tools/calyx-ffi/tests/subber.futil b/tools/calyx-ffi/tests/subber.futil new file mode 100644 index 0000000000..260456f938 --- /dev/null +++ b/tools/calyx-ffi/tests/subber.futil @@ -0,0 +1,21 @@ +import "primitives/core.futil"; + +component main(lhs: 64, rhs: 64) -> (result: 64) { + cells { + subber = std_sub(64); + temp = std_reg(64); + } + wires { + group sub { + subber.left = lhs; + subber.right = rhs; + temp.in = subber.out; + temp.write_en = 1'b1; + sub[done] = temp.done; + } + result = temp.out; + } + control { + sub; + } +} From caf6055df07b4b7de494e205f4a3d016682dde7c Mon Sep 17 00:00:00 2001 From: Ethan Uppal <113849268+ethanuppal@users.noreply.github.com> Date: Wed, 20 Nov 2024 15:55:33 -0500 Subject: [PATCH 2/6] Implement compile-time port width verification --- interp/src/lib.rs | 3 +- tools/calyx-ffi-macro/src/lib.rs | 27 +- tools/calyx-ffi/src/backend/cider.rs | 8 +- tools/calyx-ffi/src/interface.rs | 73 ++++ tools/calyx-ffi/src/lib.rs | 82 +---- tools/calyx-ffi/src/prelude.rs | 7 +- tools/calyx-ffi/src/value.rs | 58 ++++ tools/calyx-ffi/test.rs | 479 +++++++++++++++++++++++++++ tools/calyx-ffi/tests/arith_fuzz.rs | 4 +- 9 files changed, 639 insertions(+), 102 deletions(-) create mode 100644 tools/calyx-ffi/src/interface.rs create mode 100644 tools/calyx-ffi/src/value.rs create mode 100644 tools/calyx-ffi/test.rs diff --git a/interp/src/lib.rs b/interp/src/lib.rs index 6c6afe53be..b6545d6642 100644 --- a/interp/src/lib.rs +++ b/interp/src/lib.rs @@ -9,5 +9,4 @@ mod tests; pub mod flatten; -// ethan: griffin ok'd this -pub use baa::{BitVecOps, BitVecValue}; +pub use baa::{BitVecOps, BitVecValue, WidthInt, Word}; diff --git a/tools/calyx-ffi-macro/src/lib.rs b/tools/calyx-ffi-macro/src/lib.rs index a4c7c76948..6bc7206567 100644 --- a/tools/calyx-ffi-macro/src/lib.rs +++ b/tools/calyx-ffi-macro/src/lib.rs @@ -1,3 +1,5 @@ +#![forbid(unsafe_code)] + use std::{env, path::PathBuf}; use parse::{CalyxFFIMacroArgs, CalyxPortDeclaration}; @@ -9,6 +11,9 @@ mod calyx; mod parse; mod util; +// this is super bad, might go out of sync with interp::WidthInt +type WidthInt = u32; + #[proc_macro_attribute] pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { let source_manifest_dir = PathBuf::from( @@ -62,16 +67,16 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { port_names.push(port_name.clone()); - let port_width = port.borrow().width; + let port_width = port.borrow().width as WidthInt; let width_getter = format_ident!("{}_width", port_name); width_getters.push(quote! { - pub const fn #width_getter() -> u64 { - #port_width + pub const fn #width_getter() -> calyx_ffi::value::WidthInt { + #port_width as calyx_ffi::value::WidthInt } }); default_field_inits.push(quote! { - #port_name: calyx_ffi::value_from_u64::<#port_width>(0) + #port_name: calyx_ffi::value::Value::from(0) }); // idk why input output ports are being flipped?? @@ -79,18 +84,18 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { calyx_ir::Direction::Input => { let setter = format_ident!("set_{}", port_name); fields.push(quote! { - pub #port_name: calyx_ffi::Value<#port_width> + pub #port_name: calyx_ffi::value::Value<#port_width> }); setters.push(quote! { pub fn #setter(&mut self, value: u64) { - self.#port_name = calyx_ffi::value_from_u64::<#port_width>(value); + self.#port_name = calyx_ffi::value::Value::from(value); } }); input_names.push(port_name); } calyx_ir::Direction::Output => { fields.push(quote! { - #port_name: calyx_ffi::Value<#port_width> + #port_name: calyx_ffi::value::Value<#port_width> }); @@ -98,10 +103,10 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { getters.push(quote! { pub fn #port_name(&self) -> u64 { - interp::BitVecOps::to_u64(&self.#port_name).expect("port value wider than 64 bits") + (&self.#port_name).try_into().expect("port value wider than 64 bits") } - pub const fn #bitvec_getter(&self) -> &calyx_ffi::Value<#port_width> { + pub const fn #bitvec_getter(&self) -> &calyx_ffi::value::Value<#port_width> { &self.#port_name } }); @@ -186,7 +191,7 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { let name_bits = format_ident!("{}_bits", &name); getters.push(quote! { - fn #name_bits(&self) -> &calyx_ffi::Value<#width> { + fn #name_bits(&self) -> &calyx_ffi::value::Value<#width> { &self.#name } @@ -202,7 +207,7 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { let setter = format_ident!("set_{}", name); setters.push(quote! { - fn #name_bits(&mut self) -> &mut calyx_ffi::Value<#width> { + fn #name_bits(&mut self) -> &mut calyx_ffi::value::Value<#width> { &mut self.#name } diff --git a/tools/calyx-ffi/src/backend/cider.rs b/tools/calyx-ffi/src/backend/cider.rs index a1b98a19e9..46935a47b8 100644 --- a/tools/calyx-ffi/src/backend/cider.rs +++ b/tools/calyx-ffi/src/backend/cider.rs @@ -88,22 +88,22 @@ macro_rules! cider_ffi_backend { // println!("cider_ffi_backend tick"); let cider = unsafe { $dut.user_data.assume_init_mut() }; $( - cider.write_port(stringify!($input), &$dut.$input); + cider.write_port(stringify!($input), &$dut.$input.inner); )* cider.step(); $( - $dut.$output = cider.read_port(stringify!($output)); + $dut.$output.inner = cider.read_port(stringify!($output)); )* }; (@go $dut:ident; $($input:ident),*; $($output:ident),*) => { // println!("cider_ffi_backend go"); let cider = unsafe { $dut.user_data.assume_init_mut() }; $( - cider.write_port(stringify!($input), &$dut.$input); + cider.write_port(stringify!($input), &$dut.$input.inner); )* cider.go(); $( - $dut.$output = cider.read_port(stringify!($output)); + $dut.$output.inner = cider.read_port(stringify!($output)); )* }; } diff --git a/tools/calyx-ffi/src/interface.rs b/tools/calyx-ffi/src/interface.rs new file mode 100644 index 0000000000..c93773d5ea --- /dev/null +++ b/tools/calyx-ffi/src/interface.rs @@ -0,0 +1,73 @@ +use calyx_ir::Context; +use std::{ + any, cell::RefCell, collections::HashMap, env, path::PathBuf, rc::Rc, +}; + +/// A non-combinational calyx component. +pub trait CalyxFFIComponent: any::Any { + /// The path to the component source file. Must be a constant expression. + fn path(&self) -> &'static str; + + /// The in-source name of this component. Must be a constant expression. + fn name(&self) -> &'static str; + + /// Internal initialization routine. Do not call! + fn init(&mut self, context: &Context); + + /// Resets this component. + fn reset(&mut self); + + /// Whether this component's backend supports ticking. + fn can_tick(&self) -> bool; + + /// Advances this component by one clock cycle. May not always be available, so check [`has_tick`]([CalyxFFIComponent::has_tick]). + fn tick(&mut self); + + /// Calls this component, blocking until it is done executing. + fn go(&mut self); +} + +pub type CalyxFFIComponentRef = Rc>; + +fn box_calyx_ffi_component( + comp: T, +) -> CalyxFFIComponentRef { + Rc::new(RefCell::new(comp)) +} + +#[derive(Default)] +pub struct CalyxFFI { + contexts: HashMap<&'static str, Context>, +} + +impl CalyxFFI { + pub fn new() -> Self { + Self::default() + } + + /// Constructs a new calyx component of the given type. + /// + /// The `path` implementation for `CalyxFFIComponent` must be a constant + /// expression and should derived via the `calyx_ffi` procedural macro. + pub fn new_comp( + &mut self, + ) -> CalyxFFIComponentRef { + let mut comp = T::default(); + let path = comp.path(); + let context = self.contexts.entry(path).or_insert_with_key(|path| { + // there has to be a better way to find lib + let home_dir = env::var("HOME").expect("user home not set"); + let mut lib_path = PathBuf::from(home_dir); + lib_path.push(".calyx"); + let ws = calyx_frontend::Workspace::construct( + &Some(path.into()), + &lib_path, + ) + .expect("couldn't parse calyx"); + calyx_ir::from_ast::ast_to_ir(ws) + .expect("couldn't construct calyx ir") + }); + comp.init(context); + box_calyx_ffi_component(comp) + } +} diff --git a/tools/calyx-ffi/src/lib.rs b/tools/calyx-ffi/src/lib.rs index 9ba180bc89..df7f17b2d1 100644 --- a/tools/calyx-ffi/src/lib.rs +++ b/tools/calyx-ffi/src/lib.rs @@ -1,82 +1,4 @@ -use calyx_ir::Context; -use std::{ - any, cell::RefCell, collections::HashMap, env, path::PathBuf, rc::Rc, -}; - pub mod backend; +pub mod interface; pub mod prelude; - -/// A non-combinational calyx component. -pub trait CalyxFFIComponent: any::Any { - /// The path to the component source file. Must be a constant expression. - fn path(&self) -> &'static str; - - /// The in-source name of this component. Must be a constant expression. - fn name(&self) -> &'static str; - - /// Internal initialization routine. Do not call! - fn init(&mut self, context: &Context); - - /// Resets this component. - fn reset(&mut self); - - /// Whether this component's backend supports ticking. - fn can_tick(&self) -> bool; - - /// Advances this component by one clock cycle. May not always be available, so check [`has_tick`]([CalyxFFIComponent::has_tick]). - fn tick(&mut self); - - /// Calls this component, blocking until it is done executing. - fn go(&mut self); -} - -pub type CalyxFFIComponentRef = Rc>; - -fn box_calyx_ffi_component( - comp: T, -) -> CalyxFFIComponentRef { - Rc::new(RefCell::new(comp)) -} - -#[derive(Default)] -pub struct CalyxFFI { - contexts: HashMap<&'static str, Context>, -} - -impl CalyxFFI { - pub fn new() -> Self { - Self::default() - } - - /// Constructs a new calyx component of the given type. - /// - /// The `path` implementation for `CalyxFFIComponent` must be a constant - /// expression and should derived via the `calyx_ffi` procedural macro. - pub fn new_comp( - &mut self, - ) -> CalyxFFIComponentRef { - let mut comp = T::default(); - let path = comp.path(); - let context = self.contexts.entry(path).or_insert_with_key(|path| { - // there has to be a better way to find lib - let home_dir = env::var("HOME").expect("user home not set"); - let mut lib_path = PathBuf::from(home_dir); - lib_path.push(".calyx"); - let ws = calyx_frontend::Workspace::construct( - &Some(path.into()), - &lib_path, - ) - .expect("couldn't parse calyx"); - calyx_ir::from_ast::ast_to_ir(ws) - .expect("couldn't construct calyx ir") - }); - comp.init(context); - box_calyx_ffi_component(comp) - } -} - -pub type Value = interp::BitVecValue; - -pub fn value_from_u64(value: u64) -> Value { - Value::from_u64(value, N as u32) -} +pub mod value; diff --git a/tools/calyx-ffi/src/prelude.rs b/tools/calyx-ffi/src/prelude.rs index 425a29c2ec..accb64d95a 100644 --- a/tools/calyx-ffi/src/prelude.rs +++ b/tools/calyx-ffi/src/prelude.rs @@ -1,5 +1,6 @@ pub use super::{ - value_from_u64, CalyxFFI, CalyxFFIComponent, CalyxFFIComponentRef, Value, + interface::{CalyxFFI, CalyxFFIComponent, CalyxFFIComponentRef}, + value::Value, }; pub use calyx_ffi_macro::{calyx_ffi, calyx_ffi_test, calyx_ffi_tests}; pub use calyx_ir; @@ -20,12 +21,12 @@ macro_rules! declare_interface { calyx_ffi::prelude::paste::paste! { pub trait $name: CalyxFFIComponent { $( - fn [<$input _bits>](&mut self) -> &mut calyx_ffi::Value<$input_width>; + fn [<$input _bits>](&mut self) -> &mut calyx_ffi::value::Value<$input_width>; fn [](&mut self, value: u64); )* $( - fn [<$output _bits>](&self) -> &calyx_ffi::Value<$output_width>; + fn [<$output _bits>](&self) -> &calyx_ffi::value::Value<$output_width>; fn $output(&self) -> u64; )* diff --git a/tools/calyx-ffi/src/value.rs b/tools/calyx-ffi/src/value.rs new file mode 100644 index 0000000000..e32b198c5c --- /dev/null +++ b/tools/calyx-ffi/src/value.rs @@ -0,0 +1,58 @@ +use std::{error, fmt}; + +pub use interp::WidthInt; + +#[derive(Debug)] +pub enum ValueConversionError { + WidthTooLarge(interp::WidthInt), +} + +impl fmt::Display for ValueConversionError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ValueConversionError::WidthTooLarge(width) => { + write!( + f, + "Failed to convert bitvector of width `{}` into `u64`", + width + ) + } + } + } +} + +impl error::Error for ValueConversionError {} + +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)] +pub struct Value { + pub inner: interp::BitVecValue, +} + +impl From for Value { + fn from(value: u64) -> Self { + Self { + inner: interp::BitVecValue::from_u64(value, N), + } + } +} + +impl TryInto for &Value { + type Error = ValueConversionError; + + fn try_into(self) -> Result { + use interp::BitVecOps; + self.inner + .to_u64() + .ok_or(Self::Error::WidthTooLarge(self.inner.width())) + } +} + +impl interp::BitVecOps for Value { + fn width(&self) -> interp::WidthInt { + N + } + + fn words(&self) -> &[interp::Word] { + self.inner.words() + } +} diff --git a/tools/calyx-ffi/test.rs b/tools/calyx-ffi/test.rs new file mode 100644 index 0000000000..718f4c0556 --- /dev/null +++ b/tools/calyx-ffi/test.rs @@ -0,0 +1,479 @@ +#![feature(prelude_import)] +#[prelude_import] +use std::prelude::rust_2021::*; +#[macro_use] +extern crate std; +use calyx_ffi::prelude::*; +use calyx_ffi::cider_ffi_backend; +pub trait In2Out1: CalyxFFIComponent { + fn lhs_bits(&mut self) -> &mut calyx_ffi::value::Value<64>; + fn set_lhs(&mut self, value: u64); + fn rhs_bits(&mut self) -> &mut calyx_ffi::value::Value<64>; + fn set_rhs(&mut self, value: u64); + fn result_bits(&self) -> &calyx_ffi::value::Value<64>; + fn result(&self) -> u64; +} +struct Adder { + pub lhs: calyx_ffi::value::Value<64u64>, + pub rhs: calyx_ffi::value::Value<64u64>, + result: calyx_ffi::value::Value<64u64>, + pub go: calyx_ffi::value::Value<1u64>, + pub clk: calyx_ffi::value::Value<1u64>, + pub reset: calyx_ffi::value::Value<1u64>, + done: calyx_ffi::value::Value<1u64>, + user_data: std::mem::MaybeUninit<::calyx_ffi::backend::cider::CiderFFIBackend>, +} +impl Adder { + pub const fn lhs_width() -> calyx_ffi::value::WidthInt { + 64u64 as calyx_ffi::value::WidthInt + } + pub const fn rhs_width() -> calyx_ffi::value::WidthInt { + 64u64 as calyx_ffi::value::WidthInt + } + pub const fn result_width() -> calyx_ffi::value::WidthInt { + 64u64 as calyx_ffi::value::WidthInt + } + pub const fn go_width() -> calyx_ffi::value::WidthInt { + 1u64 as calyx_ffi::value::WidthInt + } + pub const fn clk_width() -> calyx_ffi::value::WidthInt { + 1u64 as calyx_ffi::value::WidthInt + } + pub const fn reset_width() -> calyx_ffi::value::WidthInt { + 1u64 as calyx_ffi::value::WidthInt + } + pub const fn done_width() -> calyx_ffi::value::WidthInt { + 1u64 as calyx_ffi::value::WidthInt + } + pub fn result(&self) -> u64 { + (&self.result).try_into().expect("port value wider than 64 bits") + } + pub const fn result_bits(&self) -> &calyx_ffi::value::Value<64u64> { + &self.result + } + pub fn done(&self) -> u64 { + (&self.done).try_into().expect("port value wider than 64 bits") + } + pub const fn done_bits(&self) -> &calyx_ffi::value::Value<1u64> { + &self.done + } + pub fn set_lhs(&mut self, value: u64) { + self.lhs = calyx_ffi::value::Value::from(value); + } + pub fn set_rhs(&mut self, value: u64) { + self.rhs = calyx_ffi::value::Value::from(value); + } + pub fn set_go(&mut self, value: u64) { + self.go = calyx_ffi::value::Value::from(value); + } + pub fn set_clk(&mut self, value: u64) { + self.clk = calyx_ffi::value::Value::from(value); + } + pub fn set_reset(&mut self, value: u64) { + self.reset = calyx_ffi::value::Value::from(value); + } +} +impl std::default::Default for Adder { + fn default() -> Self { + Self { + lhs: calyx_ffi::value::Value::from(0), + rhs: calyx_ffi::value::Value::from(0), + result: calyx_ffi::value::Value::from(0), + go: calyx_ffi::value::Value::from(0), + clk: calyx_ffi::value::Value::from(0), + reset: calyx_ffi::value::Value::from(0), + done: calyx_ffi::value::Value::from(0), + user_data: unsafe { std::mem::MaybeUninit::zeroed() }, + } + } +} +impl std::clone::Clone for Adder { + fn clone(&self) -> Self { + Self { + lhs: self.lhs.clone(), + rhs: self.rhs.clone(), + result: self.result.clone(), + go: self.go.clone(), + clk: self.clk.clone(), + reset: self.reset.clone(), + done: self.done.clone(), + user_data: unsafe { + std::mem::MaybeUninit::new(self.user_data.assume_init_ref().clone()) + }, + } + } +} +impl CalyxFFIComponent for Adder { + fn path(&self) -> &'static str { + "/Users/ethan/Documents/GitHub/calyx/tools/calyx-ffi/tests/adder.futil" + } + fn name(&self) -> &'static str { + "main" + } + fn init(&mut self, context: &calyx_ir::Context) { + self.user_data + .write( + ::calyx_ffi::backend::cider::CiderFFIBackend::from(context, self.name()), + ); + } + fn reset(&mut self) { + { + ::std::io::_print( + format_args!("cider_ffi_backend reset. doesn\'t work LOL\n"), + ); + }; + } + fn can_tick(&self) -> bool { + true + } + fn tick(&mut self) { + let cider = unsafe { self.user_data.assume_init_mut() }; + cider.write_port("lhs", &self.lhs.inner); + cider.write_port("rhs", &self.rhs.inner); + cider.write_port("go", &self.go.inner); + cider.write_port("clk", &self.clk.inner); + cider.write_port("reset", &self.reset.inner); + cider.step(); + self.result.inner = cider.read_port("result"); + self.done.inner = cider.read_port("done"); + } + fn go(&mut self) { + let cider = unsafe { self.user_data.assume_init_mut() }; + cider.write_port("lhs", &self.lhs.inner); + cider.write_port("rhs", &self.rhs.inner); + cider.write_port("go", &self.go.inner); + cider.write_port("clk", &self.clk.inner); + cider.write_port("reset", &self.reset.inner); + cider.go(); + self.result.inner = cider.read_port("result"); + self.done.inner = cider.read_port("done"); + } +} +impl In2Out1 for Adder { + fn result_bits(&self) -> &calyx_ffi::value::Value<64> { + &self.result + } + fn result(&self) -> u64 { + Self::result(self) + } + fn lhs_bits(&mut self) -> &mut calyx_ffi::value::Value<64> { + &mut self.lhs + } + fn set_lhs(&mut self, value: u64) { + Self::set_lhs(self, value); + } + fn rhs_bits(&mut self) -> &mut calyx_ffi::value::Value<64> { + &mut self.rhs + } + fn set_rhs(&mut self, value: u64) { + Self::set_rhs(self, value); + } +} +struct Subber { + pub lhs: calyx_ffi::value::Value<64u64>, + pub rhs: calyx_ffi::value::Value<64u64>, + result: calyx_ffi::value::Value<64u64>, + pub go: calyx_ffi::value::Value<1u64>, + pub clk: calyx_ffi::value::Value<1u64>, + pub reset: calyx_ffi::value::Value<1u64>, + done: calyx_ffi::value::Value<1u64>, + user_data: std::mem::MaybeUninit<::calyx_ffi::backend::cider::CiderFFIBackend>, +} +impl Subber { + pub const fn lhs_width() -> calyx_ffi::value::WidthInt { + 64u64 as calyx_ffi::value::WidthInt + } + pub const fn rhs_width() -> calyx_ffi::value::WidthInt { + 64u64 as calyx_ffi::value::WidthInt + } + pub const fn result_width() -> calyx_ffi::value::WidthInt { + 64u64 as calyx_ffi::value::WidthInt + } + pub const fn go_width() -> calyx_ffi::value::WidthInt { + 1u64 as calyx_ffi::value::WidthInt + } + pub const fn clk_width() -> calyx_ffi::value::WidthInt { + 1u64 as calyx_ffi::value::WidthInt + } + pub const fn reset_width() -> calyx_ffi::value::WidthInt { + 1u64 as calyx_ffi::value::WidthInt + } + pub const fn done_width() -> calyx_ffi::value::WidthInt { + 1u64 as calyx_ffi::value::WidthInt + } + pub fn result(&self) -> u64 { + (&self.result).try_into().expect("port value wider than 64 bits") + } + pub const fn result_bits(&self) -> &calyx_ffi::value::Value<64u64> { + &self.result + } + pub fn done(&self) -> u64 { + (&self.done).try_into().expect("port value wider than 64 bits") + } + pub const fn done_bits(&self) -> &calyx_ffi::value::Value<1u64> { + &self.done + } + pub fn set_lhs(&mut self, value: u64) { + self.lhs = calyx_ffi::value::Value::from(value); + } + pub fn set_rhs(&mut self, value: u64) { + self.rhs = calyx_ffi::value::Value::from(value); + } + pub fn set_go(&mut self, value: u64) { + self.go = calyx_ffi::value::Value::from(value); + } + pub fn set_clk(&mut self, value: u64) { + self.clk = calyx_ffi::value::Value::from(value); + } + pub fn set_reset(&mut self, value: u64) { + self.reset = calyx_ffi::value::Value::from(value); + } +} +impl std::default::Default for Subber { + fn default() -> Self { + Self { + lhs: calyx_ffi::value::Value::from(0), + rhs: calyx_ffi::value::Value::from(0), + result: calyx_ffi::value::Value::from(0), + go: calyx_ffi::value::Value::from(0), + clk: calyx_ffi::value::Value::from(0), + reset: calyx_ffi::value::Value::from(0), + done: calyx_ffi::value::Value::from(0), + user_data: unsafe { std::mem::MaybeUninit::zeroed() }, + } + } +} +impl std::clone::Clone for Subber { + fn clone(&self) -> Self { + Self { + lhs: self.lhs.clone(), + rhs: self.rhs.clone(), + result: self.result.clone(), + go: self.go.clone(), + clk: self.clk.clone(), + reset: self.reset.clone(), + done: self.done.clone(), + user_data: unsafe { + std::mem::MaybeUninit::new(self.user_data.assume_init_ref().clone()) + }, + } + } +} +impl CalyxFFIComponent for Subber { + fn path(&self) -> &'static str { + "/Users/ethan/Documents/GitHub/calyx/tools/calyx-ffi/tests/subber.futil" + } + fn name(&self) -> &'static str { + "main" + } + fn init(&mut self, context: &calyx_ir::Context) { + self.user_data + .write( + ::calyx_ffi::backend::cider::CiderFFIBackend::from(context, self.name()), + ); + } + fn reset(&mut self) { + { + ::std::io::_print( + format_args!("cider_ffi_backend reset. doesn\'t work LOL\n"), + ); + }; + } + fn can_tick(&self) -> bool { + true + } + fn tick(&mut self) { + let cider = unsafe { self.user_data.assume_init_mut() }; + cider.write_port("lhs", &self.lhs.inner); + cider.write_port("rhs", &self.rhs.inner); + cider.write_port("go", &self.go.inner); + cider.write_port("clk", &self.clk.inner); + cider.write_port("reset", &self.reset.inner); + cider.step(); + self.result.inner = cider.read_port("result"); + self.done.inner = cider.read_port("done"); + } + fn go(&mut self) { + let cider = unsafe { self.user_data.assume_init_mut() }; + cider.write_port("lhs", &self.lhs.inner); + cider.write_port("rhs", &self.rhs.inner); + cider.write_port("go", &self.go.inner); + cider.write_port("clk", &self.clk.inner); + cider.write_port("reset", &self.reset.inner); + cider.go(); + self.result.inner = cider.read_port("result"); + self.done.inner = cider.read_port("done"); + } +} +impl In2Out1 for Subber { + fn result_bits(&self) -> &calyx_ffi::value::Value<64> { + &self.result + } + fn result(&self) -> u64 { + Self::result(self) + } + fn lhs_bits(&mut self) -> &mut calyx_ffi::value::Value<64> { + &mut self.lhs + } + fn set_lhs(&mut self, value: u64) { + Self::set_lhs(self, value); + } + fn rhs_bits(&mut self) -> &mut calyx_ffi::value::Value<64> { + &mut self.rhs + } + fn set_rhs(&mut self, value: u64) { + Self::set_rhs(self, value); + } +} +#[cfg(test)] +mod tests { + use std::mem; + use super::*; + use rand::Rng; + fn fuzz_in2out1 u64>(comp: &mut I, oracle: &F) { + comp.reset(); + let mut rng = rand::thread_rng(); + for (mut x, mut y) in (0..100).map(|_| (rng.gen(), rng.gen())) { + if y > x { + mem::swap(&mut x, &mut y); + } + comp.set_lhs(x); + comp.set_rhs(y); + comp.go(); + match (&oracle(x, y), &comp.result()) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + let kind = ::core::panicking::AssertKind::Eq; + ::core::panicking::assert_failed( + kind, + &*left_val, + &*right_val, + ::core::option::Option::Some( + format_args!( + "component did not evaluate f({0}, {1}) = {2} correctly", + x, + y, + oracle(x, y), + ), + ), + ); + } + } + }; + } + } + fn test_add(adder: &mut Adder) { + fn assert_is_calyx_ffi_component() {} + assert_is_calyx_ffi_component::(); + { + ::std::io::_print(format_args!("testing adder\n")); + }; + fuzz_in2out1(adder, &(|x, y| x.wrapping_add(y))) + } + fn test_sub(subber: &mut Subber) { + fn assert_is_calyx_ffi_component() {} + assert_is_calyx_ffi_component::(); + { + ::std::io::_print(format_args!("testing subber\n")); + }; + fuzz_in2out1(subber, &(|x, y| x - y)) + } + pub(crate) mod calyx_ffi_generated_wrappers { + use super::*; + pub(crate) const CALYX_FFI_TESTS: &'static [unsafe fn(&mut CalyxFFI) -> ()] = &[ + test_add, + test_sub, + ]; + pub(crate) unsafe fn test_add(ffi: &mut CalyxFFI) { + let dut = ffi.new_comp::(); + let dut_ref = &mut *dut.borrow_mut(); + let dut_pointer = dut_ref as *mut dyn CalyxFFIComponent as *mut _ + as *mut Adder; + let dut_concrete: &mut Adder = &mut *dut_pointer; + super::test_add(dut_concrete); + } + pub(crate) unsafe fn test_sub(ffi: &mut CalyxFFI) { + let dut = ffi.new_comp::(); + let dut_ref = &mut *dut.borrow_mut(); + let dut_pointer = dut_ref as *mut dyn CalyxFFIComponent as *mut _ + as *mut Subber; + let dut_concrete: &mut Subber = &mut *dut_pointer; + super::test_sub(dut_concrete); + } + } + pub(crate) mod calyx_ffi_generated_tests { + use super::*; + extern crate test; + #[cfg(test)] + #[rustc_test_marker = "tests::calyx_ffi_generated_tests::test_add"] + pub const test_add: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("tests::calyx_ffi_generated_tests::test_add"), + ignore: false, + ignore_message: ::core::option::Option::None, + source_file: "tools/calyx-ffi/tests/arith_fuzz.rs", + start_line: 64usize, + start_col: 8usize, + end_line: 64usize, + end_col: 16usize, + compile_fail: false, + no_run: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::IntegrationTest, + }, + testfn: test::StaticTestFn( + #[coverage(off)] + || test::assert_test_result(test_add()), + ), + }; + pub(crate) fn test_add() { + let mut ffi = CalyxFFI::new(); + unsafe { + super::calyx_ffi_generated_wrappers::test_add(&mut ffi); + } + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker = "tests::calyx_ffi_generated_tests::test_sub"] + pub const test_sub: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("tests::calyx_ffi_generated_tests::test_sub"), + ignore: false, + ignore_message: ::core::option::Option::None, + source_file: "tools/calyx-ffi/tests/arith_fuzz.rs", + start_line: 70usize, + start_col: 8usize, + end_line: 70usize, + end_col: 16usize, + compile_fail: false, + no_run: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::IntegrationTest, + }, + testfn: test::StaticTestFn( + #[coverage(off)] + || test::assert_test_result(test_sub()), + ), + }; + pub(crate) fn test_sub() { + let mut ffi = CalyxFFI::new(); + unsafe { + super::calyx_ffi_generated_wrappers::test_sub(&mut ffi); + } + } + } +} +pub mod calyx_ffi_generated_top { + use super::*; + pub unsafe fn run_tests(ffi: &mut CalyxFFI) { + for test in tests::calyx_ffi_generated_wrappers::CALYX_FFI_TESTS { + test(ffi); + } + } +} +#[rustc_main] +#[coverage(off)] +pub fn main() -> () { + extern crate test; + test::test_main_static(&[&test_add, &test_sub]) +} diff --git a/tools/calyx-ffi/tests/arith_fuzz.rs b/tools/calyx-ffi/tests/arith_fuzz.rs index 9bc7cdb427..63e896bd6f 100644 --- a/tools/calyx-ffi/tests/arith_fuzz.rs +++ b/tools/calyx-ffi/tests/arith_fuzz.rs @@ -63,12 +63,12 @@ mod tests { #[calyx_ffi_test] fn test_add(adder: &mut Adder) { println!("testing adder"); - fuzz_in2out1(adder, &|x, y| x.wrapping_add(y)) + fuzz_in2out1(adder, &|x, y| x.wrapping_add(y)); } #[calyx_ffi_test] fn test_sub(subber: &mut Subber) { println!("testing subber"); - fuzz_in2out1(subber, &|x, y| x - y) + fuzz_in2out1(subber, &|x, y| x - y); } } From 99353508b1f4a924be61c746ef9a3e1a3cb94cec Mon Sep 17 00:00:00 2001 From: Ethan Uppal <113849268+ethanuppal@users.noreply.github.com> Date: Wed, 20 Nov 2024 16:08:23 -0500 Subject: [PATCH 3/6] Implement Kevin's review --- tools/calyx-ffi-macro/src/lib.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/tools/calyx-ffi-macro/src/lib.rs b/tools/calyx-ffi-macro/src/lib.rs index 6bc7206567..8cc6bffa5f 100644 --- a/tools/calyx-ffi-macro/src/lib.rs +++ b/tools/calyx-ffi-macro/src/lib.rs @@ -14,6 +14,7 @@ mod util; // this is super bad, might go out of sync with interp::WidthInt type WidthInt = u32; +/// Connects this `struct` to a calyx component in the given file. #[proc_macro_attribute] pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { let source_manifest_dir = PathBuf::from( @@ -32,14 +33,12 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { path.push(given_path); let path = path; - // let comp = calyx::parse_calyx_file(&args, path.clone()); if let Err(error) = comp { return error; } let comp = comp.unwrap(); let comp = comp.get(); - // let comp_name = syn::parse_str::(&format!("\"{}\"", comp.name)) @@ -79,18 +78,21 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { #port_name: calyx_ffi::value::Value::from(0) }); - // idk why input output ports are being flipped?? + // we need to reverse the port direction match port.borrow().direction.reverse() { calyx_ir::Direction::Input => { let setter = format_ident!("set_{}", port_name); + fields.push(quote! { pub #port_name: calyx_ffi::value::Value<#port_width> }); + setters.push(quote! { pub fn #setter(&mut self, value: u64) { self.#port_name = calyx_ffi::value::Value::from(value); } }); + input_names.push(port_name); } calyx_ir::Direction::Output => { @@ -101,15 +103,20 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { let bitvec_getter = format_ident!("{}_bits", port_name); - getters.push(quote! { - pub fn #port_name(&self) -> u64 { - (&self.#port_name).try_into().expect("port value wider than 64 bits") - } + if port_width <= 64 { + getters.push(quote! { + pub fn #port_name(&self) -> u64 { + (&self.#port_name).try_into().expect("port value wider than 64 bits") + } + }) + } + getters.push(quote! { pub const fn #bitvec_getter(&self) -> &calyx_ffi::value::Value<#port_width> { &self.#port_name } }); + output_names.push(port_name); } calyx_ir::Direction::Inout => { @@ -233,6 +240,7 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { .into() } +/// Extracts tests marked with `#[calyx_ffi_test]` and generates wrapper `#[test]`s and modules. #[derive(Default)] struct CalyxFFITestModuleVisitor { pub wrappers: Vec, @@ -247,8 +255,9 @@ impl syn::visit::Visit<'_> for CalyxFFITestModuleVisitor { .any(|attr| attr.path().is_ident("calyx_ffi_test")); if has_calyx_ffi_test { let fn_name = &i.sig.ident; - let dut_type = get_ffi_test_dut_type(i) - .expect("calyx_ffi_test should enforce this invariant"); + let dut_type = get_ffi_test_dut_type(i).expect( + "calyx_ffi_test should enforce that the type is well-formed", + ); self.wrappers.push(syn::parse_quote! { pub(crate) unsafe fn #fn_name(ffi: &mut CalyxFFI) { From 6ce0fb600f310e53630e435888b3c8a8ccf9a763 Mon Sep 17 00:00:00 2001 From: Ethan Uppal <113849268+ethanuppal@users.noreply.github.com> Date: Wed, 20 Nov 2024 16:43:47 -0500 Subject: [PATCH 4/6] Simplify PR --- tools/calyx-ffi-macro/src/lib.rs | 179 +---------- tools/calyx-ffi/src/prelude.rs | 2 +- tools/calyx-ffi/test.rs | 479 ---------------------------- tools/calyx-ffi/tests/adder.futil | 23 -- tools/calyx-ffi/tests/arith_fuzz.rs | 74 ----- tools/calyx-ffi/tests/fifo.futil | 130 -------- tools/calyx-ffi/tests/fifo.rs | 69 ---- tools/calyx-ffi/tests/stack.futil | 70 ---- tools/calyx-ffi/tests/stack.rs | 61 ---- tools/calyx-ffi/tests/subber.futil | 21 -- 10 files changed, 2 insertions(+), 1106 deletions(-) delete mode 100644 tools/calyx-ffi/test.rs delete mode 100644 tools/calyx-ffi/tests/adder.futil delete mode 100644 tools/calyx-ffi/tests/arith_fuzz.rs delete mode 100644 tools/calyx-ffi/tests/fifo.futil delete mode 100644 tools/calyx-ffi/tests/fifo.rs delete mode 100644 tools/calyx-ffi/tests/stack.futil delete mode 100644 tools/calyx-ffi/tests/stack.rs delete mode 100644 tools/calyx-ffi/tests/subber.futil diff --git a/tools/calyx-ffi-macro/src/lib.rs b/tools/calyx-ffi-macro/src/lib.rs index 8cc6bffa5f..a6329225dd 100644 --- a/tools/calyx-ffi-macro/src/lib.rs +++ b/tools/calyx-ffi-macro/src/lib.rs @@ -5,7 +5,7 @@ use std::{env, path::PathBuf}; use parse::{CalyxFFIMacroArgs, CalyxPortDeclaration}; use proc_macro::TokenStream; use quote::{format_ident, quote}; -use syn::{parse_macro_input, spanned::Spanned}; +use syn::parse_macro_input; mod calyx; mod parse; @@ -239,180 +239,3 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { } .into() } - -/// Extracts tests marked with `#[calyx_ffi_test]` and generates wrapper `#[test]`s and modules. -#[derive(Default)] -struct CalyxFFITestModuleVisitor { - pub wrappers: Vec, - pub tests: Vec, -} - -impl syn::visit::Visit<'_> for CalyxFFITestModuleVisitor { - fn visit_item_fn(&mut self, i: &syn::ItemFn) { - let has_calyx_ffi_test = i - .attrs - .iter() - .any(|attr| attr.path().is_ident("calyx_ffi_test")); - if has_calyx_ffi_test { - let fn_name = &i.sig.ident; - let dut_type = get_ffi_test_dut_type(i).expect( - "calyx_ffi_test should enforce that the type is well-formed", - ); - - self.wrappers.push(syn::parse_quote! { - pub(crate) unsafe fn #fn_name(ffi: &mut CalyxFFI) { - let dut = ffi.new_comp::<#dut_type>(); - let dut_ref = &mut *dut.borrow_mut(); - let dut_pointer = dut_ref as *mut dyn CalyxFFIComponent as *mut _ as *mut #dut_type; - let dut_concrete: &mut #dut_type = &mut *dut_pointer; - super::#fn_name(dut_concrete); - } - }); - self.tests.push(syn::parse_quote! { - #[test] - pub(crate) fn #fn_name() { - let mut ffi = CalyxFFI::new(); - unsafe { - super::calyx_ffi_generated_wrappers::#fn_name(&mut ffi); - } - } - }); - } - } -} - -#[proc_macro_attribute] -pub fn calyx_ffi_tests(args: TokenStream, item: TokenStream) -> TokenStream { - if !args.is_empty() { - return util::compile_error( - &args.into_iter().next().unwrap().span().into(), - "#[calyx_ffi_tests] takes no arguments".into(), - ); - } - - let mut module = parse_macro_input!(item as syn::ItemMod); - let module_name = &module.ident; - - let mut visitor = CalyxFFITestModuleVisitor::default(); - syn::visit::visit_item_mod(&mut visitor, &module); - let wrappers = visitor.wrappers; - let tests = visitor.tests; - - let test_names = wrappers.iter().map(|test| test.sig.ident.clone()); - let generated_wrappers = quote! { - pub(crate) mod calyx_ffi_generated_wrappers { - use super::*; - - pub(crate) const CALYX_FFI_TESTS: &'static [unsafe fn(&mut CalyxFFI) -> ()] = &[ - #(#test_names),* - ]; - - #(#wrappers)* - } - }; - let generated_wrappers_item: syn::Item = - syn::parse2(generated_wrappers).unwrap(); - - let generated_tests = quote! { - pub(crate) mod calyx_ffi_generated_tests { - use super::*; - - #(#tests)* - } - }; - let generated_tests_item: syn::Item = syn::parse2(generated_tests).unwrap(); - - let items_to_add = vec![generated_wrappers_item, generated_tests_item]; - if let Some((_, ref mut items)) = module.content { - items.extend(items_to_add); - } else { - module.content = Some((syn::token::Brace::default(), items_to_add)); - } - - quote! { - #module - - pub mod calyx_ffi_generated_top { - use super::*; - - pub unsafe fn run_tests(ffi: &mut CalyxFFI) { - for test in #module_name::calyx_ffi_generated_wrappers::CALYX_FFI_TESTS { - test(ffi); - } - } - } - } - .into() -} - -#[proc_macro_attribute] -pub fn calyx_ffi_test(args: TokenStream, item: TokenStream) -> TokenStream { - if !args.is_empty() { - return util::compile_error( - &args.into_iter().next().unwrap().span().into(), - "#[calyx_ffi_test] takes no arguments".into(), - ); - } - - let mut func = parse_macro_input!(item as syn::ItemFn); - let dut_type = get_ffi_test_dut_type(&func); - let Ok(dut_type) = dut_type else { - return dut_type.err().unwrap(); - }; - - let check_trait_impl = quote! { - { - fn assert_is_calyx_ffi_component() {} - assert_is_calyx_ffi_component::<#dut_type>(); - } - }; - - let check_trait_impl_stmts: syn::Block = syn::parse2(check_trait_impl) - .expect("Failed to parse check_trait_impl as a block"); - - let new_stmts: Vec = check_trait_impl_stmts - .stmts - .iter() - .chain(func.block.stmts.iter()) - .cloned() - .collect(); - - let new_block = syn::Block { - brace_token: func.block.brace_token, - stmts: new_stmts, - }; - func.block = Box::new(new_block); - - quote! { - #func - } - .into() -} - -fn get_ffi_test_dut_type( - func: &syn::ItemFn, -) -> Result<&syn::Type, TokenStream> { - let inputs: Vec<&syn::FnArg> = func.sig.inputs.iter().collect(); - - let bad_sig_msg = "#[calyx_ffi_test] tests must take exactly one argument, namely, a mutable reference to the DUT".into(); - - if inputs.len() != 1 { - return Err(util::compile_error(&func.span(), bad_sig_msg)); - } - let input = inputs.first().unwrap(); - - let syn::FnArg::Typed(pat_ty) = input else { - return Err(util::compile_error(&func.span(), bad_sig_msg)); - }; - - let syn::Type::Reference(syn::TypeReference { - mutability: Some(syn::token::Mut { span: _ }), - ref elem, - .. - }) = *pat_ty.ty - else { - return Err(util::compile_error(&func.span(), bad_sig_msg)); - }; - - Ok(elem) -} diff --git a/tools/calyx-ffi/src/prelude.rs b/tools/calyx-ffi/src/prelude.rs index accb64d95a..592e19026f 100644 --- a/tools/calyx-ffi/src/prelude.rs +++ b/tools/calyx-ffi/src/prelude.rs @@ -2,7 +2,7 @@ pub use super::{ interface::{CalyxFFI, CalyxFFIComponent, CalyxFFIComponentRef}, value::Value, }; -pub use calyx_ffi_macro::{calyx_ffi, calyx_ffi_test, calyx_ffi_tests}; +pub use calyx_ffi_macro::calyx_ffi; pub use calyx_ir; pub use interp; pub use paste; diff --git a/tools/calyx-ffi/test.rs b/tools/calyx-ffi/test.rs deleted file mode 100644 index 718f4c0556..0000000000 --- a/tools/calyx-ffi/test.rs +++ /dev/null @@ -1,479 +0,0 @@ -#![feature(prelude_import)] -#[prelude_import] -use std::prelude::rust_2021::*; -#[macro_use] -extern crate std; -use calyx_ffi::prelude::*; -use calyx_ffi::cider_ffi_backend; -pub trait In2Out1: CalyxFFIComponent { - fn lhs_bits(&mut self) -> &mut calyx_ffi::value::Value<64>; - fn set_lhs(&mut self, value: u64); - fn rhs_bits(&mut self) -> &mut calyx_ffi::value::Value<64>; - fn set_rhs(&mut self, value: u64); - fn result_bits(&self) -> &calyx_ffi::value::Value<64>; - fn result(&self) -> u64; -} -struct Adder { - pub lhs: calyx_ffi::value::Value<64u64>, - pub rhs: calyx_ffi::value::Value<64u64>, - result: calyx_ffi::value::Value<64u64>, - pub go: calyx_ffi::value::Value<1u64>, - pub clk: calyx_ffi::value::Value<1u64>, - pub reset: calyx_ffi::value::Value<1u64>, - done: calyx_ffi::value::Value<1u64>, - user_data: std::mem::MaybeUninit<::calyx_ffi::backend::cider::CiderFFIBackend>, -} -impl Adder { - pub const fn lhs_width() -> calyx_ffi::value::WidthInt { - 64u64 as calyx_ffi::value::WidthInt - } - pub const fn rhs_width() -> calyx_ffi::value::WidthInt { - 64u64 as calyx_ffi::value::WidthInt - } - pub const fn result_width() -> calyx_ffi::value::WidthInt { - 64u64 as calyx_ffi::value::WidthInt - } - pub const fn go_width() -> calyx_ffi::value::WidthInt { - 1u64 as calyx_ffi::value::WidthInt - } - pub const fn clk_width() -> calyx_ffi::value::WidthInt { - 1u64 as calyx_ffi::value::WidthInt - } - pub const fn reset_width() -> calyx_ffi::value::WidthInt { - 1u64 as calyx_ffi::value::WidthInt - } - pub const fn done_width() -> calyx_ffi::value::WidthInt { - 1u64 as calyx_ffi::value::WidthInt - } - pub fn result(&self) -> u64 { - (&self.result).try_into().expect("port value wider than 64 bits") - } - pub const fn result_bits(&self) -> &calyx_ffi::value::Value<64u64> { - &self.result - } - pub fn done(&self) -> u64 { - (&self.done).try_into().expect("port value wider than 64 bits") - } - pub const fn done_bits(&self) -> &calyx_ffi::value::Value<1u64> { - &self.done - } - pub fn set_lhs(&mut self, value: u64) { - self.lhs = calyx_ffi::value::Value::from(value); - } - pub fn set_rhs(&mut self, value: u64) { - self.rhs = calyx_ffi::value::Value::from(value); - } - pub fn set_go(&mut self, value: u64) { - self.go = calyx_ffi::value::Value::from(value); - } - pub fn set_clk(&mut self, value: u64) { - self.clk = calyx_ffi::value::Value::from(value); - } - pub fn set_reset(&mut self, value: u64) { - self.reset = calyx_ffi::value::Value::from(value); - } -} -impl std::default::Default for Adder { - fn default() -> Self { - Self { - lhs: calyx_ffi::value::Value::from(0), - rhs: calyx_ffi::value::Value::from(0), - result: calyx_ffi::value::Value::from(0), - go: calyx_ffi::value::Value::from(0), - clk: calyx_ffi::value::Value::from(0), - reset: calyx_ffi::value::Value::from(0), - done: calyx_ffi::value::Value::from(0), - user_data: unsafe { std::mem::MaybeUninit::zeroed() }, - } - } -} -impl std::clone::Clone for Adder { - fn clone(&self) -> Self { - Self { - lhs: self.lhs.clone(), - rhs: self.rhs.clone(), - result: self.result.clone(), - go: self.go.clone(), - clk: self.clk.clone(), - reset: self.reset.clone(), - done: self.done.clone(), - user_data: unsafe { - std::mem::MaybeUninit::new(self.user_data.assume_init_ref().clone()) - }, - } - } -} -impl CalyxFFIComponent for Adder { - fn path(&self) -> &'static str { - "/Users/ethan/Documents/GitHub/calyx/tools/calyx-ffi/tests/adder.futil" - } - fn name(&self) -> &'static str { - "main" - } - fn init(&mut self, context: &calyx_ir::Context) { - self.user_data - .write( - ::calyx_ffi::backend::cider::CiderFFIBackend::from(context, self.name()), - ); - } - fn reset(&mut self) { - { - ::std::io::_print( - format_args!("cider_ffi_backend reset. doesn\'t work LOL\n"), - ); - }; - } - fn can_tick(&self) -> bool { - true - } - fn tick(&mut self) { - let cider = unsafe { self.user_data.assume_init_mut() }; - cider.write_port("lhs", &self.lhs.inner); - cider.write_port("rhs", &self.rhs.inner); - cider.write_port("go", &self.go.inner); - cider.write_port("clk", &self.clk.inner); - cider.write_port("reset", &self.reset.inner); - cider.step(); - self.result.inner = cider.read_port("result"); - self.done.inner = cider.read_port("done"); - } - fn go(&mut self) { - let cider = unsafe { self.user_data.assume_init_mut() }; - cider.write_port("lhs", &self.lhs.inner); - cider.write_port("rhs", &self.rhs.inner); - cider.write_port("go", &self.go.inner); - cider.write_port("clk", &self.clk.inner); - cider.write_port("reset", &self.reset.inner); - cider.go(); - self.result.inner = cider.read_port("result"); - self.done.inner = cider.read_port("done"); - } -} -impl In2Out1 for Adder { - fn result_bits(&self) -> &calyx_ffi::value::Value<64> { - &self.result - } - fn result(&self) -> u64 { - Self::result(self) - } - fn lhs_bits(&mut self) -> &mut calyx_ffi::value::Value<64> { - &mut self.lhs - } - fn set_lhs(&mut self, value: u64) { - Self::set_lhs(self, value); - } - fn rhs_bits(&mut self) -> &mut calyx_ffi::value::Value<64> { - &mut self.rhs - } - fn set_rhs(&mut self, value: u64) { - Self::set_rhs(self, value); - } -} -struct Subber { - pub lhs: calyx_ffi::value::Value<64u64>, - pub rhs: calyx_ffi::value::Value<64u64>, - result: calyx_ffi::value::Value<64u64>, - pub go: calyx_ffi::value::Value<1u64>, - pub clk: calyx_ffi::value::Value<1u64>, - pub reset: calyx_ffi::value::Value<1u64>, - done: calyx_ffi::value::Value<1u64>, - user_data: std::mem::MaybeUninit<::calyx_ffi::backend::cider::CiderFFIBackend>, -} -impl Subber { - pub const fn lhs_width() -> calyx_ffi::value::WidthInt { - 64u64 as calyx_ffi::value::WidthInt - } - pub const fn rhs_width() -> calyx_ffi::value::WidthInt { - 64u64 as calyx_ffi::value::WidthInt - } - pub const fn result_width() -> calyx_ffi::value::WidthInt { - 64u64 as calyx_ffi::value::WidthInt - } - pub const fn go_width() -> calyx_ffi::value::WidthInt { - 1u64 as calyx_ffi::value::WidthInt - } - pub const fn clk_width() -> calyx_ffi::value::WidthInt { - 1u64 as calyx_ffi::value::WidthInt - } - pub const fn reset_width() -> calyx_ffi::value::WidthInt { - 1u64 as calyx_ffi::value::WidthInt - } - pub const fn done_width() -> calyx_ffi::value::WidthInt { - 1u64 as calyx_ffi::value::WidthInt - } - pub fn result(&self) -> u64 { - (&self.result).try_into().expect("port value wider than 64 bits") - } - pub const fn result_bits(&self) -> &calyx_ffi::value::Value<64u64> { - &self.result - } - pub fn done(&self) -> u64 { - (&self.done).try_into().expect("port value wider than 64 bits") - } - pub const fn done_bits(&self) -> &calyx_ffi::value::Value<1u64> { - &self.done - } - pub fn set_lhs(&mut self, value: u64) { - self.lhs = calyx_ffi::value::Value::from(value); - } - pub fn set_rhs(&mut self, value: u64) { - self.rhs = calyx_ffi::value::Value::from(value); - } - pub fn set_go(&mut self, value: u64) { - self.go = calyx_ffi::value::Value::from(value); - } - pub fn set_clk(&mut self, value: u64) { - self.clk = calyx_ffi::value::Value::from(value); - } - pub fn set_reset(&mut self, value: u64) { - self.reset = calyx_ffi::value::Value::from(value); - } -} -impl std::default::Default for Subber { - fn default() -> Self { - Self { - lhs: calyx_ffi::value::Value::from(0), - rhs: calyx_ffi::value::Value::from(0), - result: calyx_ffi::value::Value::from(0), - go: calyx_ffi::value::Value::from(0), - clk: calyx_ffi::value::Value::from(0), - reset: calyx_ffi::value::Value::from(0), - done: calyx_ffi::value::Value::from(0), - user_data: unsafe { std::mem::MaybeUninit::zeroed() }, - } - } -} -impl std::clone::Clone for Subber { - fn clone(&self) -> Self { - Self { - lhs: self.lhs.clone(), - rhs: self.rhs.clone(), - result: self.result.clone(), - go: self.go.clone(), - clk: self.clk.clone(), - reset: self.reset.clone(), - done: self.done.clone(), - user_data: unsafe { - std::mem::MaybeUninit::new(self.user_data.assume_init_ref().clone()) - }, - } - } -} -impl CalyxFFIComponent for Subber { - fn path(&self) -> &'static str { - "/Users/ethan/Documents/GitHub/calyx/tools/calyx-ffi/tests/subber.futil" - } - fn name(&self) -> &'static str { - "main" - } - fn init(&mut self, context: &calyx_ir::Context) { - self.user_data - .write( - ::calyx_ffi::backend::cider::CiderFFIBackend::from(context, self.name()), - ); - } - fn reset(&mut self) { - { - ::std::io::_print( - format_args!("cider_ffi_backend reset. doesn\'t work LOL\n"), - ); - }; - } - fn can_tick(&self) -> bool { - true - } - fn tick(&mut self) { - let cider = unsafe { self.user_data.assume_init_mut() }; - cider.write_port("lhs", &self.lhs.inner); - cider.write_port("rhs", &self.rhs.inner); - cider.write_port("go", &self.go.inner); - cider.write_port("clk", &self.clk.inner); - cider.write_port("reset", &self.reset.inner); - cider.step(); - self.result.inner = cider.read_port("result"); - self.done.inner = cider.read_port("done"); - } - fn go(&mut self) { - let cider = unsafe { self.user_data.assume_init_mut() }; - cider.write_port("lhs", &self.lhs.inner); - cider.write_port("rhs", &self.rhs.inner); - cider.write_port("go", &self.go.inner); - cider.write_port("clk", &self.clk.inner); - cider.write_port("reset", &self.reset.inner); - cider.go(); - self.result.inner = cider.read_port("result"); - self.done.inner = cider.read_port("done"); - } -} -impl In2Out1 for Subber { - fn result_bits(&self) -> &calyx_ffi::value::Value<64> { - &self.result - } - fn result(&self) -> u64 { - Self::result(self) - } - fn lhs_bits(&mut self) -> &mut calyx_ffi::value::Value<64> { - &mut self.lhs - } - fn set_lhs(&mut self, value: u64) { - Self::set_lhs(self, value); - } - fn rhs_bits(&mut self) -> &mut calyx_ffi::value::Value<64> { - &mut self.rhs - } - fn set_rhs(&mut self, value: u64) { - Self::set_rhs(self, value); - } -} -#[cfg(test)] -mod tests { - use std::mem; - use super::*; - use rand::Rng; - fn fuzz_in2out1 u64>(comp: &mut I, oracle: &F) { - comp.reset(); - let mut rng = rand::thread_rng(); - for (mut x, mut y) in (0..100).map(|_| (rng.gen(), rng.gen())) { - if y > x { - mem::swap(&mut x, &mut y); - } - comp.set_lhs(x); - comp.set_rhs(y); - comp.go(); - match (&oracle(x, y), &comp.result()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - let kind = ::core::panicking::AssertKind::Eq; - ::core::panicking::assert_failed( - kind, - &*left_val, - &*right_val, - ::core::option::Option::Some( - format_args!( - "component did not evaluate f({0}, {1}) = {2} correctly", - x, - y, - oracle(x, y), - ), - ), - ); - } - } - }; - } - } - fn test_add(adder: &mut Adder) { - fn assert_is_calyx_ffi_component() {} - assert_is_calyx_ffi_component::(); - { - ::std::io::_print(format_args!("testing adder\n")); - }; - fuzz_in2out1(adder, &(|x, y| x.wrapping_add(y))) - } - fn test_sub(subber: &mut Subber) { - fn assert_is_calyx_ffi_component() {} - assert_is_calyx_ffi_component::(); - { - ::std::io::_print(format_args!("testing subber\n")); - }; - fuzz_in2out1(subber, &(|x, y| x - y)) - } - pub(crate) mod calyx_ffi_generated_wrappers { - use super::*; - pub(crate) const CALYX_FFI_TESTS: &'static [unsafe fn(&mut CalyxFFI) -> ()] = &[ - test_add, - test_sub, - ]; - pub(crate) unsafe fn test_add(ffi: &mut CalyxFFI) { - let dut = ffi.new_comp::(); - let dut_ref = &mut *dut.borrow_mut(); - let dut_pointer = dut_ref as *mut dyn CalyxFFIComponent as *mut _ - as *mut Adder; - let dut_concrete: &mut Adder = &mut *dut_pointer; - super::test_add(dut_concrete); - } - pub(crate) unsafe fn test_sub(ffi: &mut CalyxFFI) { - let dut = ffi.new_comp::(); - let dut_ref = &mut *dut.borrow_mut(); - let dut_pointer = dut_ref as *mut dyn CalyxFFIComponent as *mut _ - as *mut Subber; - let dut_concrete: &mut Subber = &mut *dut_pointer; - super::test_sub(dut_concrete); - } - } - pub(crate) mod calyx_ffi_generated_tests { - use super::*; - extern crate test; - #[cfg(test)] - #[rustc_test_marker = "tests::calyx_ffi_generated_tests::test_add"] - pub const test_add: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("tests::calyx_ffi_generated_tests::test_add"), - ignore: false, - ignore_message: ::core::option::Option::None, - source_file: "tools/calyx-ffi/tests/arith_fuzz.rs", - start_line: 64usize, - start_col: 8usize, - end_line: 64usize, - end_col: 16usize, - compile_fail: false, - no_run: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::IntegrationTest, - }, - testfn: test::StaticTestFn( - #[coverage(off)] - || test::assert_test_result(test_add()), - ), - }; - pub(crate) fn test_add() { - let mut ffi = CalyxFFI::new(); - unsafe { - super::calyx_ffi_generated_wrappers::test_add(&mut ffi); - } - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker = "tests::calyx_ffi_generated_tests::test_sub"] - pub const test_sub: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("tests::calyx_ffi_generated_tests::test_sub"), - ignore: false, - ignore_message: ::core::option::Option::None, - source_file: "tools/calyx-ffi/tests/arith_fuzz.rs", - start_line: 70usize, - start_col: 8usize, - end_line: 70usize, - end_col: 16usize, - compile_fail: false, - no_run: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::IntegrationTest, - }, - testfn: test::StaticTestFn( - #[coverage(off)] - || test::assert_test_result(test_sub()), - ), - }; - pub(crate) fn test_sub() { - let mut ffi = CalyxFFI::new(); - unsafe { - super::calyx_ffi_generated_wrappers::test_sub(&mut ffi); - } - } - } -} -pub mod calyx_ffi_generated_top { - use super::*; - pub unsafe fn run_tests(ffi: &mut CalyxFFI) { - for test in tests::calyx_ffi_generated_wrappers::CALYX_FFI_TESTS { - test(ffi); - } - } -} -#[rustc_main] -#[coverage(off)] -pub fn main() -> () { - extern crate test; - test::test_main_static(&[&test_add, &test_sub]) -} diff --git a/tools/calyx-ffi/tests/adder.futil b/tools/calyx-ffi/tests/adder.futil deleted file mode 100644 index 1730a7c5fd..0000000000 --- a/tools/calyx-ffi/tests/adder.futil +++ /dev/null @@ -1,23 +0,0 @@ -import "primitives/core.futil"; - -component main(lhs: 64, rhs: 64) -> (result: 64) { - cells { - adder = std_add(64); - temp = std_reg(64); - } - wires { - group add { - adder.left = lhs; - adder.right = rhs; - temp.in = adder.out; - temp.write_en = 1'b1; - add[done] = temp.done; - } - result = temp.out; - } - control { - add; - } -} - - diff --git a/tools/calyx-ffi/tests/arith_fuzz.rs b/tools/calyx-ffi/tests/arith_fuzz.rs deleted file mode 100644 index 63e896bd6f..0000000000 --- a/tools/calyx-ffi/tests/arith_fuzz.rs +++ /dev/null @@ -1,74 +0,0 @@ -use calyx_ffi::prelude::*; - -use calyx_ffi::cider_ffi_backend; - -// not necessary, just to show it off -calyx_ffi::declare_interface! { - In2Out1(lhs: 64, rhs: 64) -> (result: 64) -} - -#[calyx_ffi( - src = "tests/adder.futil", - comp = "main", - backend = cider_ffi_backend, - derive = [ - In2Out1(lhs: 64, rhs: 64) -> (result: 64) - ] -)] -struct Adder; - -#[calyx_ffi( - src = "tests/subber.futil", - comp = "main", - backend = cider_ffi_backend, - derive = [ - In2Out1(lhs: 64, rhs: 64) -> (result: 64) - ] -)] -struct Subber; - -#[cfg(test)] -#[calyx_ffi_tests] -mod tests { - use std::mem; - - use super::*; - use rand::Rng; - - // inv: the left argument will always be greater than the right - fn fuzz_in2out1 u64>( - comp: &mut I, - oracle: &F, - ) { - comp.reset(); - let mut rng = rand::thread_rng(); - for (mut x, mut y) in (0..100).map(|_| (rng.gen(), rng.gen())) { - if y > x { - mem::swap(&mut x, &mut y); - } - comp.set_lhs(x); - comp.set_rhs(y); - comp.go(); - assert_eq!( - oracle(x, y), - comp.result(), - "component did not evaluate f({}, {}) = {} correctly", - x, - y, - oracle(x, y) - ); - } - } - - #[calyx_ffi_test] - fn test_add(adder: &mut Adder) { - println!("testing adder"); - fuzz_in2out1(adder, &|x, y| x.wrapping_add(y)); - } - - #[calyx_ffi_test] - fn test_sub(subber: &mut Subber) { - println!("testing subber"); - fuzz_in2out1(subber, &|x, y| x - y); - } -} diff --git a/tools/calyx-ffi/tests/fifo.futil b/tools/calyx-ffi/tests/fifo.futil deleted file mode 100644 index 6bc65ba106..0000000000 --- a/tools/calyx-ffi/tests/fifo.futil +++ /dev/null @@ -1,130 +0,0 @@ -import "primitives/core.futil"; -import "primitives/memories/seq.futil"; -import "primitives/binary_operators.futil"; -component fifo(cmd: 1, value: 32) -> () { - cells { - mem = seq_mem_d1(32, 16, 4); - reg_1 = std_reg(4); - reg_2 = std_reg(4); - ref ans = std_reg(32); - ref err = std_reg(1); - reg_3 = std_reg(5); - eq_4 = std_eq(5); - reg_2_incr_1_5 = std_add(4); - reg_3_decr_1_6 = std_sub(5); - eq_7 = std_eq(5); - reg_1_incr_1_8 = std_add(4); - reg_3_incr_1_9 = std_add(5); - cmd_eq_0_10 = std_eq(1); - cmd_eq_1_11 = std_eq(1); - } - wires { - group raise_err { - err.in = 1'd1; - err.write_en = 1'd1; - raise_err[done] = err.done; - } - comb group eq_4_group { - eq_4.left = reg_3.out; - eq_4.right = 5'd0; - } - group read_payload_from_mem_pop { - mem.addr0 = reg_2.out; - mem.content_en = 1'd1; - ans.write_en = mem.done ? 1'd1; - ans.in = mem.done ? mem.read_data; - read_payload_from_mem_pop[done] = ans.done; - } - group reg_2_incr_1_5_group { - reg_2_incr_1_5.left = reg_2.out; - reg_2_incr_1_5.right = 4'd1; - reg_2.write_en = 1'd1; - reg_2.in = reg_2_incr_1_5.out; - reg_2_incr_1_5_group[done] = reg_2.done; - } - group reg_3_decr_1_6_group { - reg_3_decr_1_6.left = reg_3.out; - reg_3_decr_1_6.right = 5'd1; - reg_3.write_en = 1'd1; - reg_3.in = reg_3_decr_1_6.out; - reg_3_decr_1_6_group[done] = reg_3.done; - } - comb group eq_7_group { - eq_7.left = reg_3.out; - eq_7.right = 5'd16; - } - group write_payload_to_mem { - mem.addr0 = reg_1.out; - mem.write_en = 1'd1; - mem.write_data = value; - write_payload_to_mem[done] = mem.done; - mem.content_en = 1'd1; - } - group reg_1_incr_1_8_group { - reg_1_incr_1_8.left = reg_1.out; - reg_1_incr_1_8.right = 4'd1; - reg_1.write_en = 1'd1; - reg_1.in = reg_1_incr_1_8.out; - reg_1_incr_1_8_group[done] = reg_1.done; - } - group reg_3_incr_1_9_group { - reg_3_incr_1_9.left = reg_3.out; - reg_3_incr_1_9.right = 5'd1; - reg_3.write_en = 1'd1; - reg_3.in = reg_3_incr_1_9.out; - reg_3_incr_1_9_group[done] = reg_3.done; - } - cmd_eq_0_10.left = cmd; - cmd_eq_0_10.right = 1'd0; - cmd_eq_1_11.left = cmd; - cmd_eq_1_11.right = 1'd1; - } - control { - par { - if cmd_eq_0_10.out { - if eq_4.out with eq_4_group { - raise_err; - } else { - seq { - read_payload_from_mem_pop; - reg_2_incr_1_5_group; - reg_3_decr_1_6_group; - } - } - } - if cmd_eq_1_11.out { - if eq_7.out with eq_7_group { - raise_err; - } else { - seq { - write_payload_to_mem; - reg_1_incr_1_8_group; - reg_3_incr_1_9_group; - } - } - } - } - } -} -component main(cmd: 1, value: 32) -> (ans: 32, err: 1) { - cells { - ans_reg = std_reg(32); - err_reg = std_reg(1); - queue = fifo(); - } - wires { - ans = ans_reg.out; - err = err_reg.out; - group dummy { - ans_reg.in = ans_reg.out; - ans_reg.write_en = 1'b1; - dummy[done] = ans_reg.done; - } - } - control { - seq { - invoke queue[ans = ans_reg, err = err_reg](cmd = cmd, value = value)(); - dummy; - } - } -} diff --git a/tools/calyx-ffi/tests/fifo.rs b/tools/calyx-ffi/tests/fifo.rs deleted file mode 100644 index f1199f5406..0000000000 --- a/tools/calyx-ffi/tests/fifo.rs +++ /dev/null @@ -1,69 +0,0 @@ -use calyx_ffi::cider_ffi_backend; -use calyx_ffi::prelude::*; - -enum QueueCommand { - Pop = 0, - Push = 1, -} - -#[derive(PartialEq, Eq, Debug)] -enum QueueStatus { - Ok = 0, - Err = 1, -} - -calyx_ffi::declare_interface! { - Queue(cmd: 1, value: 32) -> (ans: 32, err: 1) impl { - fn status(&self) -> QueueStatus { - if self.err() == 0 { QueueStatus::Ok } else { QueueStatus::Err } - } - } mut impl { - fn assert_no_error(&mut self) { - assert_eq!(QueueStatus::Ok, self.status(), "queue underflowed or overflowed"); - } - - fn push(&mut self, value: u32) { - self.reset(); - self.set_cmd(QueueCommand::Push as u64); - self.set_value(value as u64); - self.go(); - self.assert_no_error(); - } - - fn pop(&mut self) -> u32 { - self.reset(); - self.set_cmd(QueueCommand::Pop as u64); - self.go(); - self.assert_no_error(); - self.ans() as u32 - } - } -} - -#[calyx_ffi( - src = "tests/fifo.futil", - comp = "main", - backend = cider_ffi_backend, - derive = [ - Queue(cmd: 1, value: 32) -> (ans: 32, err: 1) - ] -)] -struct Fifo; - -#[cfg(test)] -#[calyx_ffi_tests] -mod tests { - use super::*; - - #[calyx_ffi_test] - fn test_fifo(fifo: &mut Fifo) { - println!("testing fifo"); - - fifo.push(1); - fifo.push(2); - assert_eq!(1, fifo.pop()); - fifo.push(3); - assert_eq!(2, fifo.pop()); - assert_eq!(3, fifo.pop()); - } -} diff --git a/tools/calyx-ffi/tests/stack.futil b/tools/calyx-ffi/tests/stack.futil deleted file mode 100644 index 11575c4c0c..0000000000 --- a/tools/calyx-ffi/tests/stack.futil +++ /dev/null @@ -1,70 +0,0 @@ -import "primitives/core.futil"; -import "primitives/memories/seq.futil"; -import "primitives/binary_operators.futil"; - -component main(cmd: 1, value: 32) -> (out: 32, length: 4) { - cells { - store = seq_mem_d1(32, 16, 4); - next = std_reg( 4); - incr = std_add( 4); - decr = std_sub( 4); - last = std_reg(32); - test = std_eq(1); - } - wires { - out = last.out; - length = next.out; - - comb group check_cmd { - test.left = cmd; - test.right = 1'b0; - } - - group write_at_next { - store.addr0 = next.out; - store.write_data = value; - store.write_en = 1'b1; - store.content_en = 1'b1; - write_at_next[done] = store.done; - } - group read_from_next { - store.addr0 = next.out; - store.content_en = 1'b1; - last.in = store.read_data; - last.write_en = store.done; - read_from_next[done] = last.done; - } - group increment_next { - incr.left = next.out; - incr.right = 4'd1; - next.in = incr.out; - next.write_en = 1'b1; - increment_next[done] = next.done; - } - group decrement_next { - decr.left = next.out; - decr.right = 4'd1; - next.in = decr.out; - next.write_en = 1'b1; - decrement_next[done] = next.done; - } - } - control { - // if-else is buggy in cider2 - par { - if test.out with check_cmd { - seq { - write_at_next; - increment_next; - } - } - if cmd { - seq { - decrement_next; - read_from_next; - } - } - } - } -} - diff --git a/tools/calyx-ffi/tests/stack.rs b/tools/calyx-ffi/tests/stack.rs deleted file mode 100644 index 8e5b0d60a8..0000000000 --- a/tools/calyx-ffi/tests/stack.rs +++ /dev/null @@ -1,61 +0,0 @@ -use calyx_ffi::cider_ffi_backend; -use calyx_ffi::prelude::*; - -enum StackCommand { - Push = 0, - Pop = 1, -} - -const STACK_CAPACITY: u64 = 16; - -calyx_ffi::declare_interface! { - Stack(cmd: 1, value: 32) -> (out: 32, length: 4) mut impl { - fn push(&mut self, value: u32,) { - assert!(self.length() < STACK_CAPACITY, "tried to push when length={}", STACK_CAPACITY); - println!("stack has length {} before push", self.length()); - let old_length = self.length(); - self.set_cmd(StackCommand::Push as u64); - self.set_value(value as u64); - self.go(); - assert_eq!(old_length + 1, self.length(), "stack length should increase by 1 on push"); - } - - fn pop(&mut self) -> u32 { - assert!(self.length() > 0, "tried to pop when stack empty"); - println!("stack has length {} before pop", self.length()); - let old_length = self.length(); - self.set_cmd(StackCommand::Pop as u64); - self.go(); - assert_eq!(old_length - 1, self.length(), "stack length should decrease by 1 on pop"); - self.out() as u32 - } - } -} - -#[calyx_ffi( - src = "tests/stack.futil", - comp = "main", - backend = cider_ffi_backend, - derive = [ - Stack(cmd: 1, value: 32) -> (out: 32, length: 4) - ] -)] -struct ReallyBadStack; - -#[cfg(test)] -#[calyx_ffi_tests] -mod tests { - use super::*; - - #[calyx_ffi_test] - fn test_stack(stack: &mut ReallyBadStack) { - println!("testing stack"); - - stack.push(1); - stack.push(2); - assert_eq!(2, stack.pop()); - stack.push(3); - assert_eq!(3, stack.pop()); - assert_eq!(1, stack.pop()); - } -} diff --git a/tools/calyx-ffi/tests/subber.futil b/tools/calyx-ffi/tests/subber.futil deleted file mode 100644 index 260456f938..0000000000 --- a/tools/calyx-ffi/tests/subber.futil +++ /dev/null @@ -1,21 +0,0 @@ -import "primitives/core.futil"; - -component main(lhs: 64, rhs: 64) -> (result: 64) { - cells { - subber = std_sub(64); - temp = std_reg(64); - } - wires { - group sub { - subber.left = lhs; - subber.right = rhs; - temp.in = subber.out; - temp.write_en = 1'b1; - sub[done] = temp.done; - } - result = temp.out; - } - control { - sub; - } -} From cedaf993fcc138c58a1fa5f8cd3e686a359dcd5a Mon Sep 17 00:00:00 2001 From: Ethan Uppal <113849268+ethanuppal@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:29:13 -0500 Subject: [PATCH 5/6] Implement Kevin's second review --- Cargo.lock | 1 + tools/calyx-ffi-macro/Cargo.toml | 2 +- tools/calyx-ffi-macro/src/calyx.rs | 2 +- tools/calyx-ffi-macro/src/lib.rs | 5 +---- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 70c55dcc13..7572443f1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -354,6 +354,7 @@ dependencies = [ "calyx-frontend", "calyx-ir", "calyx-utils", + "interp", "proc-macro2", "quote", "syn 2.0.87", diff --git a/tools/calyx-ffi-macro/Cargo.toml b/tools/calyx-ffi-macro/Cargo.toml index e9d1eddc15..88d8b42af0 100644 --- a/tools/calyx-ffi-macro/Cargo.toml +++ b/tools/calyx-ffi-macro/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true proc-macro2 = "1.0.86" quote = "1.0.36" syn = { version = "2.0.69", features = ["full", "visit"] } +interp = { path = "../../interp" } calyx-utils.workspace = true calyx-frontend.workspace = true calyx-ir.workspace = true -# bigint = "4.4.3" diff --git a/tools/calyx-ffi-macro/src/calyx.rs b/tools/calyx-ffi-macro/src/calyx.rs index 4039321976..73490bfd23 100644 --- a/tools/calyx-ffi-macro/src/calyx.rs +++ b/tools/calyx-ffi-macro/src/calyx.rs @@ -19,7 +19,7 @@ pub fn parse_calyx_file( args: &CalyxFFIMacroArgs, file: PathBuf, ) -> Result { - // there has to be a better way to find lib + // TODO(ethan): there has to be a better way to find lib let home_dir = env::var("HOME").expect("user home not set"); let mut lib_path = PathBuf::from(home_dir); lib_path.push(".calyx"); diff --git a/tools/calyx-ffi-macro/src/lib.rs b/tools/calyx-ffi-macro/src/lib.rs index a6329225dd..ac7a0bb027 100644 --- a/tools/calyx-ffi-macro/src/lib.rs +++ b/tools/calyx-ffi-macro/src/lib.rs @@ -11,9 +11,6 @@ mod calyx; mod parse; mod util; -// this is super bad, might go out of sync with interp::WidthInt -type WidthInt = u32; - /// Connects this `struct` to a calyx component in the given file. #[proc_macro_attribute] pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { @@ -66,7 +63,7 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { port_names.push(port_name.clone()); - let port_width = port.borrow().width as WidthInt; + let port_width = port.borrow().width as interp::WidthInt; let width_getter = format_ident!("{}_width", port_name); width_getters.push(quote! { pub const fn #width_getter() -> calyx_ffi::value::WidthInt { From 2a152d58ee8e4f88ee441d7f504dec27d5a321cc Mon Sep 17 00:00:00 2001 From: Ethan Uppal <113849268+ethanuppal@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:41:51 -0500 Subject: [PATCH 6/6] Use --- tools/calyx-ffi-macro/src/calyx.rs | 3 +-- tools/calyx-ffi-macro/src/lib.rs | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/calyx-ffi-macro/src/calyx.rs b/tools/calyx-ffi-macro/src/calyx.rs index 73490bfd23..6f15bd6b79 100644 --- a/tools/calyx-ffi-macro/src/calyx.rs +++ b/tools/calyx-ffi-macro/src/calyx.rs @@ -21,8 +21,7 @@ pub fn parse_calyx_file( ) -> Result { // TODO(ethan): there has to be a better way to find lib let home_dir = env::var("HOME").expect("user home not set"); - let mut lib_path = PathBuf::from(home_dir); - lib_path.push(".calyx"); + let lib_path = PathBuf::from(home_dir).join(".calyx"); let ws = calyx_frontend::Workspace::construct(&Some(file.clone()), &lib_path) .map_err(|err| { diff --git a/tools/calyx-ffi-macro/src/lib.rs b/tools/calyx-ffi-macro/src/lib.rs index ac7a0bb027..b5603fa780 100644 --- a/tools/calyx-ffi-macro/src/lib.rs +++ b/tools/calyx-ffi-macro/src/lib.rs @@ -26,9 +26,7 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream { let name = item_struct.ident; let given_path = args.src.to_string_lossy().to_string(); - let mut path = source_manifest_dir; - path.push(given_path); - let path = path; + let path = source_manifest_dir.join(given_path); let comp = calyx::parse_calyx_file(&args, path.clone()); if let Err(error) = comp {