move builting functions to own file

main
NotAFile 2022-01-05 02:08:25 +01:00
parent 33149eb5aa
commit 6abbd30792
2 changed files with 92 additions and 58 deletions

54
src/builtin_cells.rs Normal file
View File

@ -0,0 +1,54 @@
use crate::frontend::{Callable, CallArgument, Type};
use crate::rtlil;
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
}
fn instantiate_binop(celltype: &str, id: &str, args: &[String], ret: &str) -> rtlil::Cell {
let a = args.get(0).expect("wrong argcount slipped through type check");
let b = args.get(1).expect("wrong argcount slipped through type check");
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", ret);
cell
}
fn make_binop_callable(name: &str, celltype: &'static str) -> Callable {
let args = vec![
CallArgument {
name: "A".to_owned(),
atype: Type::wire(),
},
CallArgument {
name: "B".to_owned(),
atype: Type::wire(),
},
];
Callable {
name: name.to_owned(),
args,
ret: Type::wire(),
instantiate: Box::new(move |id, args, ret| instantiate_binop(celltype, id, args, ret))
}
}
pub fn get_builtins() -> Vec<Callable> {
vec![
make_binop_callable("and", "$and"),
make_binop_callable("xor", "$xor"),
]
}

View File

@ -1,30 +1,8 @@
use std::collections::BTreeMap;
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
use crate::builtin_cells::get_builtins;
fn make_pubid(id: &str) -> String {
"\\".to_owned() + id
@ -58,45 +36,46 @@ pub enum Type {
Wire(GenericParam<u32>)
}
// module that can be instantiated like a function
pub struct Callable {
impl Type {
pub fn wire() -> Self {
Self::Wire(GenericParam::Unsolved)
}
}
fn lower_expression(module: &mut rtlil::Module, expr: &parser::Expression) -> Result<String, CompileError> {
pub struct CallArgument {
pub name: String,
pub atype: Type,
}
// module that can be instantiated like a function
pub struct Callable {
pub name: String,
pub args: Vec<CallArgument>,
pub ret: Type,
pub instantiate: Box<dyn Fn(&str, &[String], &str) -> rtlil::Cell>
}
struct Context {
callables: BTreeMap<String, Callable>
}
fn lower_expression(ctx: &Context, 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));
let args_resolved = call.args.iter()
.map(|expr| lower_expression(ctx, module, expr)).collect::<Result<Vec<_>, _>>()?;
// TODO: make this sensible
let cell = match *call.name.fragment() {
"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()))),
};
let callable = ctx.callables.get(call.name.fragment() as &str).ok_or_else(|| {
CompileError::new(CompileErrorKind::UndefinedReference(call.name.fragment().to_string()))
})?;
let cell_id = module.make_genid(&callable.name);
let cell = (*callable.instantiate)(&cell_id, args_resolved.as_slice(), &output_gen_id);
module.add_cell(cell);
Ok(output_gen_id)
}
@ -104,9 +83,9 @@ fn lower_expression(module: &mut rtlil::Module, expr: &parser::Expression) -> Re
}
}
fn lower_assignment(module: &mut rtlil::Module, assignment: parser::Assign) -> Result<(), CompileError> {
fn lower_assignment(ctx: &Context, module: &mut rtlil::Module, assignment: parser::Assign) -> Result<(), CompileError> {
let target_id = make_pubid(&assignment.lhs);
let return_wire = lower_expression(module, &assignment.expr)?;
let return_wire = lower_expression(ctx, module, &assignment.expr)?;
module.add_connection(target_id, return_wire);
Ok(())
}
@ -114,6 +93,7 @@ fn lower_assignment(module: &mut rtlil::Module, assignment: parser::Assign) -> R
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));
let mut context = Context { callables: get_builtins().into_iter().map(|clb| (clb.name.to_owned(), clb)).collect() };
writer.write_line("autoidx 1");
for (idx, port) in pa_module.ports.iter().enumerate() {
let dir_option = match port.direction {
@ -129,7 +109,7 @@ pub fn lower_module(pa_module: parser::Module) -> Result<String, CompileError> {
}
for stmt in pa_module.statements {
match stmt {
parser::Statement::Assign(assignment) => lower_assignment(&mut ir_module, assignment)?,
parser::Statement::Assign(assignment) => lower_assignment(&context, &mut ir_module, assignment)?,
}
}
ir_module.write_rtlil(&mut writer);