1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
//! Standard parasitics exchange format (SPEF) parser.
//!
//! ## How to use
//! See [`SPEF::parse_str`].
//!
//! We also support transforming a SPEF object to a SPEF source
//! code, by using [`std::fmt::Display`].
//!
//! ## Misc
//! This parser obeys the IEEE 1481-1998 standard, with some
//! notable exceptions (to be addressed in future work):
//!
//! 1. prefix bus delimiter `:`, `.` unsupported (because they interfere with hchar.), and empty suffix bus delimiter is unsupported yet.
//! 2. sensitivity is unsupported in cap and res defs. and slew threshold is unsupported in conn attr.
//! 3. Pi model is unsupported.
use compact_str::CompactString;
use std::sync::Arc;
/// SPEF main struct.
/// It contains headers, top ports, and nets.
///
/// SPEF can be constructed by parsing a source `&str` using
/// [`SPEF::parse_str`].
/// SPEF can be dumpped to a source file string using
/// [`std::fmt::Display`].
#[derive(Debug)]
pub struct SPEF {
pub header: SPEFHeader,
pub top_ports: Vec<SPEFPort>,
pub nets: Vec<SPEFNet>,
}
/// SPEF header (from `*SPEF` to `*L_UNIT`).
#[derive(Debug)]
pub struct SPEFHeader {
pub edition: CompactString, // "IEEE 1481-1998"
pub design: CompactString,
pub date: CompactString,
pub vendor: CompactString,
pub program: CompactString,
pub version: CompactString,
pub design_flow: Vec<CompactString>,
pub divider: char,
pub delimiter: char,
pub bus_delimiter_left: char,
pub bus_delimiter_right: char,
pub time_unit: f32,
pub cap_unit: f32,
pub res_unit: f32,
pub induct_unit: f32
}
/// Direction in SPEF.
///
/// (I don't know why there is yet another direction definition
/// on par with what's inside netlistdb, sverilogparse, and
/// libertyparse.)
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Direction {
/// Input
I,
/// Output
O,
/// Bidirectional
B
}
/// It seems this means min, nominal, and max.
#[derive(Debug, PartialEq, Copy, Clone)] // no Eq.
pub enum ParValue {
Single(f32),
Three(f32, f32, f32)
}
mod hier_name;
pub use hier_name::HierName;
/// Port or pin reference.
///
/// The tuple contains hier name,
/// (optional, port => None, pin => Some) macro pin name,
/// and (optional) bit index.
///
/// Please note that this reference cannot be directly used as
/// key to netlistdb cells/pins/nets. You may create
/// your own wrapper type on top of this. (We should do this
/// in the current crate in the future.)
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct SPEFHierPortPinRef(pub Arc<HierName>, pub Option<CompactString>, pub Option<isize>);
/// A piece of connectivity information in SPEF.
///
/// In the sense of `*C ... *L ... *S ... *D ...`.
#[derive(Debug)]
pub struct SPEFConnAttr {
pub coords: Option<(f32, f32)>,
pub cap_load: Option<ParValue>,
pub slew: Option<(ParValue, ParValue)>,
pub driving_cell: Option<CompactString>
}
/// A port in SPEF.
#[derive(Debug)]
pub struct SPEFPort {
/// The `name.1` (macro pin name) is guaranteed to be None,
/// because this is a port.
pub name: SPEFHierPortPinRef,
pub direction: Direction,
pub conn_attr: SPEFConnAttr
}
/// A net in SPEF.
#[derive(Debug)]
pub struct SPEFNet {
pub name: SPEFHierPortPinRef,
pub total_cap: f32,
pub conns: Vec<SPEFNetConn>,
pub caps: Vec<SPEFNetCap>,
pub ress: Vec<SPEFNetRes>
}
/// A connection entry of a net.
#[derive(Debug)]
pub struct SPEFNetConn {
pub name: SPEFHierPortPinRef,
pub direction: Direction,
pub conn_attr: SPEFConnAttr
}
/// A capacitance entry of a net.
#[derive(Debug)]
pub struct SPEFNetCap {
pub a: SPEFHierPortPinRef,
/// Optional secondary pin with which the cap is set up.
/// If not provided, the cap is a grounded capacitance.
/// If provided, it becomes a coupling capacitance.
pub b: Option<SPEFHierPortPinRef>,
pub val: ParValue
}
/// A resistance entry of a net.
#[derive(Debug)]
pub struct SPEFNetRes {
pub a: SPEFHierPortPinRef,
pub b: SPEFHierPortPinRef,
pub val: ParValue
}
/// SPEF parser in PEG (Pest).
mod spefpest;
/// SPEF writer.
mod fmt;
impl SPEF {
/// Parse a SPEF source string to the SPEF object.
/// This is the main entry.
///
/// On error, it returns a pretty string message indicating where
/// it is not working.
#[inline]
pub fn parse_str(s: &str) -> Result<SPEF, String> {
spefpest::parse_spef(s)
}
}