libertyparse/
lib.rs

1//! A liberty cell library parser written in Rust
2//!
3//! See [Liberty::parse_str], [Liberty], [Lib], etc.
4
5use compact_str::CompactString;
6use indexmap::{IndexMap, IndexSet};
7use std::ops::Range;
8
9/// A liberty file with multiple libraries.
10/// This is the main entry of parsing.
11#[derive(Default, Debug)]
12pub struct Liberty {
13    pub libs: Vec<(CompactString, Lib)>,
14}
15
16/// A warning record of unparsed (but semantically valid)
17/// Liberty content.
18///
19/// Because Liberty format is too complex to cover completely,
20/// we have to allow some unknown structures inside it.
21#[derive(Debug)]
22#[allow(dead_code)]
23#[readonly::make]
24pub struct Unparsed {
25    /// A warning reason description
26    pub reason: &'static str,
27    /// The keyword that is unsupported / encountered error.
28    pub keyword: CompactString,
29    /// The file bytes ranges of the unparsed content.
30    pub span: Range<usize>
31}
32
33/// A liberty library wrapped inside `library(...) {...}`.
34///
35/// It consists of metadata (e.g., PVT, thresholds, derates, units) followed by cells.
36#[derive(Debug)]
37pub struct Lib {
38    /// The cell entries.
39    pub cells: Vec<(CompactString, Cell)>,
40    /// The unit definition for all value types.
41    ///
42    /// Remember that it is NOT applied to values automatically
43    /// (to avoid numerical issues).
44    /// You should manually use it to transform the units
45    /// before you can use the content in parsed results.
46    pub units: Units,
47    /// The templates of look-up tables.
48    /// 
49    /// You can use it to locate the axis orders, corresponding
50    /// units, etc.
51    pub lut_templates: IndexMap<CompactString, LUTTemplate>,
52    /// used internally. the default input pin cap.
53    ///
54    /// It will be propagated to the pins if the pins lack
55    /// such information. We will handle this.
56    pub default_input_pin_cap: f32,
57    /// used internally. the default output pin cap.
58    ///
59    /// It will be propagated to the pins if the pins lack
60    /// such information. We will handle this.
61    pub default_output_pin_cap: f32,
62    /// The slew derate in `slew_derate_from_library`.
63    ///
64    /// remember to apply this to values before you use slew LUTs.
65    pub slew_derate: f32,
66    /// the input delay thresholds (R/F).
67    ///
68    /// E.g., [0.5, 0.5]
69    pub input_delay_threshold: [f32; 2],
70    /// the output delay thresholds (R/F).
71    ///
72    /// E.g., [0.5, 0.5]
73    pub output_delay_threshold: [f32; 2],
74    /// the slew thresholds (R/F -> lower/upper).
75    ///
76    /// E.g., [(0.2, 0.8), (0.2, 0.8)]
77    pub slew_threshold: [(f32, f32); 2],
78    /// The unparsed terms. See [Unparsed].
79    pub unparsed: Vec<Unparsed>,
80}
81
82/// A library cell consisting of pin definitions and
83/// sequential functionality definitions.
84#[derive(Default, Debug)]
85pub struct Cell {
86    /// The cell pins (name, pin).
87    pub pins: Vec<(CompactString, Pin)>,
88    /// The sequential definition useful in logic simulation.
89    pub sequential_def: Option<SequentialDef>,
90    /// The unparsed terms. See [Unparsed].
91    pub unparsed: Vec<Unparsed>,
92}
93
94/// A sequential element specification.
95/// Optionally defines a number of internal states.
96#[derive(Debug)]
97pub enum SequentialDef {
98    FF(FFDef),
99    Latch(LatchDef),
100    StateTable(StateTableDef)
101}
102
103#[derive(Debug)]
104pub struct FFDef {
105    pub pin_v1: CompactString,
106    pub pin_v2: CompactString,
107    pub clocked_on: LogicExpr,
108    pub next_state: LogicExpr,
109    pub clear: Option<LogicExpr>,
110    pub preset: Option<LogicExpr>,
111    pub clear_preset_var1: Option<ClearPresetVar>,
112    pub clear_preset_var2: Option<ClearPresetVar>
113}
114
115#[derive(Debug)]
116pub struct LatchDef {
117    pub pin_v1: CompactString,
118    pub pin_v2: CompactString,
119    pub enable: Option<LogicExpr>,  // SR latch is None
120    pub data_in: Option<LogicExpr>,  // SR latch is None
121    pub clear: Option<LogicExpr>,
122    pub preset: Option<LogicExpr>,
123    pub clear_preset_var1: Option<ClearPresetVar>,
124    pub clear_preset_var2: Option<ClearPresetVar>
125}
126
127/// Clear & preset behavior definition.
128#[derive(Debug, Copy, Clone, PartialEq, Eq)]
129pub enum ClearPresetVar {
130    L, H, N, T, X
131}
132
133#[derive(Debug)]
134pub struct StateTableDef {
135    pub inputs: Vec<CompactString>,
136    pub internals: Vec<CompactString>,
137    pub rows: Vec<Vec<StateTableValue>>
138}
139
140/// All possible state table items
141/// Note that we merged the "-" and "N" in next internal
142/// nodes into a single "N". According to the hints in
143/// Liberty docs, they are actually different in
144/// event generation? No difference in our applications yet.
145#[derive(Debug, Copy, Clone, PartialEq, Eq)]
146pub enum StateTableValue {
147    L, H, N, X, LH, HL, R, F, NR, NF
148}
149
150#[derive(Debug, Clone)]
151pub struct LogicExpr {
152    /// A compiled stack language representing the logic.
153    /// It is essentially a postfix expression.
154    pub compiled: Vec<LogicExprInst>
155}
156
157/// The element of the stack language can be:
158/// 1. Push an variable to stack
159/// 2. An operation that pops some variables from stack,
160///    compute one logic operation, and push result
161///    to stack.
162#[derive(Debug, Clone)]
163pub enum LogicExprInst {
164    /// Push a variable.
165    PushVar(CompactString),
166    /// Push a 0 or 1.
167    PushConst(bool),
168    /// Operation can be b'&', b'|', b'!'.
169    Op(u8)
170}
171
172/// A library pin (macro pin) with metadata (direction, function,
173/// caps, etc) and timing arcs (delay, slew & constraints).
174#[derive(Debug)]
175pub struct Pin {
176    /// Pin direction.
177    pub direction: PinDirection,
178    /// Pin function, if supplied.
179    pub function: Option<LogicExpr>,
180    /// Pin capacitance (R/F).
181    pub cap_rf: [f32; 2],
182    /// Timing arcs.
183    pub timings: Vec<Timing>,
184    /// The unparsed terms. See [Unparsed].
185    pub unparsed: Vec<Unparsed>,
186}
187
188/// A timing arc definition. It contains arc type, timing sense,
189/// and delay/slew/constraint LUTs.
190#[derive(Debug)]
191pub struct Timing {
192    /// The other pin name (typically corresponding cell input).
193    pub related_pin: CompactString,
194    /// Arc type
195    pub typ: TimingType,
196    /// Timing sense (unate).
197    pub sense: TimingSense,
198    pub cell_rise: Option<LUT>,
199    pub cell_fall: Option<LUT>,
200    pub rise_transition: Option<LUT>,
201    pub fall_transition: Option<LUT>,
202    pub rise_constraint: Option<LUT>,
203    pub fall_constraint: Option<LUT>,
204    /// The unparsed terms. See [Unparsed].
205    pub unparsed: Vec<Unparsed>,
206}
207
208#[derive(Debug, PartialEq, Eq, Copy, Clone)]
209pub enum LUTVariable {
210    Empty,
211    InputNetTransition,
212    TotalOutputNetCapacitance,
213    ConstrainedPinTransition,
214    RelatedPinTransition
215}
216
217/// A LUT template.
218///
219/// The units are NOT applied to indices.
220#[derive(Debug)]
221pub struct LUTTemplate {
222    pub variables: [LUTVariable; 3],
223    pub units: [f32; 3],
224    pub indices: [Vec<f32>; 3],
225}
226
227/// A LUT with associated template.
228///
229/// The indices can come from an ad-hoc definition, or
230/// inherited from the template. We handle this for you.
231///
232/// The values are NOT normalized with the values_unit.
233#[derive(Debug)]
234pub struct LUT {
235    /// The template name which can be used to look up
236    /// in parent [Lib] structs.
237    pub template: CompactString,
238    /// The indices.
239    ///
240    /// Unused axes are empty vectors.
241    pub indices: [Vec<f32>; 3],
242    /// A flattened values list
243    pub values: Vec<f32>,
244    /// Unit of values.
245    ///
246    /// currently it is most likely the same as [Units::time].
247    pub values_unit: f32,
248}
249
250#[derive(Debug, PartialEq, Eq, Clone)]
251pub enum TimingType {
252    Combinational,
253    RisingEdge,
254    FallingEdge,
255    SetupRising,
256    HoldRising,
257    SetupFalling,
258    HoldFalling,
259    Unsupported(CompactString)
260}
261
262#[derive(Debug, PartialEq, Eq, Copy, Clone)]
263pub enum TimingSense {
264    PositiveUnate,
265    NegativeUnate,
266    NonUnate
267}
268
269#[derive(Debug, PartialEq, Eq, Clone)]
270pub enum PinDirection {
271    I, O, 
272    Unsupported(CompactString),
273    Unspecified
274}
275
276/// All units are stored as ratio to the standard units (s, F, Ohm, A, ...)
277#[derive(Debug)]
278pub struct Units {
279    pub time: f32,
280    pub voltage: f32,
281    pub current: f32,
282    pub power: f32,
283    pub cap: f32,
284    pub res: f32,
285}
286
287mod libertypest;
288
289impl Liberty {
290    /// The parser.
291    pub fn parse_str(s: &str) -> Result<Liberty, String> {
292        libertypest::parse_liberty(s)
293    }
294
295    /// log to `stderr` all unparsed keywords, for debugging purpose.
296    pub fn debug_report_unparsed(&self) -> (
297        IndexSet<&str>, IndexSet<&str>, IndexSet<&str>, IndexSet<&str>
298    ) {
299        let libwise = self.libs.iter()
300            .map(|(_, lib)| lib.unparsed.iter().map(|u| u.keyword.as_str()))
301            .flatten().collect::<IndexSet<&str>>();
302        if libwise.len() != 0 {
303            clilog::warn!(
304                W_LIB_UNPARSE, "{} unparsed library-wise items: {:?}",
305                libwise.len(), libwise);
306        }
307        
308        let cellwise = self.libs.iter().map(
309            |(_, lib)| lib.cells.iter().map(|(_, c)| c.unparsed.iter().map(|u| u.keyword.as_str()))
310                .flatten()).flatten().collect::<IndexSet<&str>>();
311        if cellwise.len() != 0 {
312            clilog::warn!(
313                W_LIB_UNPARSE, "{} unparsed cell-wise items: {:?}",
314                cellwise.len(), cellwise);
315        }
316        
317        let pinwise = self.libs.iter().map(
318            |(_, lib)| lib.cells.iter().map(
319                |(_, c)| c.pins.iter().map(|(_, p)| p.unparsed.iter().map(|u| u.keyword.as_str()))
320                    .flatten()).flatten()).flatten().collect::<IndexSet<&str>>();
321        if pinwise.len() != 0 {
322            clilog::warn!(
323                W_LIB_UNPARSE, "{} unparsed pin-wise items: {:?}",
324                pinwise.len(), pinwise);
325        }
326
327        let timingwise = self.libs.iter().map(
328            |(_, lib)| lib.cells.iter().map(
329                |(_, c)| c.pins.iter().map(
330                    |(_, p)| p.timings.iter().map(
331                        |t| t.unparsed.iter().map(|u| u.keyword.as_str()))
332                .flatten()).flatten()).flatten()).flatten()
333            .collect::<IndexSet<&str>>();
334        if timingwise.len() != 0 {
335            clilog::warn!(
336                W_LIB_UNPARSE, "{} unparsed timing-wise items: {:?}",
337                timingwise.len(), timingwise);
338        }
339
340        (libwise, cellwise, pinwise, timingwise)
341    }
342}
343
344mod fmt;
345
346// direction provider (optional).
347#[cfg(feature = "direction_provider")]
348mod direction_provider;
349#[cfg(feature = "direction_provider")]
350pub use direction_provider::LibDirectionProvider;
351