diff --git a/tools/calyx-ffi-macro/src/lib.rs b/tools/calyx-ffi-macro/src/lib.rs index 8cc6bffa5..a6329225d 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 accb64d95..592e19026 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 718f4c055..000000000 --- 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 1730a7c5f..000000000 --- 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 63e896bd6..000000000 --- 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 6bc65ba10..000000000 --- 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 f1199f540..000000000 --- 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 11575c4c0..000000000 --- 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 8e5b0d60a..000000000 --- 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 260456f93..000000000 --- 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; - } -}