diff --git a/src/builtin_cells.rs b/src/builtin_cells.rs index 2e5b606..84af1d7 100644 --- a/src/builtin_cells.rs +++ b/src/builtin_cells.rs @@ -1,4 +1,5 @@ -use crate::frontend::{CallArgument, Callable, Type}; +use crate::frontend::{Callable}; +use crate::frontend::types::{Type, TypeStruct}; use crate::rtlil; use crate::rtlil::SigSpec; @@ -38,39 +39,41 @@ fn instantiate_binop(celltype: &str, id: &str, args: &[SigSpec], ret: &SigSpec) cell } -fn make_binop_callable(name: &str, celltype: &'static str) -> Callable { +fn make_binop_callable<'ctx>(name: &str, celltype: &'static str) -> Callable<'ctx> { + // FIXME: CRIMES CRIMES CRIMES + let logic_type: &'static TypeStruct = Box::leak(Box::new(TypeStruct::logic_infer())); let args = vec![ - CallArgument { - name: "A".to_owned(), - atype: Type::wire(), - }, - CallArgument { - name: "B".to_owned(), - atype: Type::wire(), - }, + ( + Some("a".to_owned()), + logic_type, + ), + ( + Some("b".to_owned()), + logic_type, + ), ]; Callable { name: name.to_owned(), args, - ret: Type::wire(), - instantiate: Box::new(move |id, args, ret| instantiate_binop(celltype, id, args, ret)), + ret_type: Some(logic_type), } } -fn make_unnop_callable(name: &str, celltype: &'static str) -> Callable { - let args = vec![CallArgument { - name: "A".to_owned(), - atype: Type::wire(), - }]; +fn make_unnop_callable<'ctx>(name: &str, celltype: &'static str) -> Callable<'ctx> { + // FIXME: CRIMES CRIMES CRIMES + let logic_type: &'static TypeStruct = Box::leak(Box::new(TypeStruct::logic_infer())); + let args = vec![( + Some("A".to_owned()), + logic_type, + )]; Callable { name: name.to_owned(), args, - ret: Type::wire(), - instantiate: Box::new(move |id, args, ret| instantiate_unop(celltype, id, args, ret)), + ret_type: Some(logic_type), } } -pub fn get_builtins() -> Vec { +pub fn get_builtins<'ctx>() -> Vec> { vec![ make_binop_callable("and", "$and"), make_binop_callable("or", "$or"), diff --git a/src/frontend.rs b/src/frontend.rs index 700d325..22d9a2d 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -4,6 +4,11 @@ use crate::builtin_cells::get_builtins; use crate::parser; use crate::rtlil; use crate::rtlil::RtlilWrite; +pub use callable::Callable; +pub use types::{Type, TypeStruct}; + +mod callable; +pub mod types; /// lots of code is still not width-aware, this constant keeps track of that const TODO_WIDTH: u32 = 1; @@ -29,48 +34,19 @@ impl CompileError { } } -pub enum GenericParam { - Unsolved, - Solved(T), -} - -pub enum Type { - /// a wire of some width - Wire(GenericParam), -} - -impl Type { - pub fn wire() -> Self { - Self::Wire(GenericParam::Unsolved) - } -} - -pub struct CallArgument { - pub name: String, - pub atype: Type, -} - -// module that can be instantiated like a function -pub struct Callable { - pub name: String, - pub args: Vec, - pub ret: Type, - pub instantiate: Box rtlil::Cell>, -} - /// A user-defined signal -pub struct Signal { +pub struct Signal<'ctx> { /// the user-visible name of the signal pub name: String, /// the id of the signal in RTLIL pub il_id: String, /// the type of the signal - pub typ: Type, + pub typ: Type<'ctx>, // unique ID of the signal // pub uid: u64, } -impl Signal { +impl<'ctx> Signal<'ctx> { fn sigspec(&self) -> rtlil::SigSpec { rtlil::SigSpec::Wire(self.il_id.to_owned()) } @@ -82,14 +58,16 @@ struct ProcContext { next_sigs: BTreeMap, } -struct Context { +struct Context<'ctx> { /// map callable name to callable - callables: BTreeMap, + callables: BTreeMap>, + /// types + types: Vec>, /// map signal name to Signal - signals: BTreeMap, + signals: BTreeMap>, } -impl Context { +impl<'ctx> Context<'ctx> { fn get_signal(&self, signame: &str) -> Option<&Signal> { self.signals.get(signame) } @@ -269,22 +247,22 @@ fn lower_expression( )) })?; - if args_resolved.len() != callable.args.len() { + if args_resolved.len() != callable.argcount() { return Err(CompileError::new(CompileErrorKind::BadArgCount { - expected: callable.args.len(), + expected: callable.argcount(), received: args_resolved.len(), })); } - let cell_id = module.make_genid(&callable.name); + let cell_id = module.make_genid(&callable.name()); let output_gen_id = format!("{}$out", &cell_id); module.add_wire(rtlil::Wire::new(&output_gen_id, TODO_WIDTH, None)); let output_gen_wire = rtlil::SigSpec::Wire(output_gen_id); - let cell = - (*callable.instantiate)(&cell_id, args_resolved.as_slice(), &output_gen_wire); - module.add_cell(cell); + // let cell = + // (*callable.instantiate)(&cell_id, args_resolved.as_slice(), &output_gen_wire); + // module.add_cell(cell); Ok(output_gen_wire) } // TODO: instantiate operators directly here instead of desugaring, once the callable infrastructure improves @@ -311,16 +289,21 @@ pub fn lower_module(pa_module: parser::Module) -> Result { let mut context = Context { callables: get_builtins() .into_iter() - .map(|clb| (clb.name.to_owned(), clb)) + .map(|clb| (clb.name().to_owned(), clb)) .collect(), signals: BTreeMap::new(), + types: vec![], }; + writer.write_line("autoidx 1"); for (idx, port) in pa_module.ports.iter().enumerate() { + let sigtype = TypeStruct::logic_width(port.net.width.unwrap_or(1) as u32); + // FIXME: CRIMES CRIMES CRIMES + let sigtype = Box::leak(Box::new(sigtype)); let sig = Signal { name: port.net.name.to_owned(), il_id: make_pubid(port.net.name), - typ: Type::Wire(GenericParam::Solved(port.net.width.unwrap_or(1) as u32)), + typ: sigtype, }; let sig = context .signals diff --git a/src/frontend/callable.rs b/src/frontend/callable.rs new file mode 100644 index 0000000..e7ebbbe --- /dev/null +++ b/src/frontend/callable.rs @@ -0,0 +1,17 @@ +use super::types::Type; + +pub struct Callable<'ty> { + pub name: String, + pub args: Vec<(Option, Type<'ty>)>, + pub ret_type: Option>, +} + +impl<'ty> Callable<'ty> { + pub fn name(&self) -> &str { + &self.name + } + + pub fn argcount(&self) -> usize { + self.args.len() + } +} diff --git a/src/frontend/types.rs b/src/frontend/types.rs new file mode 100644 index 0000000..a53b1a5 --- /dev/null +++ b/src/frontend/types.rs @@ -0,0 +1,84 @@ +/// Alias for &TypeStruct to reduce repetition +/// and make futura migration to interning +/// easier +pub type Type<'ty> = &'ty TypeStruct<'ty>; + +pub struct TypeStruct<'ty> { + kind: TypeKind<'ty>, +} + +pub enum TypeKind<'ty> { + /// Elaboration-time types + ElabType(ElabKind), + /// Signal/Wire of generic width + Logic(ElabData<'ty>), + /// UInt of generic width + UInt(ElabData<'ty>), + /// Callable + Callable, +} + +struct ElabData<'ty> { + typ: Type<'ty>, + value: ElabValue<'ty>, +} + +enum ElabValue<'ty> { + /// the value is not given and has to be inferred + Infer, + /// the value is given as some byte representation + Concrete(ElabValueData<'ty>), +} + +enum ElabValueData<'ty> { + U32(u32), + Bytes(&'ty [u8]), +} + +/// Types that are only valid during Elaboration +enum ElabKind { + /// general, unsized number type + Num +} + +/// Helper functions to create primitive types +impl<'ty> TypeStruct<'ty> { + /// a logic signal with inferred width + pub fn logic_infer() -> Self { + Self { + kind: TypeKind::Logic(ElabData { + typ: &TypeStruct { + kind: TypeKind::ElabType(ElabKind::Num) + }, + value: ElabValue::Infer, + }) + } + } + + /// a logic signal with known width + pub fn logic_width(width: u32) -> Self { + Self { + kind: TypeKind::Logic(ElabData::u32(width)) + } + } + + /// return an elaboration number type + pub fn elab_num() -> Self { + Self { + kind: TypeKind::ElabType(ElabKind::Num) + } + } +} + +/// Helper functions to create primitive elaboration values +impl<'ty> ElabData<'ty> { + /// an integer + pub fn u32(val: u32) -> Self { + Self { + typ: &TypeStruct { + kind: TypeKind::ElabType(ElabKind::Num) + }, + value: ElabValue::Concrete(ElabValueData::U32(val)) + } + } +}