futilehdl/src/frontend.rs

179 lines
4.8 KiB
Rust
Raw Normal View History

2022-02-06 22:19:55 +00:00
use std::borrow::Borrow;
use std::cell::Cell;
2022-01-05 01:08:25 +00:00
use std::collections::BTreeMap;
2022-02-06 22:19:55 +00:00
use super::parser;
2022-01-04 22:05:25 +00:00
use crate::rtlil;
pub use callable::Callable;
2022-02-06 20:02:55 +00:00
pub use types::{make_primitives, Type, TypeStruct};
mod callable;
2022-02-06 22:19:55 +00:00
#[cfg(never)]
pub mod lowering;
2022-01-30 22:54:19 +00:00
pub mod typed_ir;
2022-02-01 18:46:06 +00:00
pub mod types;
2022-01-04 22:05:25 +00:00
2022-02-06 22:19:55 +00:00
use crate::builtin_cells::get_builtins;
// pub use lowering::lower_module;
/// lots of code is still not width-aware, this constant keeps track of that
const TODO_WIDTH: u32 = 1;
2022-01-04 22:05:25 +00:00
fn make_pubid(id: &str) -> String {
"\\".to_owned() + id
}
#[derive(Debug)]
pub enum CompileErrorKind {
2022-01-05 01:09:08 +00:00
UndefinedReference(String),
2022-01-14 14:32:00 +00:00
BadArgCount { received: usize, expected: usize },
2022-02-06 22:19:55 +00:00
TodoError(String),
}
#[derive(Debug)]
pub struct CompileError {
kind: CompileErrorKind,
}
impl CompileError {
fn new(kind: CompileErrorKind) -> Self {
2022-01-05 01:09:08 +00:00
Self { kind }
}
}
2022-01-17 20:02:11 +00:00
/// A user-defined signal
pub struct Signal<'ctx> {
2022-01-17 20:02:11 +00:00
/// the user-visible name of the signal
pub name: String,
/// the id of the signal in RTLIL
2022-01-17 20:04:22 +00:00
pub il_id: String,
2022-01-17 20:02:11 +00:00
/// the type of the signal
pub typ: Type<'ctx>,
2022-01-17 20:02:11 +00:00
// unique ID of the signal
// pub uid: u64,
}
impl<'ctx> Signal<'ctx> {
2022-01-17 20:04:22 +00:00
fn sigspec(&self) -> rtlil::SigSpec {
rtlil::SigSpec::Wire(self.il_id.to_owned())
}
}
2022-02-06 22:19:55 +00:00
pub struct Context<'ctx> {
2022-01-17 20:02:11 +00:00
/// map callable name to callable
callables: BTreeMap<String, Callable<'ctx>>,
/// types
2022-02-06 20:02:55 +00:00
types: BTreeMap<String, TypeStruct<'ctx>>,
2022-01-17 20:02:11 +00:00
/// map signal name to Signal
2022-02-06 22:19:55 +00:00
signals: BTreeMap<String, typed_ir::Signal<'ctx>>,
/// incrementing counter for unique IDs
ids: Counter,
}
struct Counter(Cell<usize>);
impl Counter {
fn new() -> Counter {
Counter(Cell::new(0))
}
fn next(&self) -> usize {
let next = self.0.get() + 1;
self.0.set(next);
next
}
}
2022-01-04 22:05:25 +00:00
impl<'ctx> Context<'ctx> {
2022-02-06 22:19:55 +00:00
pub fn new() -> Self {
Context {
callables: get_builtins()
.into_iter()
.map(|clb| (clb.name().to_owned(), clb))
.collect(),
signals: BTreeMap::new(),
types: make_primitives().into_iter().collect(),
ids: Counter::new(),
}
}
fn get_signal(&self, signame: &str) -> Option<&typed_ir::Signal> {
2022-01-17 20:04:22 +00:00
self.signals.get(signame)
}
2022-02-06 22:19:55 +00:00
fn try_get_signal(&self, signame: &str) -> Result<&typed_ir::Signal, CompileError> {
2022-01-20 18:55:17 +00:00
self.get_signal(signame).ok_or_else(|| {
CompileError::new(CompileErrorKind::UndefinedReference(signame.to_owned()))
})
2022-01-17 20:04:22 +00:00
}
2022-02-06 20:02:55 +00:00
2022-02-06 22:19:55 +00:00
fn try_get_type(&'ctx self, typename: &str) -> Result<Type<'ctx>, CompileError> {
2022-02-06 20:02:55 +00:00
self.types.get(typename).ok_or_else(|| {
CompileError::new(CompileErrorKind::UndefinedReference(typename.to_owned()))
})
}
2022-01-17 20:04:22 +00:00
2022-02-06 22:19:55 +00:00
fn type_expression(
&self,
expr: &parser::expression::Expression,
) -> Result<typed_ir::Expr, CompileError> {
let typ = match expr {
parser::expression::Expression::Path(name) => self.try_get_signal(name)?.typ,
parser::expression::Expression::Literal(_) => todo!(),
parser::expression::Expression::UnOp(op) => self.type_expression(&op.a)?.typ,
parser::expression::Expression::BinOp(_) => todo!(),
parser::expression::Expression::Call(call) => todo!(),
};
Ok(typed_ir::Expr {
id: 0,
inputs: vec![],
typ: typ,
})
2022-01-17 18:20:51 +00:00
}
2022-02-06 22:19:55 +00:00
fn type_comb(
&mut self,
comb: &parser::comb::CombBlock,
) -> Result<typed_ir::Block, CompileError> {
let mut signals = Vec::new();
for port in comb.ports.iter() {
let sig_id = self.ids.next();
let sig_typename = &port.net.typ;
let sig_type = self.try_get_type(sig_typename.name.fragment())?;
let sig = typed_ir::Signal {
id: sig_id as u32,
typ: sig_type,
};
signals.push(sig);
self.signals.insert(port.net.name.to_string(), sig);
2022-01-20 18:55:17 +00:00
}
2022-01-05 01:09:08 +00:00
2022-02-06 22:19:55 +00:00
let ret_typename = &comb.ret.name;
let ret_type = self.try_get_type(&ret_typename.fragment())?;
2022-01-05 01:08:25 +00:00
2022-02-06 22:19:55 +00:00
let root_expr = self.type_expression(&comb.expr)?;
2022-01-05 01:38:56 +00:00
2022-02-06 22:19:55 +00:00
Ok(typed_ir::Block {
signals,
expr: root_expr,
})
2022-02-04 23:58:47 +00:00
}
2022-02-06 22:19:55 +00:00
pub fn type_module(
&'ctx mut self,
module: parser::Module,
) -> Result<typed_ir::Block<'ctx>, CompileError> {
for item in module.items {
let block = match &item {
parser::ModuleItem::Comb(comb) => self.type_comb(comb)?,
parser::ModuleItem::Proc(_) => todo!(),
parser::ModuleItem::State(_) => todo!(),
};
return Ok(block);
2022-01-04 22:05:25 +00:00
}
2022-02-06 22:19:55 +00:00
Err(CompileError::new(CompileErrorKind::TodoError(
"no blocks in module".to_string(),
)))
2022-01-04 22:05:25 +00:00
}
}