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)
    }
}