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::parser;
|
||||||
use crate::rtlil;
|
use crate::rtlil;
|
||||||
|
use crate::builtin_cells::get_builtins;
|
||||||
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 {
|
fn make_pubid(id: &str) -> String {
|
||||||
"\\".to_owned() + id
|
"\\".to_owned() + id
|
||||||
|
@ -58,45 +36,46 @@ pub enum Type {
|
||||||
Wire(GenericParam<u32>)
|
Wire(GenericParam<u32>)
|
||||||
}
|
}
|
||||||
|
|
||||||
// module that can be instantiated like a function
|
impl Type {
|
||||||
pub struct Callable {
|
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 {
|
match expr {
|
||||||
parser::Expression::Ident(ident) => Ok(make_pubid(&ident)),
|
parser::Expression::Ident(ident) => Ok(make_pubid(&ident)),
|
||||||
parser::Expression::Call(call) => {
|
parser::Expression::Call(call) => {
|
||||||
let output_gen_id = module.make_genid("cell");
|
let output_gen_id = module.make_genid("cell");
|
||||||
module.add_wire(rtlil::Wire::new(&output_gen_id, 1, None));
|
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 callable = ctx.callables.get(call.name.fragment() as &str).ok_or_else(|| {
|
||||||
let cell = match *call.name.fragment() {
|
CompileError::new(CompileErrorKind::UndefinedReference(call.name.fragment().to_string()))
|
||||||
"and" => {
|
})?;
|
||||||
let arg_a = args_resolved.next().unwrap()?;
|
|
||||||
let arg_b = args_resolved.next().unwrap()?;
|
let cell_id = module.make_genid(&callable.name);
|
||||||
let cell_id = module.make_genid("and");
|
|
||||||
builtin_binop_cell("$and", &cell_id, &arg_a, &arg_b, &output_gen_id)
|
let cell = (*callable.instantiate)(&cell_id, args_resolved.as_slice(), &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()))),
|
|
||||||
};
|
|
||||||
module.add_cell(cell);
|
module.add_cell(cell);
|
||||||
Ok(output_gen_id)
|
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 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);
|
module.add_connection(target_id, return_wire);
|
||||||
Ok(())
|
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> {
|
pub fn lower_module(pa_module: parser::Module) -> Result<String, CompileError> {
|
||||||
let mut writer = rtlil::ILWriter::new();
|
let mut writer = rtlil::ILWriter::new();
|
||||||
let mut ir_module = rtlil::Module::new(make_pubid(&pa_module.name));
|
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");
|
writer.write_line("autoidx 1");
|
||||||
for (idx, port) in pa_module.ports.iter().enumerate() {
|
for (idx, port) in pa_module.ports.iter().enumerate() {
|
||||||
let dir_option = match port.direction {
|
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 {
|
for stmt in pa_module.statements {
|
||||||
match stmt {
|
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);
|
ir_module.write_rtlil(&mut writer);
|
||||||
|
|
Loading…
Reference in New Issue