futilehdl/src/frontend.rs

109 lines
4.0 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 struct CompileError;
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.as_str() {
"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)
}
_ => return Err(CompileError {}),
};
module.add_cell(cell);
Ok(output_gen_id)
}
parser::Expression::Operation(op) => todo!(),
}
}
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())
}