-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement compile-time port width verification
- Loading branch information
1 parent
cfe7916
commit caf6055
Showing
9 changed files
with
639 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<RefCell<dyn CalyxFFIComponent>>; | ||
|
||
fn box_calyx_ffi_component<T: CalyxFFIComponent>( | ||
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<T: CalyxFFIComponent + Default>( | ||
&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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<RefCell<dyn CalyxFFIComponent>>; | ||
|
||
fn box_calyx_ffi_component<T: CalyxFFIComponent>( | ||
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<T: CalyxFFIComponent + Default>( | ||
&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<const N: u64> = interp::BitVecValue; | ||
|
||
pub fn value_from_u64<const N: u64>(value: u64) -> Value<N> { | ||
Value::from_u64(value, N as u32) | ||
} | ||
pub mod value; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<const N: interp::WidthInt> { | ||
pub inner: interp::BitVecValue, | ||
} | ||
|
||
impl<const N: interp::WidthInt> From<u64> for Value<N> { | ||
fn from(value: u64) -> Self { | ||
Self { | ||
inner: interp::BitVecValue::from_u64(value, N), | ||
} | ||
} | ||
} | ||
|
||
impl<const N: interp::WidthInt> TryInto<u64> for &Value<N> { | ||
type Error = ValueConversionError; | ||
|
||
fn try_into(self) -> Result<u64, Self::Error> { | ||
use interp::BitVecOps; | ||
self.inner | ||
.to_u64() | ||
.ok_or(Self::Error::WidthTooLarge(self.inner.width())) | ||
} | ||
} | ||
|
||
impl<const N: interp::WidthInt> interp::BitVecOps for Value<N> { | ||
fn width(&self) -> interp::WidthInt { | ||
N | ||
} | ||
|
||
fn words(&self) -> &[interp::Word] { | ||
self.inner.words() | ||
} | ||
} |
Oops, something went wrong.