128 lines
5.1 KiB
Rust
128 lines
5.1 KiB
Rust
use std::collections::BTreeMap;
|
|
|
|
use super::typed_ir;
|
|
use super::typed_ir::ExprKind;
|
|
use super::{make_pubid, CompileError, Context, TODO_WIDTH};
|
|
use crate::rtlil;
|
|
use crate::rtlil::RtlilWrite;
|
|
|
|
fn lower_expression(
|
|
ctx: &Context,
|
|
module: &mut rtlil::Module,
|
|
expr: &typed_ir::Expr,
|
|
) -> Result<rtlil::SigSpec, CompileError> {
|
|
let expr_width = ctx.types.get_width(expr.typ).expect("signal needs width");
|
|
let expr_wire_name = format!("$sig_{}", expr.id.0);
|
|
let expr_wire = rtlil::Wire::new(expr_wire_name.clone(), expr_width, None);
|
|
module.add_wire(expr_wire);
|
|
match &expr.kind {
|
|
ExprKind::Path(def) => Ok(rtlil::SigSpec::Wire(format!("$sig_{}", def.0))),
|
|
ExprKind::Call {
|
|
called,
|
|
args,
|
|
genargs,
|
|
} => {
|
|
let args_resolved = args
|
|
.iter()
|
|
.map(|expr| lower_expression(ctx, module, expr))
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
|
|
let callable = ctx.callables.get(*called);
|
|
let cell_id = module.make_genid(callable.name());
|
|
|
|
if *called == ctx.callables.builtins.xor {
|
|
let a_width = ctx.types.get_width(args[0].typ).unwrap();
|
|
let b_width = ctx.types.get_width(args[1].typ).unwrap();
|
|
let y_width = ctx.types.get_width(expr.typ).unwrap();
|
|
let mut cell = rtlil::Cell::new(&cell_id, "$xor");
|
|
cell.add_param("\\A_SIGNED", "0");
|
|
cell.add_param("\\A_WIDTH", &a_width.to_string());
|
|
cell.add_param("\\B_SIGNED", "0");
|
|
cell.add_param("\\B_WIDTH", &b_width.to_string());
|
|
cell.add_param("\\Y_WIDTH", &y_width.to_string());
|
|
cell.add_connection(
|
|
"\\A",
|
|
&rtlil::SigSpec::Wire(format!("$sig_{}", args[0].id.0)),
|
|
);
|
|
cell.add_connection(
|
|
"\\B",
|
|
&rtlil::SigSpec::Wire(format!("$sig_{}", args[1].id.0)),
|
|
);
|
|
cell.add_connection("\\Y", &rtlil::SigSpec::Wire(expr_wire_name.clone()));
|
|
module.add_cell(cell);
|
|
} else if *called == ctx.callables.builtins.reduce_or {
|
|
let a_width = ctx.types.get_width(args[0].typ).unwrap();
|
|
let y_width = ctx.types.get_width(expr.typ).unwrap();
|
|
let mut cell = rtlil::Cell::new(&cell_id, "$reduce_or");
|
|
cell.add_param("\\A_SIGNED", "0");
|
|
cell.add_param("\\A_WIDTH", &a_width.to_string());
|
|
cell.add_param("\\Y_WIDTH", &y_width.to_string());
|
|
cell.add_connection(
|
|
"\\A",
|
|
&rtlil::SigSpec::Wire(format!("$sig_{}", args[0].id.0)),
|
|
);
|
|
cell.add_connection("\\Y", &rtlil::SigSpec::Wire(expr_wire_name.clone()));
|
|
module.add_cell(cell);
|
|
} else if *called == ctx.callables.builtins.bitnot {
|
|
let a_width = ctx.types.get_width(args[0].typ).unwrap();
|
|
let y_width = ctx.types.get_width(expr.typ).unwrap();
|
|
let mut cell = rtlil::Cell::new(&cell_id, "$not");
|
|
cell.add_param("\\A_SIGNED", "0");
|
|
cell.add_param("\\A_WIDTH", &a_width.to_string());
|
|
cell.add_param("\\Y_WIDTH", &y_width.to_string());
|
|
cell.add_connection(
|
|
"\\A",
|
|
&rtlil::SigSpec::Wire(format!("$sig_{}", args[0].id.0)),
|
|
);
|
|
cell.add_connection("\\Y", &rtlil::SigSpec::Wire(expr_wire_name.clone()));
|
|
module.add_cell(cell);
|
|
}
|
|
// TODO: insert builtin cells here
|
|
Ok(rtlil::SigSpec::Wire(expr_wire_name))
|
|
}
|
|
ExprKind::Literal(lit) => Ok(rtlil::SigSpec::Const(
|
|
todo!(),
|
|
ctx.types.get_width(expr.typ).expect("signal has no size"),
|
|
)),
|
|
}
|
|
}
|
|
|
|
fn lower_comb(
|
|
ctx: &mut Context,
|
|
module: &mut rtlil::Module,
|
|
block: typed_ir::Block,
|
|
) -> Result<(), CompileError> {
|
|
for (num, sig) in block.signals.iter().enumerate() {
|
|
let sig_id = format!("$sig_{}", sig.id.0);
|
|
let port_width = ctx.types.get_width(sig.typ).expect("signal has no size");
|
|
module.add_wire(rtlil::Wire::new(
|
|
sig_id.clone(),
|
|
port_width,
|
|
Some(rtlil::PortOption::Input((num + 1) as i32)),
|
|
));
|
|
}
|
|
|
|
let ret_id = module.make_genid("ret");
|
|
module.add_wire(rtlil::Wire::new(
|
|
ret_id.clone(),
|
|
ctx.types
|
|
.get_width(block.expr.typ)
|
|
.expect("signal has no size"),
|
|
Some(rtlil::PortOption::Output(99)),
|
|
));
|
|
let out_sig = lower_expression(ctx, module, &block.expr)?;
|
|
module.add_connection(&rtlil::SigSpec::Wire(ret_id), &out_sig);
|
|
Ok(())
|
|
}
|
|
|
|
pub fn lower_block(context: &mut Context, block: typed_ir::Block) -> Result<String, CompileError> {
|
|
let mut writer = rtlil::ILWriter::new();
|
|
let mut ir_module = rtlil::Module::new(make_pubid("test"));
|
|
|
|
lower_comb(context, &mut ir_module, block)?;
|
|
|
|
writer.write_line("autoidx 1");
|
|
ir_module.write_rtlil(&mut writer);
|
|
Ok(writer.finish())
|
|
}
|