start lowering proc blocks

This commit is contained in:
NotAFile 2022-01-17 01:15:27 +01:00
parent b8c7d501f6
commit b77fc1a1f9
7 changed files with 136 additions and 41 deletions

View File

@ -6,7 +6,7 @@ module clockdiv_2 (
proc (clk) { proc (clk) {
match (rst) { match (rst) {
0 => out_clk = 0, 0 => out_clk = 0,
1 => out_clk = ~out_clk, 1 => out_clk = ~out_clk
} }
} }
} }

View File

@ -59,6 +59,30 @@ struct Context {
callables: BTreeMap<String, Callable>, callables: BTreeMap<String, Callable>,
} }
fn lower_process(
ctx: &Context,
module: &mut rtlil::Module,
process: &parser::proc::ProcBlock
) -> Result<(), CompileError> {
let sync_cond = rtlil::SyncCond::Posedge((*process.net.fragment()).into());
let sync_rule = rtlil::SyncRule {
cond: sync_cond,
assign: Vec::new()
};
let root_case = rtlil::CaseRule {
assign: vec![],
switches: vec![],
};
let ir_proc = rtlil::Process {
id: module.make_genid("proc"),
root_case,
sync_rules: vec![sync_rule],
};
module.add_process(ir_proc);
Ok(())
}
fn lower_expression( fn lower_expression(
ctx: &Context, ctx: &Context,
module: &mut rtlil::Module, module: &mut rtlil::Module,
@ -99,6 +123,7 @@ fn lower_expression(
Ok(output_gen_id) Ok(output_gen_id)
} }
parser::Expression::Operation(_op) => todo!(), parser::Expression::Operation(_op) => todo!(),
parser::Expression::Literal(_op) => todo!(),
} }
} }
@ -140,7 +165,9 @@ pub fn lower_module(pa_module: parser::Module) -> Result<String, CompileError> {
parser::ModuleItem::Assign(assignment) => { parser::ModuleItem::Assign(assignment) => {
lower_assignment(&context, &mut ir_module, assignment)? lower_assignment(&context, &mut ir_module, assignment)?
} }
parser::ModuleItem::Proc(_proc) => todo!("lowering process"), parser::ModuleItem::Proc(proc) => {
lower_process(&context, &mut ir_module, &proc)?
}
} }
} }
ir_module.write_rtlil(&mut writer); ir_module.write_rtlil(&mut writer);

View File

