2022-02-20 21:44:58 +00:00
|
|
|
use super::typed_ir;
|
|
|
|
use super::typed_ir::ExprKind;
|
2022-04-05 11:34:48 +00:00
|
|
|
use super::{make_pubid, CompileError, Context};
|
2022-02-06 22:19:55 +00:00
|
|
|
use crate::rtlil;
|
|
|
|
use crate::rtlil::RtlilWrite;
|
|
|
|
|
|
|
|
fn lower_expression(
|
|
|
|
ctx: &Context,
|
|
|
|
module: &mut rtlil::Module,
|
2022-02-20 21:44:58 +00:00
|
|
|
expr: &typed_ir::Expr,
|
2022-02-06 22:19:55 +00:00
|
|
|
) -> Result<rtlil::SigSpec, CompileError> {
|
2022-02-20 21:44:58 +00:00
|
|
|
let expr_width = ctx.types.get_width(expr.typ).expect("signal needs width");
|
2022-02-21 12:04:05 +00:00
|
|
|
let expr_wire_name = format!("$_sig_{}", expr.id.0);
|
2022-02-20 21:44:58 +00:00
|
|
|
let expr_wire = rtlil::Wire::new(expr_wire_name.clone(), expr_width, None);
|
|
|
|
module.add_wire(expr_wire);
|
|
|
|
match &expr.kind {
|
2022-02-21 12:04:05 +00:00
|
|
|
ExprKind::Path(def) => Ok(rtlil::SigSpec::Wire(format!("\\$sig_{}", def.0))),
|
2022-04-04 19:40:08 +00:00
|
|
|
ExprKind::Call(call) => {
|
|
|
|
let args_resolved = call
|
|
|
|
.args
|
2022-02-06 22:19:55 +00:00
|
|
|
.iter()
|
|
|
|
.map(|expr| lower_expression(ctx, module, expr))
|
|
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
|
|
|
2022-04-04 19:40:08 +00:00
|
|
|
let callable = ctx.callables.get(call.called);
|
2022-02-06 22:19:55 +00:00
|
|
|
let cell_id = module.make_genid(callable.name());
|
|
|
|
|
2022-04-04 19:40:08 +00:00
|
|
|
if call.called == ctx.callables.builtins.xor {
|
|
|
|
let a_width = ctx.types.get_width(call.args[0].typ).unwrap();
|
|
|
|
let b_width = ctx.types.get_width(call.args[1].typ).unwrap();
|
2022-02-20 21:44:58 +00:00
|
|
|
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());
|
2022-02-21 12:04:05 +00:00
|
|
|
cell.add_connection("\\A", &args_resolved[0]);
|
|
|
|
cell.add_connection("\\B", &args_resolved[1]);
|
2022-02-20 21:44:58 +00:00
|
|
|
cell.add_connection("\\Y", &rtlil::SigSpec::Wire(expr_wire_name.clone()));
|
|
|
|
module.add_cell(cell);
|
2022-04-04 19:40:08 +00:00
|
|
|
} else if call.called == ctx.callables.builtins.reduce_or {
|
|
|
|
let a_width = ctx.types.get_width(call.args[0].typ).unwrap();
|
2022-02-20 21:44:58 +00:00
|
|
|
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());
|
2022-02-21 12:04:05 +00:00
|
|
|
cell.add_connection("\\A", &args_resolved[0]);
|
2022-02-20 21:44:58 +00:00
|
|
|
cell.add_connection("\\Y", &rtlil::SigSpec::Wire(expr_wire_name.clone()));
|
|
|
|
module.add_cell(cell);
|
2022-04-04 19:40:08 +00:00
|
|
|
} else if call.called == ctx.callables.builtins.bitnot {
|
|
|
|
let a_width = ctx.types.get_width(call.args[0].typ).unwrap();
|
2022-02-20 21:44:58 +00:00
|
|
|
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());
|
2022-02-21 12:04:05 +00:00
|
|
|
cell.add_connection("\\A", &args_resolved[0]);
|
2022-02-20 21:44:58 +00:00
|
|
|
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))
|
2022-02-06 22:19:55 +00:00
|
|
|
}
|
2022-02-20 21:44:58 +00:00
|
|
|
ExprKind::Literal(lit) => Ok(rtlil::SigSpec::Const(
|
2022-04-04 22:02:45 +00:00
|
|
|
ctx.types
|
|
|
|
.elab_as_u32(lit)
|
|
|
|
.expect("const does not fit in 32 bits") as i64,
|
2022-02-20 21:44:58 +00:00
|
|
|
ctx.types.get_width(expr.typ).expect("signal has no size"),
|
2022-02-06 22:19:55 +00:00
|
|
|
)),
|
2022-04-04 22:02:45 +00:00
|
|
|
ExprKind::Match(match_) => {
|
|
|
|
let cases = match_
|
|
|
|
.arms
|
|
|
|
.iter()
|
|
|
|
.map(|(pat, val)| {
|
|
|
|
Ok((
|
|
|
|
lower_expression(ctx, module, pat)?,
|
|
|
|
rtlil::CaseRule {
|
|
|
|
assign: vec![(
|
|
|
|
rtlil::SigSpec::Wire(expr_wire_name.clone()),
|
|
|
|
lower_expression(ctx, module, val)?,
|
|
|
|
)],
|
|
|
|
switches: vec![],
|
|
|
|
},
|
|
|
|
))
|
|
|
|
})
|
|
|
|
.collect::<Result<Vec<_>, CompileError>>()
|
|
|
|
.unwrap();
|
|
|
|
let root_switch = rtlil::SwitchRule {
|
|
|
|
signal: lower_expression(ctx, module, &match_.expr)?,
|
|
|
|
cases,
|
|
|
|
};
|
|
|
|
let root_case = rtlil::CaseRule {
|
|
|
|
assign: vec![],
|
|
|
|
switches: vec![root_switch],
|
|
|
|
};
|
|
|
|
let proc = rtlil::Process {
|
|
|
|
id: module.make_genid("match"),
|
|
|
|
root_case,
|
|
|
|
sync_rules: vec![],
|
|
|
|
};
|
|
|
|
module.add_process(proc);
|
|
|
|
Ok(rtlil::SigSpec::Wire(expr_wire_name))
|
|
|
|
}
|
2022-02-06 22:19:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lower_comb(
|
|
|
|
ctx: &mut Context,
|
|
|
|
module: &mut rtlil::Module,
|
2022-04-04 22:02:45 +00:00
|
|
|
block: &typed_ir::Block,
|
2022-02-06 22:19:55 +00:00
|
|
|
) -> Result<(), CompileError> {
|
2022-02-20 21:44:58 +00:00
|
|
|
for (num, sig) in block.signals.iter().enumerate() {
|
2022-02-21 12:04:05 +00:00
|
|
|
let sig_id = format!("\\$sig_{}", sig.id.0);
|
2022-02-20 21:44:58 +00:00
|
|
|
let port_width = ctx.types.get_width(sig.typ).expect("signal has no size");
|
2022-02-06 22:19:55 +00:00
|
|
|
module.add_wire(rtlil::Wire::new(
|
2022-02-20 21:44:58 +00:00
|
|
|
sig_id.clone(),
|
|
|
|
port_width,
|
2022-02-06 22:19:55 +00:00
|
|
|
Some(rtlil::PortOption::Input((num + 1) as i32)),
|
|
|
|
));
|
|
|
|
}
|
2022-02-20 21:44:58 +00:00
|
|
|
|
2022-02-21 12:04:05 +00:00
|
|
|
let ret_id = make_pubid("ret");
|
2022-02-06 22:19:55 +00:00
|
|
|
module.add_wire(rtlil::Wire::new(
|
|
|
|
ret_id.clone(),
|
2022-02-20 21:44:58 +00:00
|
|
|
ctx.types
|
|
|
|
.get_width(block.expr.typ)
|
|
|
|
.expect("signal has no size"),
|
2022-02-21 12:04:05 +00:00
|
|
|
Some(rtlil::PortOption::Output(block.signals.len() as i32)),
|
2022-02-06 22:19:55 +00:00
|
|
|
));
|
2022-02-20 21:44:58 +00:00
|
|
|
let out_sig = lower_expression(ctx, module, &block.expr)?;
|
2022-02-06 22:19:55 +00:00
|
|
|
module.add_connection(&rtlil::SigSpec::Wire(ret_id), &out_sig);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-04-04 22:02:45 +00:00
|
|
|
pub fn lower_block(context: &mut Context, block: &typed_ir::Block) -> Result<String, CompileError> {
|
2022-02-06 22:19:55 +00:00
|
|
|
let mut writer = rtlil::ILWriter::new();
|
|
|
|
let mut ir_module = rtlil::Module::new(make_pubid("test"));
|
|
|
|
|
2022-02-20 21:44:58 +00:00
|
|
|
lower_comb(context, &mut ir_module, block)?;
|
|
|
|
|
2022-02-06 22:19:55 +00:00
|
|
|
writer.write_line("autoidx 1");
|
|
|
|
ir_module.write_rtlil(&mut writer);
|
|
|
|
Ok(writer.finish())
|
|
|
|
}
|