Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tests/AdderTwoMod.blif eol=crlf
41 changes: 26 additions & 15 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ type IResultStr<'a> = IResult<&'a str, &'a str>;

use nom::{
bytes::complete::{is_not, tag, take_until},
branch::alt,
combinator::value,
sequence::{pair, terminated},
IResult,
};

const MODULE_END_UNIX: &'static str = "\n.end\n";
const MODULE_END_WINDOWS: &'static str = "\r\n.end\r\n";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is undesirable to have global constants embedded in the file.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced with local constants; only used in one function


pub fn take_until_newline(input: &str) -> IResult<&str, &str> {
alt((take_until("\r\n"), take_until("\n")))(input)
}

fn take_until_or_end<'a>(tag: &'a str, istr: &'a str) -> IResultStr<'a> {
let ret: IResult<&str, &str> = take_until(tag)(istr);
match ret {
Expand All @@ -20,8 +28,7 @@ fn take_until_or_end<'a>(tag: &'a str, istr: &'a str) -> IResultStr<'a> {
}

fn terminated_newline<'a>(istr: &'a str) -> IResultStr<'a> {
let ret: IResult<&str, &str> =
terminated(take_until("\n"), nom::character::complete::newline)(istr);
let ret: IResult<&str, &str> = terminated(take_until_newline, nom::character::complete::line_ending)(istr);
match ret {
Ok(x) => Ok(x),
Err(_) => Ok(("", istr)),
Expand Down Expand Up @@ -166,22 +173,20 @@ fn latch_parser<'a>(input: &'a str, latches: &mut Vec<ParsedPrimitive>) -> IResu
}

fn module_body_parser<'a>(input: &'a str, modules: &mut Vec<ParsedPrimitive>) -> IResultStr<'a> {
let body_end_marker = "\n.end\n";

// Get module body
let (i, _) = tag(".model ")(input)?;
let (i, name) = terminated(take_until("\n"), nom::character::complete::newline)(i)?;
let (i, name) = terminated(take_until_newline, nom::character::complete::line_ending)(i)?;
let (mut i, body) = terminated(
take_until(body_end_marker),
nom::character::complete::newline,
alt((take_until(MODULE_END_WINDOWS), take_until(MODULE_END_UNIX))),
nom::character::complete::line_ending,
)(i)?;

// Parse inputs
let (bi, iline) = terminated(take_until("\n"), nom::character::complete::newline)(body)?;
let (bi, iline) = terminated(take_until_newline, nom::character::complete::line_ending)(body)?;
let inputs: Vec<String> = iline.split(' ').map(|v| v.to_string()).skip(1).collect();

// Parse outputs
let (bi, oline) = terminated(take_until("\n"), nom::character::complete::newline)(bi)?;
let (bi, oline) = terminated(take_until_newline, nom::character::complete::line_ending)(bi)?;
let outputs: Vec<String> = oline.split(' ').map(|v| v.to_string()).skip(1).collect();

let mut elems = vec![];
Expand All @@ -201,12 +206,12 @@ fn module_body_parser<'a>(input: &'a str, modules: &mut Vec<ParsedPrimitive>) ->
}
}

if i.len() > body_end_marker.to_string().len() {
if i.len() > MODULE_END_UNIX.len() {
// Advance to the next .end
(i, _) = take_until(".")(i)?;
} else {
// End of file
(i, _) = take_until("\n")(i)?;
(i, _) = take_until_newline(i)?;
}

modules.push(ParsedPrimitive::Module {
Expand All @@ -221,20 +226,21 @@ fn module_body_parser<'a>(input: &'a str, modules: &mut Vec<ParsedPrimitive>) ->

fn parse_modules_from_blif_str<'a>(input: &'a str, circuit: &mut Vec<ParsedPrimitive>) -> IResultStr<'a> {
// remove comment
let (i, _) = value((), pair(tag("#"), is_not("\n")))(input)?;
// is_not will stop before \r or \n
let (i, _) = value((), pair(tag("#"), is_not("\r\n")))(input)?;
let (i, _) = take_until(".")(i)?;

let mut i = i;
while i.len() > 4 {
(i, _) = module_body_parser(i, circuit)?;
(i, _) = take_until_or_end("\n.model", i)?;
(i, _) = terminated_newline(i)?;
(i, _) = take_until_or_end("\n", i)?;
(i, _) = take_until_or_end(".model", i)?;
}

Ok(("", ""))
}

fn parse_blif(input: &str) -> Result<Vec<ParsedPrimitive>, String> {
pub fn parse_blif(input: &str) -> Result<Vec<ParsedPrimitive>, String> {
let mut circuit = vec![];
let res = parse_modules_from_blif_str(input, &mut circuit);
match res {
Expand Down Expand Up @@ -279,6 +285,11 @@ pub mod parser_tests {
assert_eq!(test_blif_parser("./tests/Adder.lut.blif"), true);
}

#[test]
pub fn test_adder_two_mod_parse() {
assert_eq!(test_blif_parser("./tests/AdderTwoMod.blif"), true);
}

#[test]
pub fn test_gcd_parse() {
assert_eq!(test_blif_parser("./tests/GCD.lut.blif"), true);
Expand Down
24 changes: 24 additions & 0 deletions tests/AdderTwoMod.blif
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Yosys 0.59+134 (git sha1 9871e9b17, x86_64-w64-mingw32-g++ 13.2.1 -O3)

.model full_add
.inputs a b cin
.outputs sum cout
.names $false
.names $true
1
.names $undef
.subckt OR A=y B=z Y=cout
.subckt half_add a=a b=b c=y s=x
.subckt half_add a=x b=cin c=z s=sum
.end

.model half_add
.inputs a b
.outputs s c
.names $false
.names $true
1
.names $undef
.subckt AND A=a B=b Y=c
.subckt XOR A=a B=b Y=s
.end