@ -1,5 +1,5 @@
mod module; pub mod module;
mod proc; pub mod proc;
use nom::{ use nom::{
branch::alt, branch::alt,
@ -63,6 +63,7 @@ pub struct Assign<'a> {
pub enum Operation<'a> { pub enum Operation<'a> {
And { a: String, b: Expression<'a> }, And { a: String, b: Expression<'a> },
Or { a: String, b: Expression<'a> }, Or { a: String, b: Expression<'a> },
Not(Expression<'a>),
} }
#[derive(Debug)] #[derive(Debug)]
@ -74,6 +75,7 @@ pub struct Call<'a> {
#[derive(Debug)] #[derive(Debug)]
pub enum Expression<'a> { pub enum Expression<'a> {
Ident(&'a str), Ident(&'a str),
Literal(u64),
Call(Box<Call<'a>>), Call(Box<Call<'a>>),
Operation(Box<Operation<'a>>), Operation(Box<Operation<'a>>),
} }
@ -111,6 +113,10 @@ fn operation(input: Span) -> IResult<Span, Operation> {
b, b,
}, },
), ),
map(
preceded(char('~'), expression),
|expr| Operation::Not(expr),
),
))(input) ))(input)
} }
@ -130,6 +136,7 @@ fn call_item(input: Span) -> IResult<Span, Call> {
fn expression(input: Span) -> IResult<Span, Expression> { fn expression(input: Span) -> IResult<Span, Expression> {
alt(( alt((
map(ws0(decimal), |lit| Expression::Literal(lit)),
map(ws0(operation), |op| Expression::Operation(Box::new(op))), map(ws0(operation), |op| Expression::Operation(Box::new(op))),
map(ws0(call_item), |call| Expression::Call(Box::new(call))), map(ws0(call_item), |call| Expression::Call(Box::new(call))),
map(ws0(identifier), |ident| { map(ws0(identifier), |ident| {
@ -139,19 +146,12 @@ fn expression(input: Span) -> IResult<Span, Expression> {
} }
fn assign_statement(input: Span) -> IResult<Span, Assign> { fn assign_statement(input: Span) -> IResult<Span, Assign> {
context(
"assignment",
delimited(
ws0(terminated(tag("assign"), multispace1)),
map( map(
separated_pair(ws0(identifier), char('='), ws0(expression)), separated_pair(ws0(identifier), char('='), ws0(expression)),
|(lhs, expr)| Assign { |(lhs, expr)| Assign {
lhs: (*lhs.fragment()), lhs: (*lhs.fragment()),
expr, expr,
}, },
),
ws0(char(';')),
),
)(input) )(input)
} }
@ -162,6 +162,7 @@ pub fn parse(input: Span) -> IResult<Span, Module> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use nom::combinator::all_consuming;
#[test] #[test]
fn test_decl() { fn test_decl() {
@ -183,8 +184,9 @@ mod test {
#[test] #[test]
fn test_assignment() { fn test_assignment() {
assign_statement(" assign a = b ; ".into()).unwrap(); // TODO: make wrapper and use for all tests
assign_statement(" assign a = b | c ; ".into()).unwrap(); all_consuming(assign_statement)(" a = b ".into()).unwrap();
all_consuming(assign_statement)(" a = b | c ".into()).unwrap();
} }
#[test] #[test]

View File

@ -1,11 +1,11 @@
use nom::{ use nom::{
branch::alt, branch::alt,
bytes::complete::tag, bytes::complete::tag,
character::complete::char, character::complete::{char, multispace1},
combinator::{consumed, map}, combinator::{consumed, map},
error::context, error::context,
multi::{many1, separated_list0}, multi::{many1, separated_list0},
sequence::{delimited, tuple}, sequence::{delimited, tuple, terminated},
}; };
use crate::parser::{ use crate::parser::{
@ -60,6 +60,17 @@ fn ports_list(input: Span) -> IResult<Span, Vec<PortDecl>> {
separated_list0(ws0(char(',')), ws0(port_decl))(input) separated_list0(ws0(char(',')), ws0(port_decl))(input)
} }
fn assign_item(input: Span) -> IResult<Span, Assign> {
context(
"assignment",
delimited(
ws0(terminated(tag("assign"), multispace1)),
ws0(assign_statement),
ws0(char(';')),
),
)(input)
}
fn module_item(input: Span) -> IResult<Span, ModuleItem> { fn module_item(input: Span) -> IResult<Span, ModuleItem> {
alt(( alt((
map(assign_statement, ModuleItem::Assign), map(assign_statement, ModuleItem::Assign),

View File

@ -1,13 +1,14 @@
use nom::{ use nom::{
branch::alt,
bytes::complete::tag, bytes::complete::tag,
character::complete::char, character::complete::char,
combinator::map, combinator::map,
error::context, error::context,
multi::many0, multi::{many1, separated_list0, separated_list1},
sequence::{delimited, tuple}, sequence::{delimited, tuple, separated_pair},
}; };
use crate::parser::{identifier, ws0, Expression, IResult, Span}; use crate::parser::{identifier, ws0, expression, Expression, IResult, Span, Assign, assign_statement};
#[derive(Debug)] #[derive(Debug)]
pub struct ProcBlock<'a> { pub struct ProcBlock<'a> {
@ -18,8 +19,9 @@ pub struct ProcBlock<'a> {
#[derive(Debug)] #[derive(Debug)]
pub enum ProcStatement<'a> { pub enum ProcStatement<'a> {
IfElse(IfElseBlock), IfElse(IfElseBlock),
Assign, Assign(Assign<'a>),
Match(MatchBlock<'a>), Match(MatchBlock<'a>),
Block(Vec<ProcStatement<'a>>),
} }
// TODO: postponed because annoying to implement // TODO: postponed because annoying to implement
@ -29,17 +31,41 @@ pub struct IfElseBlock {}
#[derive(Debug)] #[derive(Debug)]
pub struct MatchBlock<'a> { pub struct MatchBlock<'a> {
expr: Expression<'a>, expr: Expression<'a>,
arms: Vec<(&'a str, ProcStatement<'a>)>, arms: Vec<(Expression<'a>, ProcStatement<'a>)>,
}
fn match_arm(input: Span) -> IResult<Span, (Expression, ProcStatement)> {
separated_pair(ws0(expression), tag("=>"), ws0(proc_statement))(input)
}
fn match_block(input: Span) -> IResult<Span, MatchBlock> {
context(
"match block",
map(
tuple((
ws0(tag("match")),
ws0(delimited(char('('), ws0(expression), char(')'))),
ws0(delimited(char('{'), separated_list1(char(','), ws0(match_arm)), char('}'))),
)),
|(_, expr, arms)| MatchBlock {
expr,
arms
},
),
)(input)
}
fn statement_block(input: Span) -> IResult<Span, Vec<ProcStatement>> {
delimited(char('{'), separated_list1(char(';'), ws0(proc_statement)), char('}'))(input)
} }
/// parse a statement that is valid inside a proc block /// parse a statement that is valid inside a proc block
fn proc_statement(input: Span) -> IResult<Span, ProcStatement> { fn proc_statement(input: Span) -> IResult<Span, ProcStatement> {
map(nom::character::complete::anychar, |_| { alt((
ProcStatement::Match(MatchBlock { map(match_block, ProcStatement::Match),
expr: Expression::Ident("asdf"), map(statement_block, ProcStatement::Block),
arms: Vec::new(), map(assign_statement, ProcStatement::Assign),
}) ))(input)
})(input)
} }
pub fn proc_block(input: Span) -> IResult<Span, ProcBlock> { pub fn proc_block(input: Span) -> IResult<Span, ProcBlock> {
@ -49,9 +75,35 @@ pub fn proc_block(input: Span) -> IResult<Span, ProcBlock> {
tuple(( tuple((
ws0(tag("proc")), ws0(tag("proc")),
ws0(delimited(char('('), ws0(identifier), char(')'))), ws0(delimited(char('('), ws0(identifier), char(')'))),
ws0(delimited(char('{'), many0(ws0(proc_statement)), char('}'))), ws0(delimited(char('{'), many1(ws0(proc_statement)), char('}'))),
)), )),
|(_, net, items)| ProcBlock { net, items }, |(_, net, items)| ProcBlock { net, items },
), ),
)(input) )(input)
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_statement() {
proc_statement(" abc = def ".into()).unwrap();
}
#[test]
fn test_match_arm() {
match_arm(" 1 => abc = def ".into()).unwrap();
}
#[test]
fn test_match_block() {
let input = "
match (asdf) {
1 => a = 0,
2 => c = ~d
}
";
match_block(input.into()).unwrap();
}
}

View File

@ -1,6 +1,6 @@
mod sync; mod sync;
use sync::Process; pub use sync::{Process, SyncCond, SyncRule, SwitchRule, CaseRule};
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct ILWriter { pub struct ILWriter {

View File

@ -2,15 +2,15 @@ use crate::rtlil::{RtlilWrite, SigSpec};
#[derive(Debug)] #[derive(Debug)]
pub struct Process { pub struct Process {
id: String, pub id: String,
root_case: CaseRule, pub root_case: CaseRule,
sync_rules: Vec<SyncRule>, pub sync_rules: Vec<SyncRule>,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct CaseRule { pub struct CaseRule {
assign: Vec<(SigSpec, SigSpec)>, pub assign: Vec<(SigSpec, SigSpec)>,
switches: Vec<SwitchRule>, pub switches: Vec<SwitchRule>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -21,8 +21,8 @@ pub struct SwitchRule {
#[derive(Debug)] #[derive(Debug)]
pub struct SyncRule { pub struct SyncRule {
cond: SyncCond, pub cond: SyncCond,
assign: Vec<(SigSpec, SigSpec)>, pub assign: Vec<(SigSpec, SigSpec)>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -35,8 +35,11 @@ pub enum SyncCond {
impl RtlilWrite for Process { impl RtlilWrite for Process {
fn write_rtlil(&self, writer: &mut super::ILWriter) { fn write_rtlil(&self, writer: &mut super::ILWriter) {
writer.write_line(&format!("process {}", self.id)); writer.write_line(&format!("process {}", self.id));
writer.indent();
self.root_case.write_rtlil(writer); self.root_case.write_rtlil(writer);
writer.write_iter(&self.sync_rules); writer.write_iter(&self.sync_rules);
writer.dedent();
writer.write_line("end");
} }
} }