Skip to content

Commit

Permalink
Continue work on testbench; cider2 stubs in place
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanuppal committed Jul 30, 2024
1 parent 91abfd2 commit 0f3fc81
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 93 deletions.
11 changes: 7 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 29 additions & 15 deletions tools/calyx-ffi-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream {
let args = parse_macro_input!(attrs as CalyxFFIMacroArgs);
let item_struct = parse_macro_input!(item as syn::ItemStruct);
let name = item_struct.ident;
let path = args.src.to_string_lossy().to_string();

// <sorry>
let comp = calyx::parse_calyx_file(&args);
Expand All @@ -22,11 +23,11 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream {
let comp = comp.get();
// </sorry>

let comp_name = syn::parse_str::<syn::LitStr>(&format!(
"\"{}\"",
comp.name.to_string()
))
.expect("failed to turn quoted name into string");
let comp_name =
syn::parse_str::<syn::LitStr>(&format!("\"{}\"", comp.name))
.expect("failed to turn quoted name into string");
let comp_path = syn::parse_str::<syn::LitStr>(&format!("\"{}\"", path))
.expect("failed to turn quoted path into string");

let backend_macro = args.backend;
let mut field_names = vec![];
Expand Down Expand Up @@ -65,7 +66,8 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream {

let struct_def = quote! {
struct #name {
#(#fields),*
#(#fields,)*
user_data: std::mem::MaybeUninit<#backend_macro!(@user_data_type)>
}
};

Expand All @@ -74,35 +76,47 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream {
#(#getters)*
}

impl std::default::Default for #name {
fn default() -> Self {
Self {
#(#field_names: std::default::Default::default(),)*
user_data: unsafe { std::mem::MaybeUninit::zeroed() }
}
}
}

impl CalyxFFIComponent for #name {
fn path(&self) -> &'static str {
#comp_path
}

fn name(&self) -> &'static str {
#comp_name
}

