use compact_str::CompactString;
use indexmap::{IndexMap, IndexSet};
use std::ops::Range;
#[derive(Default, Debug)]
pub struct Liberty {
pub libs: Vec<(CompactString, Lib)>,
}
#[derive(Debug)]
#[allow(dead_code)]
#[readonly::make]
pub struct Unparsed {
pub reason: &'static str,
pub keyword: CompactString,
pub span: Range<usize>
}
#[derive(Debug)]
pub struct Lib {
pub cells: Vec<(CompactString, Cell)>,
pub units: Units,
pub lut_templates: IndexMap<CompactString, LUTTemplate>,
pub default_input_pin_cap: f32,
pub default_output_pin_cap: f32,
pub slew_derate: f32,
pub input_delay_threshold: [f32; 2],
pub output_delay_threshold: [f32; 2],
pub slew_threshold: [(f32, f32); 2],
pub unparsed: Vec<Unparsed>,
}
#[derive(Default, Debug)]
pub struct Cell {
pub pins: Vec<(CompactString, Pin)>,
pub sequential_def: Option<SequentialDef>,
pub unparsed: Vec<Unparsed>,
}
#[derive(Debug)]
pub enum SequentialDef {
FF(FFDef),
Latch(LatchDef),
StateTable(StateTableDef)
}
#[derive(Debug)]
pub struct FFDef {
pub pin_v1: CompactString,
pub pin_v2: CompactString,
pub clocked_on: LogicExpr,
pub next_state: LogicExpr,
pub clear: Option<LogicExpr>,
pub preset: Option<LogicExpr>,
pub clear_preset_var1: Option<ClearPresetVar>,
pub clear_preset_var2: Option<ClearPresetVar>
}
#[derive(Debug)]
pub struct LatchDef {
pub pin_v1: CompactString,
pub pin_v2: CompactString,
pub enable: Option<LogicExpr>, pub data_in: Option<LogicExpr>, pub clear: Option<LogicExpr>,
pub preset: Option<LogicExpr>,
pub clear_preset_var1: Option<ClearPresetVar>,
pub clear_preset_var2: Option<ClearPresetVar>
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ClearPresetVar {
L, H, N, T, X
}
#[derive(Debug)]
pub struct StateTableDef {
pub inputs: Vec<CompactString>,
pub internals: Vec<CompactString>,
pub rows: Vec<Vec<StateTableValue>>
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum StateTableValue {
L, H, N, X, LH, HL, R, F, NR, NF
}
#[derive(Debug, Clone)]
pub struct LogicExpr {
pub compiled: Vec<LogicExprInst>
}
#[derive(Debug, Clone)]
pub enum LogicExprInst {
PushVar(CompactString),
PushConst(bool),
Op(u8)
}
#[derive(Debug)]
pub struct Pin {
pub direction: PinDirection,
pub function: Option<LogicExpr>,
pub cap_rf: [f32; 2],
pub timings: Vec<Timing>,
pub unparsed: Vec<Unparsed>,
}
#[derive(Debug)]
pub struct Timing {
pub related_pin: CompactString,
pub typ: TimingType,
pub sense: TimingSense,
pub cell_rise: Option<LUT>,
pub cell_fall: Option<LUT>,
pub rise_transition: Option<LUT>,
pub fall_transition: Option<LUT>,
pub rise_constraint: Option<LUT>,
pub fall_constraint: Option<LUT>,
pub unparsed: Vec<Unparsed>,
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum LUTVariable {
Empty,
InputNetTransition,
TotalOutputNetCapacitance,
ConstrainedPinTransition,
RelatedPinTransition
}
#[derive(Debug)]
pub struct LUTTemplate {
pub variables: [LUTVariable; 3],
pub units: [f32; 3],
pub indices: [Vec<f32>; 3],
}
#[derive(Debug)]
pub struct LUT {
pub template: CompactString,
pub indices: [Vec<f32>; 3],
pub values: Vec<f32>,
pub values_unit: f32,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum TimingType {
Combinational,
RisingEdge,
FallingEdge,
SetupRising,
HoldRising,
SetupFalling,
HoldFalling,
Unsupported(CompactString)
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum TimingSense {
PositiveUnate,
NegativeUnate,
NonUnate
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum PinDirection {
I, O,
Unsupported(CompactString),
Unspecified
}
#[derive(Debug)]
pub struct Units {
pub time: f32,
pub voltage: f32,
pub current: f32,
pub power: f32,
pub cap: f32,
pub res: f32,
}
mod libertypest;
impl Liberty {
pub fn parse_str(s: &str) -> Result<Liberty, String> {
libertypest::parse_liberty(s)
}
pub fn debug_report_unparsed(&self) -> (
IndexSet<&str>, IndexSet<&str>, IndexSet<&str>, IndexSet<&str>
) {
let libwise = self.libs.iter()
.map(|(_, lib)| lib.unparsed.iter().map(|u| u.keyword.as_str()))
.flatten().collect::<IndexSet<&str>>();
if libwise.len() != 0 {
clilog::warn!(
W_LIB_UNPARSE, "{} unparsed library-wise items: {:?}",
libwise.len(), libwise);
}
let cellwise = self.libs.iter().map(
|(_, lib)| lib.cells.iter().map(|(_, c)| c.unparsed.iter().map(|u| u.keyword.as_str()))
.flatten()).flatten().collect::<IndexSet<&str>>();
if cellwise.len() != 0 {
clilog::warn!(
W_LIB_UNPARSE, "{} unparsed cell-wise items: {:?}",
cellwise.len(), cellwise);
}
let pinwise = self.libs.iter().map(
|(_, lib)| lib.cells.iter().map(
|(_, c)| c.pins.iter().map(|(_, p)| p.unparsed.iter().map(|u| u.keyword.as_str()))
.flatten()).flatten()).flatten().collect::<IndexSet<&str>>();
if pinwise.len() != 0 {
clilog::warn!(
W_LIB_UNPARSE, "{} unparsed pin-wise items: {:?}",
pinwise.len(), pinwise);
}
let timingwise = self.libs.iter().map(
|(_, lib)| lib.cells.iter().map(
|(_, c)| c.pins.iter().map(
|(_, p)| p.timings.iter().map(
|t| t.unparsed.iter().map(|u| u.keyword.as_str()))
.flatten()).flatten()).flatten()).flatten()
.collect::<IndexSet<&str>>();
if timingwise.len() != 0 {
clilog::warn!(
W_LIB_UNPARSE, "{} unparsed timing-wise items: {:?}",
timingwise.len(), timingwise);
}
(libwise, cellwise, pinwise, timingwise)
}
}
mod fmt;
#[cfg(feature = "direction_provider")]
mod direction_provider;
#[cfg(feature = "direction_provider")]
pub use direction_provider::LibDirectionProvider;