Skip to content

Commit

Permalink
Work on adding compile time port widths
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanuppal committed Nov 8, 2024
1 parent 33b9686 commit a2ba4ac
Show file tree
Hide file tree
Showing 15 changed files with 135 additions and 115 deletions.
10 changes: 1 addition & 9 deletions Cargo.lock

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

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ members = [
"tools/tb",
"tools/calyx-ffi-macro",
"tools/calyx-ffi",
"tools/tb/examples/calyx-native",
]

[workspace.package]
Expand Down
75 changes: 58 additions & 17 deletions tools/calyx-ffi-macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::{env, path::PathBuf};

use parse::CalyxFFIMacroArgs;
use parse::{CalyxFFIMacroArgs, CalyxPortDeclaration};
use proc_macro::TokenStream;
use quote::quote;
use quote::{format_ident, quote};
use syn::{parse_macro_input, spanned::Spanned};

mod calyx;
Expand Down Expand Up @@ -48,32 +48,58 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream {
let backend_macro = args.backend;
let mut input_names = Vec::new();
let mut output_names = Vec::new();
let mut field_names = vec![];
let mut fields = vec![];
let mut default_field_inits = vec![];
let mut getters = vec![];
let mut setters = vec![];
let mut width_getters = vec![];

for port in comp.signature.borrow().ports() {
let port_name_str = port.borrow().name.to_string();
let port_name = syn::parse_str::<syn::Ident>(&port_name_str)
.expect("failed to turn port name into identifier");
field_names.push(port_name.clone());
// let port_width = port.borrow().width;

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: u64
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: u64
#port_name: calyx_ffi::Value<#port_width>

});

let bitvec_getter = format_ident!("{}_bits", port_name);

getters.push(quote! {
pub fn #port_name(&self) -> u64 {
self.#port_name
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);
Expand All @@ -93,13 +119,15 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream {

let impl_block = quote! {
impl #name {
#(#width_getters)*
#(#getters)*
#(#setters)*
}

impl std::default::Default for #name {
fn default() -> Self {
Self {
#(#field_names: std::default::Default::default(),)*
#(#default_field_inits),*,
user_data: unsafe { std::mem::MaybeUninit::zeroed() }
}
}
Expand Down Expand Up @@ -142,21 +170,34 @@ pub fn calyx_ffi(attrs: TokenStream, item: TokenStream) -> TokenStream {
let trait_name = derive.name;

let mut getters = Vec::new();
for output in derive.outputs {
for CalyxPortDeclaration(name, width) in derive.outputs {
let name_bits = format_ident!("{}_bits", &name);

getters.push(quote! {
fn #output(&self) -> u64 {
self.#output
fn #name_bits(&self) -> &calyx_ffi::Value<#width> {
&self.#name
}

fn #name(&self) -> u64 {
Self::#name(self)
}
})
});
}

