make operators work via desugaring

main
NotAFile 2022-01-17 19:20:51 +01:00
parent 95d9313cdd
commit 057511f56c
6 changed files with 65 additions and 10 deletions

View File

@ -4,9 +4,9 @@ module clockdiv_2 (
output wire out_clk
) {
proc (clk) {
match (not(rst)) {
match (~rst) {
0 => out_clk = 0,
1 => out_clk = not(out_clk)
1 => out_clk = ~out_clk
}
}
}

View File

@ -3,5 +3,5 @@ module comparator (
input wire [8] b,
output wire eq
) {
assign eq = not(reduce_or(xor(a, b)));
assign eq = ~reduce_or(a ^ b);
}

View File

@ -5,6 +5,6 @@ module halfadd (
output wire carry
)
{
assign sum = xor(a, b);
assign carry = and(a, b);
assign sum = a ^ b;
assign carry = a & b;
}

View File

@ -77,5 +77,6 @@ pub fn get_builtins() -> Vec<Callable> {
make_binop_callable("xor", "$xor"),
make_binop_callable("xnor", "$xnor"),
make_unnop_callable("not", "$not"),
make_unnop_callable("reduce_or", "$reduce_or"),
]
}

View File

@ -140,11 +140,64 @@ fn lower_process(
Ok(())
}
fn desugar_operation<'a>(op: parser::Operation<'a>) -> parser::Call<'a> {
match op {
parser::Operation::And { a, b } => {
let a = desugar_expression(a);
let b = desugar_expression(b);
parser::Call {
name: "and".into(),
args: vec![a, b]
}
},
parser::Operation::Or { a, b } => {
let a = desugar_expression(a);
let b = desugar_expression(b);
parser::Call {
name: "or".into(),
args: vec![a, b]
}
}
parser::Operation::Xor { a, b } => {
let a = desugar_expression(a);
let b = desugar_expression(b);
parser::Call {
name: "xor".into(),
args: vec![a, b]
}
}
parser::Operation::Not(a) => {
let a = desugar_expression(a);
parser::Call {
name: "not".into(),
args: vec![a]
}
}
}
}
fn desugar_expression<'a>(expr: parser::Expression<'a>) -> parser::Expression<'a> {
// TODO: allow ergonomic traversal of AST
match expr {
parser::Expression::Ident(_) => expr,
parser::Expression::Literal(_) => expr,
parser::Expression::Call(mut call) => {
let new_args = call.args.into_iter().map(|argex| desugar_expression(argex)).collect();
call.args = new_args;
parser::Expression::Call(call)
},
parser::Expression::Operation(op) => {
parser::Expression::Call(Box::new(desugar_operation(*op)))
},
}
}
fn lower_expression(
ctx: &Context,
module: &mut rtlil::Module,
expr: &parser::Expression,
) -> Result<rtlil::SigSpec, CompileError> {
let expr = desugar_expression(expr.clone());
match expr {
parser::Expression::Ident(ident) => Ok(rtlil::SigSpec::Wire(make_pubid(ident))),
parser::Expression::Call(call) => {
@ -181,9 +234,10 @@ fn lower_expression(
module.add_cell(cell);
Ok(output_gen_wire)
}
// operations should really just desugar to callables
// TODO: instantiate operators directly here instead of desugaring, once the callable infrastructure improves
// to get better errors
parser::Expression::Operation(_op) => todo!("operators not yet implemented"),
parser::Expression::Literal(lit) => Ok(rtlil::SigSpec::Const(*lit as i64, TODO_WIDTH)),
parser::Expression::Literal(lit) => Ok(rtlil::SigSpec::Const(lit as i64, TODO_WIDTH)),
}
}

View File

@ -59,7 +59,7 @@ pub struct Assign<'a> {
pub expr: Expression<'a>,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum Operation<'a> {
And {
a: Expression<'a>,
@ -76,13 +76,13 @@ pub enum Operation<'a> {
Not(Expression<'a>),
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Call<'a> {
pub name: Span<'a>,
pub args: Vec<Expression<'a>>,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum Expression<'a> {
Ident(&'a str),
Literal(u64),