fn init(&mut self) {
#backend_macro!(init self; #(#field_names),*);
fn init(&mut self, context: &calyx_ir::Context) {
#backend_macro!(@init self, context; #(#field_names),*);
}

fn deinit(&mut self) {
#backend_macro!(deinit self; #(#field_names),*);
fn reset(&mut self) {
#backend_macro!(@reset self; #(#field_names),*);
}

fn reset(&mut self) {
#backend_macro!(reset self; #(#field_names),*);
fn can_tick(&self) -> bool {
#backend_macro!(@can_tick self; #(#field_names),*)
}

fn tick(&mut self) {
#backend_macro!(tick self; #(#field_names),*);
#backend_macro!(@tick self; #(#field_names),*);
}

fn go(&mut self) {
#backend_macro!(go self; #(#field_names),*);
#backend_macro!(@go self; #(#field_names),*);
}
}
};

quote! {
#[derive(Default)]
#struct_def
#impl_block
}
Expand Down
3 changes: 3 additions & 0 deletions tools/calyx-ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ rust-version.workspace = true

[dependencies]
calyx-ffi-macro = { path = "../calyx-ffi-macro" }
calyx-frontend.workspace = true
calyx-ir.workspace = true
interp = { path = "../../interp" }
34 changes: 2 additions & 32 deletions tools/calyx-ffi/src/backend.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,2 @@
/// Example FFI backend.
#[macro_export]
macro_rules! useless_ffi_backend {
(init $dut:ident; $($port:ident),*) => {
println!("useless_ffi_backend init");
};
(deinit $dut:ident; $($port:ident),*) => {
println!("useless_ffi_backend deinit");
};
(reset $dut:ident; $($port:ident),*) => {
println!("useless_ffi_backend reset");
$dut.done = 0;
$dut.reset = 1;
for i in 0..5 {
$dut.tick();
}
$dut.reset = 0;
};
(tick $dut:ident; $($port:ident),*) => {
println!("useless_ffi_backend tick");
if $dut.done == 1 {
$dut.done = 0;
}
};
(go $dut:ident; $($port:ident),*) => {
println!("useless_ffi_backend go");
$dut.go = 1;
$dut.go = 0;
$dut.done = 1;
$dut.tick();
};
}
pub mod cider;
pub mod useless;
80 changes: 80 additions & 0 deletions tools/calyx-ffi/src/backend/cider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use calyx_ir::Context;
use interp::flatten::structures::{
context::Context as CiderContext,
environment::{Environment, Simulator},
};
use std::{mem::MaybeUninit, rc::Rc};

pub struct CiderFFIBackend {
simulator: Simulator<Rc<CiderContext>>,
}

impl CiderFFIBackend {
pub fn from(context: &Context, name: &'static str) -> Self {
let cider_context = CiderContext::new();
let environment = Environment::new(Rc::new(cider_context), None);
let simulator = Simulator::new(environment);
Self { simulator }
}

pub fn write_port(&mut self, name: &'static str, value: u64) {
todo!("no way to set port on a component yet I think")
// self.simulator.
}

pub fn read_port(&self, name: &'static str) -> u64 {
todo!("no way to get port on a component yet I think")
}

pub fn step(&mut self) {
self.simulator.step().expect(
"this function isn't documented so don't know what went wrong",
);
}
}

/// Runs the component using cider2.
#[macro_export]
macro_rules! cider_ffi_backend {
(@user_data_type) => {
$crate::backend::cider::CiderFFIBackend
};
(@init $dut:ident, $ctx:expr; $($port:ident),*) => {
$dut.user_data
.write($crate::backend::cider::CiderFFIBackend::from(
$ctx,
$dut.name(),
));
};
(@reset $dut:ident; $($port:ident),*) => {
println!("cider_ffi_backend reset");
$dut.done = 0;
$dut.reset = 1;
for i in 0..5 {
$dut.tick();
}
$dut.reset = 0;
};
(@can_tick $dut:ident; $($port:ident),*) => {
true
};
(@tick $dut:ident; $($port:ident),*) => {
println!("cider_ffi_backend tick");
let cider = unsafe { $dut.user_data.assume_init_mut() };
$(
cider.write_port(stringify!($port), $dut.$port);
)*
cider.step();
$(
$dut.$port = cider.read_port(stringify!($port));
)*
};
(@go $dut:ident; $($port:ident),*) => {
println!("cider_ffi_backend go");
$dut.go = 1;
while ($dut.done != 1) {
$dut.tick();
}
$dut.go = 0;
};
}
35 changes: 35 additions & 0 deletions tools/calyx-ffi/src/backend/useless.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/// Example FFI backend.
#[macro_export]
macro_rules! useless_ffi_backend {
(@user_data_type) => {
() // unit type
};
(@init $dut:ident, $ctx:expr; $($port:ident),*) => {
println!("useless_ffi_backend init");
};
(@reset $dut:ident; $($port:ident),*) => {
println!("useless_ffi_backend reset");
$dut.done = 0;
$dut.reset = 1;
for i in 0..5 {
$dut.tick();
}
$dut.reset = 0;
};
(@can_tick $dut:ident; $($port:ident),*) => {
true
};
(@tick $dut:ident; $($port:ident),*) => {
println!("useless_ffi_backend tick");
if $dut.done == 1 {
$dut.done = 0;
}
};
(@go $dut:ident; $($port:ident),*) => {
println!("useless_ffi_backend go");
$dut.go = 1;
$dut.go = 0;
$dut.done = 1;
$dut.tick();
};
}
81 changes: 43 additions & 38 deletions tools/calyx-ffi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,71 +1,76 @@
use std::{any, cell::RefCell, collections::HashMap, rc::Rc};
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 in-source name of this component.
/// 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);

/// Internal deinitialization routine. Do not call!
fn deinit(&mut self);
fn init(&mut self, context: &Context);

// Resets this component.
/// Resets this component.
fn reset(&mut self);

// Advances this component by one clock cycle. May not always be available.
/// 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.
/// Calls this component, blocking until it is done executing.
fn go(&mut self);
}

pub type CalyxFFIComponentRef = Rc<RefCell<dyn CalyxFFIComponent>>;

fn box_calyx_ffi_component<T: CalyxFFIComponent>(
comp: T,
) -> CalyxFFIComponentRef {
Rc::new(RefCell::new(comp))
}

#[derive(Default)]
pub struct CalyxFFI {
reuse: HashMap<&'static str, usize>,
comps: Vec<CalyxFFIComponentRef>,
contexts: HashMap<&'static str, Context>,
}

impl CalyxFFI {
pub fn new() -> Self {
Self::default()
}

/// Any component `T`.
pub fn comp<T: CalyxFFIComponent + Default>(
&mut self,
) -> CalyxFFIComponentRef {
let name = T::default().name();
if let Some(index) = self.reuse.get(name) {
self.comps[*index].clone()
} else {
self.new_comp::<T>()
}
}

/// A new component `T`.
/// 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<T: CalyxFFIComponent + Default>(
&mut self,
) -> CalyxFFIComponentRef {
let comp = Rc::new(RefCell::new(T::default()));
comp.borrow_mut().init();
self.comps.push(comp.clone());
self.reuse
.insert(comp.borrow().name(), self.comps.len() - 1);
comp
}
}

impl Drop for CalyxFFI {
fn drop(&mut self) {
for comp in &self.comps {
comp.borrow_mut().deinit();
}
let mut comp = unsafe { 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)
}
}
Loading

0 comments on commit 0f3fc81

Please sign in to comment.