diff --git a/doc/examples/clockdiv.fut b/doc/examples/clockdiv.fut index 94960b4..236ea8b 100644 --- a/doc/examples/clockdiv.fut +++ b/doc/examples/clockdiv.fut @@ -6,7 +6,7 @@ module clockdiv_2 ( proc (clk) { match (rst) { 0 => out_clk = 0, - 1 => out_clk = ~out_clk, + 1 => out_clk = ~out_clk } } } diff --git a/src/frontend.rs b/src/frontend.rs index d805f56..a02b8ae 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -59,6 +59,30 @@ struct Context { callables: BTreeMap, } + +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( ctx: &Context, module: &mut rtlil::Module, @@ -99,6 +123,7 @@ fn lower_expression( Ok(output_gen_id) } parser::Expression::Operation(_op) => todo!(), + parser::Expression::Literal(_op) => todo!(), } } @@ -140,7 +165,9 @@ pub fn lower_module(pa_module: parser::Module) -> Result { parser::ModuleItem::Assign(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); diff --git a/src/parser.rs b/src/parser.rs index af03e33..9207d38 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,5 @@ -mod module; -mod proc; +pub mod module; +pub mod proc; use nom::{ branch::alt, @@ -63,6 +63,7 @@ pub struct Assign<'a> { pub enum Operation<'a> { And { a: String, b: Expression<'a> }, Or { a: String, b: Expression<'a> }, + Not(Expression<'a>), } #[derive(Debug)] @@ -74,6 +75,7 @@ pub struct Call<'a> { #[derive(Debug)] pub enum Expression<'a> { Ident(&'a str), + Literal(u64), Call(Box>), Operation(Box>), } @@ -111,6 +113,10 @@ fn operation(input: Span) -> IResult { b, }, ), + map( + preceded(char('~'), expression), + |expr| Operation::Not(expr), + ), ))(input) } @@ -130,6 +136,7 @@ fn call_item(input: Span) -> IResult { fn expression(input: Span) -> IResult { alt(( + map(ws0(decimal), |lit| Expression::Literal(lit)), map(ws0(operation), |op| Expression::Operation(Box::new(op))), map(ws0(call_item), |call| Expression::Call(Box::new(call))), map(ws0(identifier), |ident| { @@ -139,19 +146,12 @@ fn expression(input: Span) -> IResult { } fn assign_statement(input: Span) -> IResult { - context( - "assignment", - delimited( - ws0(terminated(tag("assign"), multispace1)), - map( - separated_pair(ws0(identifier), char('='), ws0(expression)), - |(lhs, expr)| Assign { - lhs: (*lhs.fragment()), - expr, - }, - ), - ws0(char(';')), - ), + map( + separated_pair(ws0(identifier), char('='), ws0(expression)), + |(lhs, expr)| Assign { + lhs: (*lhs.fragment()), + expr, + }, )(input) } @@ -162,6 +162,7 @@ pub fn parse(input: Span) -> IResult { #[cfg(test)] mod test { use super::*; + use nom::combinator::all_consuming; #[test] fn test_decl() { @@ -183,8 +184,9 @@ mod test { #[test] fn test_assignment() { - assign_statement(" assign a = b ; ".into()).unwrap(); - assign_statement(" assign a = b | c ; ".into()).unwrap(); + // TODO: make wrapper and use for all tests + all_consuming(assign_statement)(" a = b ".into()).unwrap(); + all_consuming(assign_statement)(" a = b | c ".into()).unwrap(); } #[test] diff --git a/src/parser/module.rs b/src/parser/module.rs index 869120e..fe1e676 100644 --- a/src/parser/module.rs +++ b/src/parser/module.rs @@ -1,11 +1,11 @@ use nom::{ branch::alt, bytes::complete::tag, - character::complete::char, + character::complete::{char, multispace1}, combinator::{consumed, map}, error::context, multi::{many1, separated_list0}, - sequence::{delimited, tuple}, + sequence::{delimited, tuple, terminated}, }; use crate::parser::{ @@ -60,6 +60,17 @@ fn ports_list(input: Span) -> IResult> { separated_list0(ws0(char(',')), ws0(port_decl))(input) } +fn assign_item(input: Span) -> IResult { + context( + "assignment", + delimited( + ws0(terminated(tag("assign"), multispace1)), + ws0(assign_statement), + ws0(char(';')), + ), + )(input) +} + fn module_item(input: Span) -> IResult { alt(( map(assign_statement, ModuleItem::Assign), diff --git a/src/parser/proc.rs b/src/parser/proc.rs index 0d69bef..8ec34e4 100644 --- a/src/parser/proc.rs +++ b/src/parser/proc.rs @@ -1,13 +1,14 @@ use nom::{ + branch::alt, bytes::complete::tag, character::complete::char, combinator::map, error::context, - multi::many0, - sequence::{delimited, tuple}, + multi::{many1, separated_list0, separated_list1}, + 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)] pub struct ProcBlock<'a> { @@ -18,8 +19,9 @@ pub struct ProcBlock<'a> { #[derive(Debug)] pub enum ProcStatement<'a> { IfElse(IfElseBlock), - Assign, + Assign(Assign<'a>), Match(MatchBlock<'a>), + Block(Vec>), } // TODO: postponed because annoying to implement @@ -29,17 +31,41 @@ pub struct IfElseBlock {} #[derive(Debug)] pub struct MatchBlock<'a> { expr: Expression<'a>, - arms: Vec<(&'a str, ProcStatement<'a>)>, + arms: Vec<(Expression<'a>, ProcStatement<'a>)>, +} + +fn match_arm(input: Span) -> IResult { + separated_pair(ws0(expression), tag("=>"), ws0(proc_statement))(input) +} + +fn match_block(input: Span) -> IResult { + 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> { + delimited(char('{'), separated_list1(char(';'), ws0(proc_statement)), char('}'))(input) } /// parse a statement that is valid inside a proc block fn proc_statement(input: Span) -> IResult { - map(nom::character::complete::anychar, |_| { - ProcStatement::Match(MatchBlock { - expr: Expression::Ident("asdf"), - arms: Vec::new(), - }) - })(input) + alt(( + map(match_block, ProcStatement::Match), + map(statement_block, ProcStatement::Block), + map(assign_statement, ProcStatement::Assign), + ))(input) } pub fn proc_block(input: Span) -> IResult { @@ -49,9 +75,35 @@ pub fn proc_block(input: Span) -> IResult { tuple(( ws0(tag("proc")), 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 }, ), )(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(); + } +} diff --git a/src/rtlil.rs b/src/rtlil.rs index 28cb98f..4121b84 100644 --- a/src/rtlil.rs +++ b/src/rtlil.rs @@ -1,6 +1,6 @@ mod sync; -use sync::Process; +pub use sync::{Process, SyncCond, SyncRule, SwitchRule, CaseRule}; #[derive(Debug, Default)] pub struct ILWriter { diff --git a/src/rtlil/sync.rs b/src/rtlil/sync.rs index 2b9e9e6..d380b06 100644 --- a/src/rtlil/sync.rs +++ b/src/rtlil/sync.rs @@ -2,15 +2,15 @@ use crate::rtlil::{RtlilWrite, SigSpec}; #[derive(Debug)] pub struct Process { - id: String, - root_case: CaseRule, - sync_rules: Vec, + pub id: String, + pub root_case: CaseRule, + pub sync_rules: Vec, } #[derive(Debug)] pub struct CaseRule { - assign: Vec<(SigSpec, SigSpec)>, - switches: Vec, + pub assign: Vec<(SigSpec, SigSpec)>, + pub switches: Vec, } #[derive(Debug)] @@ -21,8 +21,8 @@ pub struct SwitchRule { #[derive(Debug)] pub struct SyncRule { - cond: SyncCond, - assign: Vec<(SigSpec, SigSpec)>, + pub cond: SyncCond, + pub assign: Vec<(SigSpec, SigSpec)>, } #[derive(Debug)] @@ -35,8 +35,11 @@ pub enum SyncCond { impl RtlilWrite for Process { fn write_rtlil(&self, writer: &mut super::ILWriter) { writer.write_line(&format!("process {}", self.id)); + writer.indent(); self.root_case.write_rtlil(writer); writer.write_iter(&self.sync_rules); + writer.dedent(); + writer.write_line("end"); } }