blif_parser/
parser.rs

1use crate::primitives::*;
2use std::fs;
3use indexmap::IndexMap;
4
5type IResultStr<'a> = IResult<&'a str, &'a str>;
6
7use nom::{
8    bytes::complete::{is_not, tag, take_until},
9    combinator::value,
10    sequence::{pair, terminated},
11    IResult,
12};
13
14fn take_until_or_end<'a>(tag: &'a str, istr: &'a str) -> IResultStr<'a> {
15    let ret: IResult<&str, &str> = take_until(tag)(istr);
16    match ret {
17        Ok(x) => Ok(x),
18        Err(_) => Ok(("", istr)),
19    }
20}
21
22fn terminated_newline<'a>(istr: &'a str) -> IResultStr<'a> {
23    let ret: IResult<&str, &str> =
24        terminated(take_until("\n"), nom::character::complete::newline)(istr);
25    match ret {
26        Ok(x) => Ok(x),
27        Err(_) => Ok(("", istr)),
28    }
29}
30
31fn lut_table_parser<'a>(input: &'a str, table: &mut Vec<Vec<u8>>) -> IResultStr<'a> {
32    let mut i = input;
33    let mut li;
34    let mut te;
35    while i.len() > 0 {
36        (i, li) = terminated_newline(i)?;
37
38        let mut row: Vec<u8> = vec![];
39        let (_, mut table_input) = take_until(" ")(li)?;
40        while table_input.len() > 0 {
41            (table_input, te) = nom::character::complete::one_of("01")(table_input)?;
42            row.push(te.to_digit(10).unwrap() as u8);
43        }
44        table.push(row);
45    }
46    Ok(("", ""))
47}
48
49fn lut_body_parser<'a>(input: &'a str, luts: &mut Vec<ParsedPrimitive>) -> IResultStr<'a> {
50    let (i, ioline) = terminated_newline(input)?;
51    let mut io: Vec<&str> = ioline.split(' ').collect();
52
53    let output = io.pop().unwrap_or("INVALID_OUTPUT").to_string();
54    let inputs: Vec<String> = io.iter().map(|v| v.to_string()).collect();
55    let (i, table) = take_until_or_end(".", i)?;
56
57    let mut lut_table = vec![];
58    let _ = lut_table_parser(table, &mut lut_table);
59
60    luts.push(ParsedPrimitive::Lut {
61        inputs: inputs,
62        output: output,
63        table: lut_table
64    });
65
66    Ok((i, ""))
67}
68
69fn subckt_parser<'a>(input: &'a str, subckts: &mut Vec<ParsedPrimitive>) -> IResultStr<'a> {
70    let (i, sline) = terminated_newline(input)?;
71    let conns_vec: Vec<&str> = sline.split(' ').collect();
72    let name = conns_vec[0];
73
74    let mut conns = IndexMap::new();
75    conns_vec.iter().skip(1).for_each(|c| {
76        let lr: Vec<&str> = c.split('=').collect();
77        let lhs = lr[0];
78        let rhs = lr[1];
79        conns.insert(lhs.to_string(), rhs.to_string());
80    });
81
82    subckts.push(ParsedPrimitive::Subckt {
83        name: name.to_string(),
84        conns: conns,
85    });
86
87    Ok((i, ""))
88}
89
90// _SDFF_NP0_ : FF with reset C D Q R
91// _DFFE_PN_  : FF with enables C D E Q
92// _SDFFE_PP0N_ : FF with reset and enable C D E Q R
93fn gate_parser<'a>(input: &'a str, gates: &mut Vec<ParsedPrimitive>) -> IResultStr<'a> {
94    let (i, line) = terminated_newline(input)?;
95
96    let signal_conns: Vec<&str> = line.split(' ').collect();
97    let mut c = "".to_string();
98    let mut d = "".to_string();
99    let mut q = "".to_string();
100    let mut r = None;
101    let mut e = None;
102
103    for sc in signal_conns.iter() {
104        let x: Vec<&str> = sc.split('=').collect();
105        if x.len() != 2 {
106            continue;
107        }
108        match x[0] {
109            "C" => {
110                c = x[1].to_string();
111            }
112            "D" => {
113                d = x[1].to_string();
114            }
115            "Q" => {
116                q = x[1].to_string();
117            }
118            "R" => {
119                r = Some(x[1].to_string());
120            }
121            "E" => {
122                e = Some(x[1].to_string());
123            }
124            _ => {}
125        }
126    }
127
128    gates.push(ParsedPrimitive::Gate { c: c, d: d, q: q, r: r, e: e });
129    Ok((i, ""))
130}
131
132fn latch_parser<'a>(input: &'a str, latches: &mut Vec<ParsedPrimitive>) -> IResultStr<'a> {
133    let (i, line) = terminated_newline(input)?;
134    let latch_info: Vec<&str> = line.split(' ').collect();
135
136    let mut input = "".to_string();
137    let mut output = "".to_string();
138    let mut control = "".to_string();
139    let mut init = LatchInit::UNKNOWN;
140
141    for (idx, li) in latch_info.iter().enumerate() {
142        match idx {
143            0 => {
144                input = li.to_string();
145            }
146            1 => {
147                output = li.to_string();
148            }
149            3 => {
150                control = li.to_string();
151            }
152            4 => {
153                init = LatchInit::to_enum(li);
154            }
155            _ => {}
156        }
157    }
158    match init {
159        LatchInit::ONE =>
160            assert!(false, "Chisel RegInits changes the LUTs not the latch inputs"),
161        _ =>
162            ()
163    }
164    latches.push(ParsedPrimitive::Latch { input: input, output: output, control: control, init: init });
165    Ok((i, ""))
166}
167
168fn module_body_parser<'a>(input: &'a str, modules: &mut Vec<ParsedPrimitive>) -> IResultStr<'a> {
169    let body_end_marker = "\n.end\n";
170
171    // Get module body
172    let (i, _) = tag(".model ")(input)?;
173    let (i, name) = terminated(take_until("\n"), nom::character::complete::newline)(i)?;
174    let (mut i, body) = terminated(
175        take_until(body_end_marker),
176        nom::character::complete::newline,
177    )(i)?;
178
179    // Parse inputs
180    let (bi, iline) = terminated(take_until("\n"), nom::character::complete::newline)(body)?;
181    let inputs: Vec<String> = iline.split(' ').map(|v| v.to_string()).skip(1).collect();
182
183    // Parse outputs
184    let (bi, oline) = terminated(take_until("\n"), nom::character::complete::newline)(bi)?;
185    let outputs: Vec<String> = oline.split(' ').map(|v| v.to_string()).skip(1).collect();
186
187    let mut elems = vec![];
188    let mut bi = bi;
189    let mut tagstr;
190
191    while bi.len() > 1 {
192        (bi, tagstr) = terminated(take_until(" "), nom::character::complete::multispace0)(bi)?;
193        if tagstr.eq(".names") {
194            (bi, _) = lut_body_parser(bi, &mut elems)?;
195        } else if tagstr.eq(".subckt") {
196            (bi, _) = subckt_parser(bi, &mut elems)?;
197        } else if tagstr.eq(".gate") {
198            (bi, _) = gate_parser(bi, &mut elems)?;
199        } else if tagstr.eq(".latch") {
200            (bi, _) = latch_parser(bi, &mut elems)?;
201        }
202    }
203
204    if i.len() > body_end_marker.to_string().len() {
205        // Advance to the next .end
206        (i, _) = take_until(".")(i)?;
207    } else {
208        // End of file
209        (i, _) = take_until("\n")(i)?;
210    }
211
212    modules.push(ParsedPrimitive::Module {
213        name: name.to_string(),
214        inputs: inputs,
215        outputs: outputs,
216        elems: elems
217    });
218
219    Ok((i, ""))
220}
221
222fn parse_modules_from_blif_str<'a>(input: &'a str, circuit: &mut Vec<ParsedPrimitive>) -> IResultStr<'a> {
223    // remove comment
224    let (i, _) = value((), pair(tag("#"), is_not("\n")))(input)?;
225    let (i, _) = take_until(".")(i)?;
226
227    let mut i = i;
228    while i.len() > 4 {
229        (i, _) = module_body_parser(i, circuit)?;
230        (i, _) = take_until_or_end("\n.model", i)?;
231        (i, _) = terminated_newline(i)?;
232    }
233
234    Ok(("", ""))
235}
236
237fn parse_blif(input: &str) -> Result<Vec<ParsedPrimitive>, String> {
238    let mut circuit = vec![];
239    let res = parse_modules_from_blif_str(input, &mut circuit);
240    match res {
241        Ok(_) => {
242            return Ok(circuit);
243        }
244        Err(e) => {
245            return Err(format!("Error while parsing:\n{}", e).to_string());
246        }
247    }
248}
249
250pub fn parse_blif_file(input_file_path: &str) -> Result<Vec<ParsedPrimitive>, String> {
251    let blif_file = fs::read_to_string(input_file_path);
252    match blif_file {
253        Ok(blif_str) => {
254            return parse_blif(&blif_str);
255        }
256        Err(e) => {
257            return Err(format!("Error while reading the file:\n{}", e).to_string());
258        }
259    }
260}
261
262#[cfg(test)]
263pub mod parser_tests {
264    use super::*;
265
266    pub fn test_blif_parser(file_path: &str) -> bool {
267        let res = parse_blif_file(&file_path);
268        match res {
269            Ok(_) => true,
270            Err(err) => {
271                println!("blif file parsing error:\n{}", err);
272                false
273            }
274        }
275    }
276
277    #[test]
278    pub fn test_adder_parse() {
279        assert_eq!(test_blif_parser("./tests/Adder.lut.blif"), true);
280    }
281
282    #[test]
283    pub fn test_gcd_parse() {
284        assert_eq!(test_blif_parser("./tests/GCD.lut.blif"), true);
285    }
286
287    #[test]
288    pub fn test_const_parse() {
289        assert_eq!(test_blif_parser("./tests/Const.lut.blif"), true);
290    }
291}