109 lines
4.0 KiB
Rust
109 lines
4.0 KiB
Rust
|
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())
|
||
|
}
|