futilehdl/src/frontend.rs

138 lines
4.5 KiB
Rust
Raw Normal View History

2022-01-04 22:05:25 +00:00
use crate::parser;
use crate::rtlil;
fn builtin_binop_cell(celltype: &str, id: &str, a: &str, b: &str, y: &str) -> rtlil::Cell {
let mut cell = rtlil::Cell::new(id, celltype);
cell.add_param("\\A_SIGNED", "0");
cell.add_param("\\A_WIDTH", "1");
cell.add_param("\\B_SIGNED", "0");
cell.add_param("\\B_WIDTH", "1");
cell.add_param("\\Y_WIDTH", "1");
cell.add_connection("\\A", a);
cell.add_connection("\\B", b);
cell.add_connection("\\Y", y);
cell
}
fn builtin_unop_cell(celltype: &str, id: &str, a: &str, y: &str) -> rtlil::Cell {
let mut cell = rtlil::Cell::new(id, celltype);
cell.add_param("\\A_SIGNED", "0");
cell.add_param("\\A_WIDTH", "1");
cell.add_param("\\Y_WIDTH", "1");
cell.add_connection("\\A", a);
cell.add_connection("\\Y", y);
cell
}
// the hacky way
fn make_pubid(id: &str) -> String {
"\\".to_owned() + id
}
#[derive(Debug)]
pub enum CompileErrorKind {
UndefinedReference(String)
}
#[derive(Debug)]
pub struct CompileError {
kind: CompileErrorKind,
}
impl CompileError {
fn new(kind: CompileErrorKind) -> Self {
Self {
kind
}
}
}
pub enum GenericParam<T> {
Unsolved,
Solved(T),
}
pub enum Type {
/// a wire of some width
Wire(GenericParam<u32>)
}
// module that can be instantiated like a function
pub struct Callable {
}
2022-01-04 22:05:25 +00:00
fn lower_expression(module: &mut rtlil::Module, expr: &parser::Expression) -> Result<String, CompileError> {
match expr {
parser::Expression::Ident(ident) => Ok(make_pubid(&ident)),
parser::Expression::Call(call) => {
let output_gen_id = module.make_genid("cell");
module.add_wire(rtlil::Wire::new(&output_gen_id, 1, None));
let mut args_resolved = call.args.iter().map(|expr| lower_expression(module, expr));
// TODO: make this sensible
let cell = match *call.name.fragment() {
2022-01-04 22:05:25 +00:00
"and" => {
let arg_a = args_resolved.next().unwrap()?;
let arg_b = args_resolved.next().unwrap()?;
let cell_id = module.make_genid("and");
builtin_binop_cell("$and", &cell_id, &arg_a, &arg_b, &output_gen_id)
}
"xor" => {
let arg_a = args_resolved.next().unwrap()?;
let arg_b = args_resolved.next().unwrap()?;
let cell_id = module.make_genid("xor");
builtin_binop_cell("$xor", &cell_id, &arg_a, &arg_b, &output_gen_id)
}
"not" => {
let arg_a = args_resolved.next().unwrap()?;
let cell_id = module.make_genid("not");
builtin_unop_cell("$not", &cell_id, &arg_a, &output_gen_id)
}
"reduce_or" => {
let arg_a = args_resolved.next().unwrap()?;
let cell_id = module.make_genid("reduce_or");
builtin_unop_cell("$reduce_or", &cell_id, &arg_a, &output_gen_id)
}
name => return Err(CompileError::new(CompileErrorKind::UndefinedReference(name.to_owned()))),
2022-01-04 22:05:25 +00:00
};
module.add_cell(cell);
Ok(output_gen_id)
}
parser::Expression::Operation(_op) => todo!(),
2022-01-04 22:05:25 +00:00
}
}
fn lower_assignment(module: &mut rtlil::Module, assignment: parser::Assign) -> Result<(), CompileError> {
let target_id = make_pubid(&assignment.lhs);
let return_wire = lower_expression(module, &assignment.expr)?;
module.add_connection(target_id, return_wire);
Ok(())
}
pub fn lower_module(pa_module: parser::Module) -> Result<String, CompileError> {
let mut writer = rtlil::ILWriter::new();
let mut ir_module = rtlil::Module::new(make_pubid(&pa_module.name));
writer.write_line("autoidx 1");
for (idx, port) in pa_module.ports.iter().enumerate() {
let dir_option = match port.direction {
parser::PortDirection::Input => rtlil::PortOption::Input(idx as i32 + 1),
parser::PortDirection::Output => rtlil::PortOption::Output(idx as i32 + 1),
};
let wire = rtlil::Wire::new(
make_pubid(&port.net.name),
port.net.width.unwrap_or(1) as u32,
Some(dir_option)
);
ir_module.add_wire(wire);
}
for stmt in pa_module.statements {
match stmt {
parser::Statement::Assign(assignment) => lower_assignment(&mut ir_module, assignment)?,
}
}
ir_module.write_rtlil(&mut writer);
Ok(writer.finish())
}