This commit is contained in:
2025-08-26 20:47:30 +02:00
parent 7e9c488412
commit f23ab17926
4 changed files with 148 additions and 13 deletions

View File

@@ -2,6 +2,7 @@
low-memory-usage BLIF (berkeley logic interchange format) parser.
## Comparison with other parsers
| | this | SIS | yosys | abc | [pip blifparser] | [lorina] | [crates.io blif-parser] | [quaigh] | [libblifparse] | [spydrnet] |
| ------------------------------------------- | ---- | --- | ----- | --- | ---------------- | -------- | ----------------------- | -------- | -------------- | ---------- |
| top module, latches, LUTs | x | x | x | x | x | x | x | x | x | x |
@@ -15,7 +16,7 @@ low-memory-usage BLIF (berkeley logic interchange format) parser.
| sub-file references | x | x | ? | - | x | - | - | - | - | - |
| finite state machines (`.start_kiss`) | x | x | - | - | x | - | - | - | - | - |
| clock constraints (mostly for simulation) | soon | x | - | - | - | - | - | - | - | - |
| delay constraints | soon | x | - | x | - | - | - | - | - | - |
| delay constraints | soon | x | - | ~ | - | - | - | - | - | - |
| full BLIF specification [^1] | soon | x | - | - | - | - | - | - | - | - |
| extension: "Black- & White-boxes" [^2] | soon | - | - | - | - | - | - | - | - | - |
| extension: `.blackbox` | soon | - | x | x | - | - | - | - | x | x |
@@ -23,7 +24,7 @@ low-memory-usage BLIF (berkeley logic interchange format) parser.
| extension: `.attr` and `.param` (EBLIF[^3]) | x | - | x | - | - | - | - | - | x | x |
| extension: `.conn` (EBLIF[^3]) | x | - | x | - | - | - | - | - | x | x |
| extension: `.barbuff` (identical: `.conn`) | x | - | x | - | - | - | - | - | - | - |
| extension: `.and_gate_delay` | soon | - | - | x | - | - | - | - | - | - |
[^1]: https://people.eecs.berkeley.edu/~alanmi/publications/other/blif.pdf
@@ -37,11 +38,13 @@ low-memory-usage BLIF (berkeley logic interchange format) parser.
[libblifparse]: https://github.com/verilog-to-routing/libblifparse
[spydrnet]: https://github.com/byuccl/spydrnet
- the latest BLIF specification (dated July 28, 1992)
- all yosys BLIF extensions
(supports reading of BLIF files generated with `write_blif -iname -iattr -param -cname -blackbox -attr -conn`)
- KISS state machines (which yosys doesn't even support)
- clock and delay constraints (yosys just ignores those)
If you found a program that generates non-standard BLIF attributes or keywords, please open a GitHub issue.
## Tested with BLIF generators
- yosys `write_blif`, including all supported extensions: `write_blif -iname -iattr -param -cname -blackbox -attr -conn`
- abc write blif
## Goals
- parse every BLIF file in existence
If you found a program that generates or consists of non-standard BLIF attributes or keywords, please open a GitHub issue.
We want to support all non-standard extensions.

View File

@@ -127,10 +127,17 @@ impl From<ModelCmdKind> for ModelCmd {
}
}
#[derive(Debug, Clone, Hash, PartialEq, PartialOrd)]
#[derive(Debug, Clone, PartialEq, PartialOrd, Default)]
pub struct ModelAttr {
/// from blif `.area` attribute
pub area: Option<f64>,
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Model {
pub meta: ModelMeta,
pub commands: Vec<ModelCmd>,
pub attr: ModelAttr,
}
impl CommandConsumer for Model {
@@ -214,6 +221,10 @@ impl CommandConsumer for Model {
.into(),
)
}
fn set_area(&mut self, area: f64) {
self.attr.area = Some(area);
}
}
#[derive(Debug)]
@@ -225,12 +236,12 @@ pub enum FullBlifErr<E: std::fmt::Debug> {
SearchPathsNotSupported,
}
#[derive(Debug, PartialEq, Hash)]
#[derive(Debug, PartialEq)]
pub enum BlifEntry {
Model(Model),
}
#[derive(Debug, PartialEq, Hash)]
#[derive(Debug, PartialEq)]
pub struct Blif {
pub entries: Vec<BlifEntry>,
to_search: Vec<String>,
@@ -243,6 +254,7 @@ impl ModelConsumer for Blif {
Model {
meta,
commands: vec![],
attr: Default::default(),
}
}

View File

@@ -106,6 +106,8 @@ pub trait CommandConsumer {
/// non-standard
fn connect(&mut self, from: &str, to: &str);
fn set_area(&mut self, area: f64);
}
#[derive(Debug, Clone, Hash, PartialEq, PartialOrd)]
@@ -844,6 +846,20 @@ fn parse_mod(
consumer.connect(from, to);
}
".area" => {
let val = args
.next()
.ok_or(BlifParserError::MissingArgs)?
.parse()
.map_err(|_| BlifParserError::Invalid)?;
if args.next().is_some() {
Err(BlifParserError::TooManyArgs)?
}
consumer.set_area(val);
}
// TODO: clock & delay cst
// TODO: .blackblox
_ => Err(BlifParserError::UnknownKw(cmd.to_string()))?,

View File

@@ -1,3 +1,8 @@
#![allow(non_snake_case)]
#![allow(unused)]
use std::default;
use super::ast::*;
use super::*;
@@ -38,6 +43,7 @@ fn simple_named() {
})
.into()
],
attr: Default::default(),
})],
);
}
@@ -77,6 +83,7 @@ fn simple_unnamed() {
})
.into()
],
attr: Default::default(),
})],
);
}
@@ -115,6 +122,7 @@ c
})
.into()
],
attr: Default::default(),
})],
);
}
@@ -154,6 +162,7 @@ c
})
.into()
],
attr: Default::default(),
})],
);
}
@@ -224,6 +233,7 @@ fn lut() {
})
.into()
],
attr: Default::default(),
})],
);
}
@@ -281,7 +291,8 @@ fn submod() {
lut: LUT(vec![([Tristate::True].into_iter().collect(), true)])
})
.into()
]
],
attr: Default::default(),
}),
BlifEntry::Model(Model {
meta: ModelMeta {
@@ -303,7 +314,8 @@ fn submod() {
)])
})
.into()
]
],
attr: Default::default(),
})
]
);
@@ -507,3 +519,95 @@ fn yosys_attrs() {
// TODO: assert_eq
}
#[test]
fn delay_cst__area() {
let ast = parse_str_blif_to_ast(
"top.blif",
r#"
.model top
.names $true
1
# .area is not a model attribute, but a command
.area 100.31
"#,
)
.unwrap();
assert_eq!(
ast.entries,
vec![BlifEntry::Model(Model {
meta: ModelMeta {
name: "top".into(),
inputs: None,
outputs: None,
clocks: vec![],
},
commands: vec![ModelCmd {
kind: ModelCmdKind::Gate(Gate {
meta: GateMeta {
inputs: vec![],
output: "$true".into(),
external_dc: false,
},
lut: LUT(vec![([].into_iter().collect(), true)])
}),
attrs: vec![],
}],
attr: ModelAttr {
area: Some(100.31),
..Default::default()
}
})]
);
}
/// generated by abc: https://github.com/berkeley-abc/abc/blob/master/src/base/io/ioWriteBlif.c
#[test]
fn abc__and_gate_delay() {
let ast = parse_str_blif_to_ast(
"top.blif",
r#"
.model top
.names $true
1
# not a model attribute, but a command
.and_gate_delay 12.31
"#,
)
.unwrap();
// TODO: assert
}
#[test]
fn delay_cst__default_spec() {
let ast = parse_str_blif_to_ast(
"top.blif",
r#"
.model top
.names $true
1
# not a model attribute, but a command
.default_input_arrival 3.0 3.2
.default_output_required 2.1 2.5
.default_max_input_load 200
.default_output_load 300
"#,
)
.unwrap();
// TODO: assert
}
// TODO:
//.delay <in-name> <phase> <load> <max-load> <brise> <drise> <bfall> <dfall>
//.wire_load_slope <load>
//.wire <wire-load-list>
//.input_arrival <in-name> <rise> <fall> [<before-after> <event>]
//.output_required <out-name> <rise> <fall> [<before-after> <event>]
//.max_input_load <load>
//.input_drive <in-name> <rise> <fall>
//.output_load <out-name> <load>