let mut setters = Vec::new();
for input in derive.inputs {
for CalyxPortDeclaration(name, width) in derive.inputs {
let name_bits = format_ident!("{}_bits", name);
let setter = format_ident!("set_{}", name);

setters.push(quote! {
fn #input(&mut self) -> &mut u64 {
&mut self.#input
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! {
Expand Down
19 changes: 15 additions & 4 deletions tools/calyx-ffi-macro/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,21 @@ use syn::{
parse::{Parse, ParseStream},
};

pub struct CalyxPortDeclaration(pub syn::Ident, pub syn::LitInt);

impl Parse for CalyxPortDeclaration {
fn parse(input: ParseStream) -> syn::Result<Self> {
let name = input.parse::<syn::Ident>()?;
input.parse::<syn::Token![:]>()?;
let width = input.parse::<syn::LitInt>()?;
Ok(Self(name, width))
}
}

pub struct CalyxInterface {
pub name: syn::Ident,
pub inputs: Vec<syn::Ident>,
pub outputs: Vec<syn::Ident>,
pub inputs: Vec<CalyxPortDeclaration>,
pub outputs: Vec<CalyxPortDeclaration>,
}

impl Parse for CalyxInterface {
Expand All @@ -19,13 +30,13 @@ impl Parse for CalyxInterface {
let outputs;
parenthesized!(inputs in input);
let inputs = inputs
.parse_terminated(syn::Ident::parse, syn::Token![,])?
.parse_terminated(CalyxPortDeclaration::parse, syn::Token![,])?
.into_iter()
.collect();
input.parse::<syn::Token![->]>()?;
parenthesized!(outputs in input);
let outputs = outputs
.parse_terminated(syn::Ident::parse, syn::Token![,])?
.parse_terminated(CalyxPortDeclaration::parse, syn::Token![,])?
.into_iter()
.collect();
Ok(Self {
Expand Down
4 changes: 4 additions & 0 deletions tools/calyx-ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ 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"
15 changes: 6 additions & 9 deletions tools/calyx-ffi/src/backend/cider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use interp::{
context::Context as CiderContext, environment::Simulator,
},
},
BitVecOps, BitVecValue,
BitVecValue,
};
use std::rc::Rc;

Expand All @@ -29,20 +29,17 @@ impl CiderFFIBackend {
Self { simulator }
}

pub fn write_port(&mut self, name: &'static str, value: u64) {
pub fn write_port(&mut self, name: &'static str, value: &BitVecValue) {
if name == "go" || name == "reset" {
return;
}
self.simulator
.pin_value(name, BitVecValue::from_u64(value, 64));
self.simulator.pin_value(name, value.clone());
}

pub fn read_port(&self, name: &'static str) -> u64 {
pub fn read_port(&self, name: &'static str) -> BitVecValue {
self.simulator
.lookup_port_from_string(&String::from(name))
.expect("wrong port name")
.to_u64()
.expect("type was not u64")
}

pub fn step(&mut self) {
Expand Down Expand Up @@ -86,7 +83,7 @@ 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);
)*
cider.step();
$(
Expand All @@ -97,7 +94,7 @@ macro_rules! cider_ffi_backend {
// 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);
)*
cider.go();
$(
Expand Down
16 changes: 8 additions & 8 deletions tools/calyx-ffi/src/backend/useless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,27 @@ macro_rules! useless_ffi_backend {
};
(@reset $dut:ident; $($input:ident),*; $($output:ident),*) => {
println!("useless_ffi_backend reset");
$dut.done = 0;
$dut.reset = 1;
$dut.done = interp::BitVecValue::from_u64(0, $dut.done_width() as u32);
$dut.set_reset(1);
for i in 0..5 {
$dut.tick();
}
$dut.reset = 0;
$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.done = 0;
if $dut.done() == 1 {
$dut.set_reset(0);
}
};
(@go $dut:ident; $($input:ident),*; $($output:ident),*) => {
println!("useless_ffi_backend go");
$dut.go = 1;
$dut.go = 0;
$dut.done = 1;
$dut.set_go(1);
$dut.set_go(0);
$dut.done = interp::BitVecValue::from_u64(1, $dut.done_width() as u32);
$dut.tick();
};
}
6 changes: 6 additions & 0 deletions tools/calyx-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,9 @@ impl CalyxFFI {
box_calyx_ffi_component(comp)
}
}

pub type Value<const N: u64> = interp::BitVecValue;

pub fn value_from_u64<const N: u64>(value: u64) -> Value<N> {
Value::from_u64(value, N as u32)
}
29 changes: 19 additions & 10 deletions tools/calyx-ffi/src/prelude.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
pub use super::{CalyxFFI, CalyxFFIComponent, CalyxFFIComponentRef};
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;

#[macro_export]
macro_rules! declare_calyx_ffi_interface {
($name:ident($($input:ident),*) -> ($($output:ident),*)) => {
pub trait $name: CalyxFFIComponent {
$(
fn $input(&mut self) -> &mut u64;
)*
$(
fn $output(&self) -> u64;
)*
macro_rules! declare_interface {
($name:ident($($input:ident: $input_width:literal),*) -> ($($output:ident: $output_width:literal),*)) => {
paste::paste! {
pub trait $name: CalyxFFIComponent {
$(
fn [<$input _bits>](&mut self) -> &mut calyx_ffi::Value<$input_width>;

fn [<set_ $input>](&mut self, value: u64);
)*
$(
fn [<$output _bits>](&self) -> &calyx_ffi::Value<$output_width>;

fn $output(&self) -> u64;
)*
}
}
};
}
File renamed without changes.
Loading

0 comments on commit a2ba4ac

Please sign in to comment.