From 68be74d032b74cb3de03e898cdac2055a41bf109 Mon Sep 17 00:00:00 2001 From: NotAFile Date: Wed, 23 Feb 2022 23:36:01 +0100 Subject: [PATCH] make multiple blocks in one file work --- src/frontend.rs | 121 ++++++++++++++++++++++++++++----------- src/frontend/callable.rs | 1 + src/frontend/typed_ir.rs | 1 + src/main.rs | 37 +++++++----- 4 files changed, 110 insertions(+), 50 deletions(-) diff --git a/src/frontend.rs b/src/frontend.rs index dd1aeef..a237bd4 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -43,22 +43,9 @@ impl CompileError { } } -/// A user-defined signal -pub struct Signal { - /// 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, - // unique ID of the signal - // pub uid: u64, -} - -impl Signal { - fn sigspec(&self) -> rtlil::SigSpec { - rtlil::SigSpec::Wire(self.il_id.to_owned()) - } +#[derive(Debug)] +pub struct Module { + pub blocks: Vec, } pub struct Context { @@ -227,20 +214,20 @@ impl Context { Ok(t_expr) } - fn type_comb( + fn callable_from_block( &mut self, comb: &parser::comb::CombBlock, - ) -> Result { - let mut signals = Vec::new(); - + ) -> Result { + let mut genargs = vec![]; for (idx, tvarname) in comb.genparams.iter().enumerate() { let tvar = self.types.make_typevar(0, idx as u32); + // hacky workaround for no scopes self.typenames.insert(tvarname.name.to_string(), tvar); + genargs.push((Some(tvarname.name.to_string()), tvar)); } + let mut args = vec![]; for port in comb.ports.iter() { - let sig_id = self.ids.next(); - let sig_typename = &port.net.typ; let mut sig_type = self.try_get_type(sig_typename.name.fragment())?; if let Some(arg) = &sig_typename.generics { @@ -252,38 +239,73 @@ impl Context { .unwrap(); } - let sig = typed_ir::Signal { - id: typed_ir::DefId(sig_id as u32), - typ: sig_type, - }; - signals.push(sig.clone()); - self.signals.insert(port.net.name.to_string(), sig); + args.push((Some(port.net.name.to_string()), sig_type)); } let ret_typename = &comb.ret.name; - let _ret_type = self.try_get_type(ret_typename.fragment())?; - // TODO: use ret type + let ret_type = self.try_get_type(ret_typename.fragment())?; + + let signature = Callable { + name: comb.name.to_string(), + args, + genargs, + ret_type, + }; + let signature_id = self.callables.add(signature); + self.callable_names + .insert(comb.name.to_string(), signature_id); + Ok(signature_id) + } + + fn type_comb( + &mut self, + comb: &parser::comb::CombBlock, + ) -> Result { + let mut signals = Vec::new(); + + let callable_id = self.callable_from_block(comb)?; + let callable = self.callables.get(callable_id); + + for (argname, typ) in &callable.args { + let sig_id = self.ids.next(); + let sig = typed_ir::Signal { + id: typed_ir::DefId(sig_id as u32), + typ: *typ, + }; + signals.push(sig.clone()); + if let Some(argname) = argname { + self.signals.insert(argname.clone(), sig); + } + } let root_expr = self.type_expression(&comb.expr)?; Ok(typed_ir::Block { + signature: callable_id, signals, expr: root_expr, }) } - pub fn type_module(&mut self, module: parser::Module) -> Result { + pub fn type_module(&mut self, module: parser::Module) -> Result { + let mut typed_module = Module { blocks: vec![] }; + // hacky loop to predefine all names + for item in &module.items { + match &item { + parser::ModuleItem::Comb(comb) => self.callable_from_block(comb)?, + parser::ModuleItem::Proc(_) => todo!("proc block"), + parser::ModuleItem::State(_) => todo!("state block"), + }; + } for item in module.items { let block = match &item { parser::ModuleItem::Comb(comb) => self.type_comb(comb)?, parser::ModuleItem::Proc(_) => todo!("proc block"), parser::ModuleItem::State(_) => todo!("state block"), }; - return Ok(block); + typed_module.blocks.push(block); } - Err(CompileError::new(CompileErrorKind::TodoError( - "no blocks in module".to_string(), - ))) + Ok(typed_module) } pub fn infer_expr_types(&mut self, expr: &typed_ir::Expr) -> typed_ir::Expr { @@ -357,6 +379,35 @@ impl Context { w: &mut dyn std::fmt::Write, block: &typed_ir::Block, ) -> std::fmt::Result { + let callsig = self.callables.get(block.signature); + { + // TODO: ugly copy paste job + let args = callsig + .args + .iter() + .map(|(name, typ)| { + let mut out = String::new(); + self.types.pretty_type(&mut out, *typ)?; + Ok(out) + }) + .collect::, std::fmt::Error>>()?; + let genargs = callsig + .genargs + .iter() + .map(|(name, typ)| { + let mut type_str = String::new(); + self.types.pretty_type(&mut type_str, *typ)?; + Ok(type_str) + }) + .collect::, std::fmt::Error>>()?; + writeln!( + w, + "block {}<{}>({})", + callsig.name(), + genargs.join(", "), + args.join(", ") + )?; + } for sig in &block.signals { let mut typ_pretty = String::new(); self.types.pretty_type(&mut typ_pretty, sig.typ)?; diff --git a/src/frontend/callable.rs b/src/frontend/callable.rs index 0764153..6875303 100644 --- a/src/frontend/callable.rs +++ b/src/frontend/callable.rs @@ -3,6 +3,7 @@ use super::types::{Type, TypingContext}; #[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq, Ord)] pub struct CallableId(pub usize); +#[derive(Debug)] pub struct Callable { pub name: String, pub args: Vec<(Option, Type)>, diff --git a/src/frontend/typed_ir.rs b/src/frontend/typed_ir.rs index 3f7683f..e177d87 100644 --- a/src/frontend/typed_ir.rs +++ b/src/frontend/typed_ir.rs @@ -48,6 +48,7 @@ pub struct Signal { /// A block of HDL code, e.g. comb block #[derive(Debug, Clone)] pub struct Block { + pub signature: CallableId, pub signals: Vec, pub expr: Expr, } diff --git a/src/main.rs b/src/main.rs index a561cec..5c0d39d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -60,22 +60,26 @@ fn main() { } let mut frontendcontext = crate::frontend::Context::new(); let typed = frontendcontext.type_module(res.1); - if let Ok(block) = typed { - if opt.debug { - let mut pretty_block = String::new(); - frontendcontext - .pretty_typed_block(&mut pretty_block, &block) - .unwrap(); - println!("{}", &pretty_block); - } - let typed_inferred = frontendcontext.infer_types(block); - if opt.debug { - let mut pretty_block = String::new(); - frontendcontext - .pretty_typed_block(&mut pretty_block, &typed_inferred) - .unwrap(); - println!("{}", &pretty_block); + if let Ok(module) = typed { + for block in module.blocks { + if opt.debug { + let mut pretty_block = String::new(); + frontendcontext + .pretty_typed_block(&mut pretty_block, &block) + .unwrap(); + println!("{}", &pretty_block); + } + let typed_inferred = frontendcontext.infer_types(block); + if opt.debug { + let mut pretty_block = String::new(); + frontendcontext + .pretty_typed_block(&mut pretty_block, &typed_inferred) + .unwrap(); + println!("{}", &pretty_block); + } } + // TODO: be able to determine modules that are fully parameterized + /* let lowered = frontend::lowering::lower_block(&mut frontendcontext, typed_inferred); match lowered { Ok(res) => { @@ -87,6 +91,9 @@ fn main() { } Err(err) => eprintln!("{:#?}", err), } + */ + } else { + eprintln!("{:#?}", typed); } } }