move builting functions to own file
This commit is contained in:
parent
33149eb5aa
commit
6abbd30792
|
@ -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"),
|
||||
]
|
||||
}
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue