diff --git a/doc/examples/clockdiv.fut b/doc/examples/clockdiv.fut new file mode 100644 index 0000000..94960b4 --- /dev/null +++ b/doc/examples/clockdiv.fut @@ -0,0 +1,12 @@ +module clockdiv_2 ( + input wire clk, + input wire rst, + output wire out_clk +) { + proc (clk) { + match (rst) { + 0 => out_clk = 0, + 1 => out_clk = ~out_clk, + } + } +} diff --git a/src/frontend.rs b/src/frontend.rs index ca6589d..704f72d 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -135,11 +135,12 @@ pub fn lower_module(pa_module: parser::Module) -> Result { ); ir_module.add_wire(wire); } - for stmt in pa_module.statements { - match stmt { - parser::Statement::Assign(assignment) => { + for item in pa_module.items { + match item { + parser::ModuleItem::Assign(assignment) => { lower_assignment(&context, &mut ir_module, assignment)? } + parser::ModuleItem::Proc(proc) => todo!("lowering process") } } ir_module.write_rtlil(&mut writer); diff --git a/src/main.rs b/src/main.rs index d2a9e8c..af238c3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ use std::fs::File; use std::io::prelude::*; use std::path::PathBuf; use structopt::StructOpt; +use nom::error::convert_error; #[derive(Debug, StructOpt)] #[structopt(name = "example", about = "An example of StructOpt usage.")] @@ -28,9 +29,10 @@ fn main() { let input = parser::Span::new(input); let parsed = parser::parse(input); match parsed { - Err(nom::Err::Error(_err) | nom::Err::Failure(_err)) => { - // TODO: get this working again - // print!("{}", convert_error(input, err)) + Err(nom::Err::Error(err) | nom::Err::Failure(err)) => { + // TODO: get pretty errors again + // print!("{}", convert_error(*input, err)) + print!("{}", err); } Err(_) => (), Ok(res) => { diff --git a/src/parser.rs b/src/parser.rs index a70a738..81e5de8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -66,12 +66,37 @@ pub struct PortDecl<'a> { pub struct Module<'a> { pub name: &'a str, pub ports: Vec>, - pub statements: Vec>, + pub items: Vec>, } #[derive(Debug)] -pub enum Statement<'a> { +pub enum ModuleItem<'a> { Assign(Assign<'a>), + Proc(ProcBlock<'a>), +} + +#[derive(Debug)] +pub struct ProcBlock<'a> { + pub net: Span<'a>, + pub items: Vec>, +} + +#[derive(Debug)] +pub enum ProcStatement<'a> { + IfElse(IfElseBlock), + Assign, + Match(MatchBlock<'a>), +} + +// TODO: postponed because annoying to implement +#[derive(Debug)] +pub struct IfElseBlock { +} + +#[derive(Debug)] +pub struct MatchBlock<'a> { + expr: Expression<'a>, + arms: Vec<(&'a str, ProcStatement<'a>)> } #[derive(Debug)] @@ -180,7 +205,7 @@ fn expression(input: Span) -> IResult { ))(input) } -fn assign_statement(input: Span) -> IResult { +fn assign_statement(input: Span) -> IResult { context( "assignment", delimited( @@ -188,10 +213,10 @@ fn assign_statement(input: Span) -> IResult { map( separated_pair(ws0(identifier), char('='), ws0(expression)), |(lhs, expr)| { - Statement::Assign(Assign { + Assign { lhs: (*lhs.fragment()), expr, - }) + } }, ), ws0(char(';')), @@ -199,6 +224,47 @@ fn assign_statement(input: Span) -> IResult { )(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) +} + +fn proc_block(input: Span) -> IResult { + context( + "proc block", + map( + tuple(( + ws0(tag("proc")), + ws0(delimited(char('('), ws0(identifier), char(')'))), + ws0(delimited(char('{'), many0(ws0(proc_statement)), char('}'))) + )), + |(_, net, items)| { + ProcBlock { + net, + items, + } + } + ) + )(input) + +} + +fn module_item(input: Span) -> IResult { + alt(( + map(assign_statement, |assig| ModuleItem::Assign(assig)), + map(proc_block, |proc| ModuleItem::Proc(proc)), + ))(input) +} + +/// parse a top-level module declaration pub fn module(input: Span) -> IResult { context( "module", @@ -209,14 +275,14 @@ pub fn module(input: Span) -> IResult { ws0(delimited(char('('), ws0(ports_list), char(')'))), ws0(delimited( char('{'), - many1(ws0(assign_statement)), + many1(ws0(module_item)), char('}'), )), )), - |(_, name, ports, statements)| Module { + |(_, name, ports, items)| Module { name: (*name.fragment()), ports, - statements, + items, }, ), )(input) diff --git a/src/rtlil.rs b/src/rtlil.rs index 0107c72..5495208 100644 --- a/src/rtlil.rs +++ b/src/rtlil.rs @@ -1,5 +1,7 @@ mod sync; +use sync::Process; + #[derive(Debug, Default)] pub struct ILWriter { data: String, @@ -120,6 +122,7 @@ pub struct Module { name: String, wires: Vec, cells: Vec, + processes: Vec, connections: Vec<(SigSpec, SigSpec)>, gen_id: i32, } @@ -131,6 +134,7 @@ impl Module { wires: Default::default(), cells: Default::default(), connections: Default::default(), + processes: Default::default(), gen_id: 0, } } @@ -147,6 +151,10 @@ impl Module { self.cells.push(cell) } + pub fn add_process(&mut self, proc: Process) { + self.processes.push(proc) + } + pub fn make_genid(&mut self, stem: &str) -> String { let res = format!("${}${}", stem, self.gen_id); self.gen_id += 1; @@ -160,6 +168,7 @@ impl RtlilWrite for Module { writer.indent(); writer.write_iter(&self.wires); writer.write_iter(&self.cells); + writer.write_iter(&self.processes); for conn in &self.connections { writer.write_line(&format!("connect {} {}", conn.0, conn.1)) } diff --git a/src/rtlil/sync.rs b/src/rtlil/sync.rs index ff34991..2b9e9e6 100644 --- a/src/rtlil/sync.rs +++ b/src/rtlil/sync.rs @@ -1,26 +1,31 @@ use crate::rtlil::{RtlilWrite, SigSpec}; +#[derive(Debug)] pub struct Process { id: String, root_case: CaseRule, sync_rules: Vec, } +#[derive(Debug)] pub struct CaseRule { assign: Vec<(SigSpec, SigSpec)>, switches: Vec, } +#[derive(Debug)] pub struct SwitchRule { signal: String, cases: Vec, } +#[derive(Debug)] pub struct SyncRule { cond: SyncCond, assign: Vec<(SigSpec, SigSpec)>, } +#[derive(Debug)] pub enum SyncCond { Always, Posedge(String),