make multiple blocks in one file work
This commit is contained in:
parent
8c16a94be4
commit
68be74d032
121
src/frontend.rs
121
src/frontend.rs
|
@ -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)?;
|
||||||
|
|
|
@ -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)>,
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,8 @@ 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 {
|
||||||
|
for block in module.blocks {
|
||||||
if opt.debug {
|
if opt.debug {
|
||||||
let mut pretty_block = String::new();
|
let mut pretty_block = String::new();
|
||||||
frontendcontext
|
frontendcontext
|
||||||
|
@ -76,6 +77,9 @@ fn main() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("{}", &pretty_block);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue