make multiple blocks in one file work

This commit is contained in:
NotAFile 2022-02-23 23:36:01 +01:00
parent 8c16a94be4
commit 68be74d032
4 changed files with 110 additions and 50 deletions

View File

@ -43,22 +43,9 @@ impl CompileError {
} }
} }
/// A user-defined signal #[derive(Debug)]
pub struct Signal { pub struct Module {
/// the user-visible name of the signal pub blocks: Vec<typed_ir::Block>,
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())
}
} }
pub struct Context { pub struct Context {
@ -227,20 +214,20 @@ impl Context {
Ok(t_expr) Ok(t_expr)
} }
fn type_comb( fn callable_from_block(
&mut self, &mut self,
comb: &parser::comb::CombBlock, comb: &parser::comb::CombBlock,
) -> Result<typed_ir::Block, CompileError> { ) -> Result<CallableId, CompileError> {
let mut signals = Vec::new(); let mut genargs = vec![];
for (idx, tvarname) in comb.genparams.iter().enumerate() { for (idx, tvarname) in comb.genparams.iter().enumerate() {
let tvar = self.types.make_typevar(0, idx as u32); let tvar = self.types.make_typevar(0, idx as u32);
// hacky workaround for no scopes
self.typenames.insert(tvarname.name.to_string(), tvar); 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() { for port in comb.ports.iter() {
let sig_id = self.ids.next();
let sig_typename = &port.net.typ; let sig_typename = &port.net.typ;
let mut sig_type = self.try_get_type(sig_typename.name.fragment())?; let mut sig_type = self.try_get_type(sig_typename.name.fragment())?;
if let Some(arg) = &sig_typename.generics { if let Some(arg) = &sig_typename.generics {
@ -252,38 +239,73 @@ impl Context {
.unwrap(); .unwrap();
} }
let sig = typed_ir::Signal { args.push((Some(port.net.name.to_string()), sig_type));
id: typed_ir::DefId(sig_id as u32),
typ: sig_type,
};
signals.push(sig.clone());
self.signals.insert(port.net.name.to_string(), sig);
} }
let ret_typename = &comb.ret.name; let ret_typename = &comb.ret.name;
let _ret_type = self.try_get_type(ret_typename.fragment())?; let ret_type = self.try_get_type(ret_typename.fragment())?;
// TODO: use ret type
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<typed_ir::Block, CompileError> {
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)?; let root_expr = self.type_expression(&comb.expr)?;
Ok(typed_ir::Block { Ok(typed_ir::Block {
signature: callable_id,
signals, signals,
expr: root_expr, expr: root_expr,
}) })
} }
pub fn type_module(&mut self, module: parser::Module) -> Result<typed_ir::Block, CompileError> { pub fn type_module(&mut self, module: parser::Module) -> Result<Module, CompileError> {
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 { for item in module.items {
let block = match &item { let block = match &item {
parser::ModuleItem::Comb(comb) => self.type_comb(comb)?, parser::ModuleItem::Comb(comb) => self.type_comb(comb)?,
parser::ModuleItem::Proc(_) => todo!("proc block"), parser::ModuleItem::Proc(_) => todo!("proc block"),
parser::ModuleItem::State(_) => todo!("state block"), parser::ModuleItem::State(_) => todo!("state block"),
}; };
return Ok(block); typed_module.blocks.push(block);
} }
Err(CompileError::new(CompileErrorKind::TodoError( Ok(typed_module)
"no blocks in module".to_string(),
)))
} }
pub fn infer_expr_types(&mut self, expr: &typed_ir::Expr) -> typed_ir::Expr { 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, w: &mut dyn std::fmt::Write,
block: &typed_ir::Block, block: &typed_ir::Block,
) -> std::fmt::Result { ) -> 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::<Result<Vec<String>, 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::<Result<Vec<String>, std::fmt::Error>>()?;
writeln!(
w,
"block {}<{}>({})",
callsig.name(),
genargs.join(", "),
args.join(", ")
)?;
}
for sig in &block.signals { for sig in &block.signals {
let mut typ_pretty = String::new(); let mut typ_pretty = String::new();
self.types.pretty_type(&mut typ_pretty, sig.typ)?; self.types.pretty_type(&mut typ_pretty, sig.typ)?;

View File

@ -3,6 +3,7 @@ use super::types::{Type, TypingContext};
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq, Ord)] #[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq, Ord)]
pub struct CallableId(pub usize); pub struct CallableId(pub usize);
#[derive(Debug)]
pub struct Callable { pub struct Callable {
pub name: String, pub name: String,
pub args: Vec<(Option<String>, Type)>, pub args: Vec<(Option<String>, Type)>,

View File

@ -48,6 +48,7 @@ pub struct Signal {
/// A block of HDL code, e.g. comb block /// A block of HDL code, e.g. comb block
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Block { pub struct Block {
pub signature: CallableId,
pub signals: Vec<Signal>, pub signals: Vec<Signal>,
pub expr: Expr, pub expr: Expr,
} }

View File

@ -60,22 +60,26 @@ fn main() {
} }
let mut frontendcontext = crate::frontend::Context::new(); let mut frontendcontext = crate::frontend::Context::new();
let typed = frontendcontext.type_module(res.1); let typed = frontendcontext.type_module(res.1);
if let Ok(block) = typed { if let Ok(module) = typed {
if opt.debug { for block in module.blocks {
let mut pretty_block = String::new(); if opt.debug {
frontendcontext let mut pretty_block = String::new();
.pretty_typed_block(&mut pretty_block, &block) frontendcontext
.unwrap(); .pretty_typed_block(&mut pretty_block, &block)
println!("{}", &pretty_block); .unwrap();
} println!("{}", &pretty_block);
let typed_inferred = frontendcontext.infer_types(block); }
if opt.debug { let typed_inferred = frontendcontext.infer_types(block);
let mut pretty_block = String::new(); if opt.debug {
frontendcontext let mut pretty_block = String::new();
.pretty_typed_block(&mut pretty_block, &typed_inferred) frontendcontext
.unwrap(); .pretty_typed_block(&mut pretty_block, &typed_inferred)
println!("{}", &pretty_block); .unwrap();
println!("{}", &pretty_block);
}
} }
// TODO: be able to determine modules that are fully parameterized
/*
let lowered = frontend::lowering::lower_block(&mut frontendcontext, typed_inferred); let lowered = frontend::lowering::lower_block(&mut frontendcontext, typed_inferred);
match lowered { match lowered {
Ok(res) => { Ok(res) => {
@ -87,6 +91,9 @@ fn main() {
} }
Err(err) => eprintln!("{:#?}", err), Err(err) => eprintln!("{:#?}", err),
} }
*/
} else {
eprintln!("{:#?}", typed);
} }
} }
} }