use crate::{
ast::{
AttributeList, CodeFormatter, ComplexAttri, ComplexParseError, GroupComments,
GroupFn, Indentation, SimpleAttri,
},
common::items::Formula,
expression::logic,
ArcStr, GroupSet, NotNan,
};
use core::fmt::{self, Write};
#[derive(Debug, Clone, Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone,Default);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Sensitization {
#[id]
#[liberty(name)]
pub name: ArcStr,
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[liberty(undefined)]
pub undefined: AttributeList,
#[liberty(complex)]
pub pin_names: Vec<ArcStr>,
#[liberty(complex(type = Vec))]
pub vector: Vec<SensitizationVector>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct SensitizationVector {
id: usize,
states: Vec<logic::Static>,
}
impl ComplexAttri for SensitizationVector {
#[inline]
fn parse(v: &[&str]) -> Result<Self, ComplexParseError> {
let mut i = v.iter();
let id: usize = match i.next() {
Some(&s) => match s.parse() {
Ok(f) => f,
Err(e) => return Err(ComplexParseError::Int(e)),
},
None => return Err(ComplexParseError::LengthDismatch),
};
let states = match i.next() {
Some(&s) => match s
.split_ascii_whitespace()
.map(str::parse)
.collect::<Result<Vec<logic::Static>, _>>()
{
Ok(states) => states,
Err(_) => return Err(ComplexParseError::UnsupportedWord),
},
None => return Err(ComplexParseError::LengthDismatch),
};
if i.next().is_some() {
return Err(ComplexParseError::LengthDismatch);
}
Ok(Self { id, states })
}
#[inline]
fn fmt_self<T: Write, I: Indentation>(
&self,
f: &mut CodeFormatter<'_, T, I>,
) -> fmt::Result {
let mut buffer = itoa::Buffer::new();
write!(f, "{}, ", buffer.format(self.id))?;
crate::ast::join_fmt(
self.states.iter(),
f,
|state, ff| {
write!(
ff,
"{}",
match state {
logic::Static::UnInit(logic::UnInit::HighImpedance) => "Z",
logic::Static::UnInit(logic::UnInit::Unknown(_)) => "X",
logic::Static::Level(logic::Level::High) => "1",
logic::Static::Level(logic::Level::Low) => "0",
}
)
},
" ",
)
}
}
#[cfg(test)]
mod test_sensitization {
use super::*;
#[test]
fn sensitization() {
let sense = crate::ast::test_parse_fmt::<Sensitization>(
r#"(sensitization_nand2) {
pin_names ( IN1, IN2, OUT1 );
vector ( 1, "0 0 1" );
vector ( 2, "0 X 1" );
vector ( 3, "Z 0 1" );
vector ( 4, "1 1 0" );
}"#,
r#"
liberty_db::library::items::Sensitization (sensitization_nand2) {
| pin_names ("IN1, IN2, OUT1");
| vector (1, "0 0 1");
| vector (2, "0 X 1");
| vector (3, "Z 0 1");
| vector (4, "1 1 0");
}"#,
);
assert_eq!(
sense.vector,
vec![
SensitizationVector {
id: 1,
states: vec![
logic::Static::Level(logic::Level::Low),
logic::Static::Level(logic::Level::Low),
logic::Static::Level(logic::Level::High),
]
},
SensitizationVector {
id: 2,
states: vec![
logic::Static::Level(logic::Level::Low),
logic::Static::UnInit(logic::UnInit::Unknown(None)),
logic::Static::Level(logic::Level::High),
]
},
SensitizationVector {
id: 3,
states: vec![
logic::Static::UnInit(logic::UnInit::HighImpedance),
logic::Static::Level(logic::Level::Low),
logic::Static::Level(logic::Level::High),
]
},
SensitizationVector {
id: 4,
states: vec![
logic::Static::Level(logic::Level::High),
logic::Static::Level(logic::Level::High),
logic::Static::Level(logic::Level::Low),
]
}
]
);
let sense1 = crate::ast::test_parse_fmt::<Sensitization>(
r#"(sensitization_nand2) {
vector ( 1, "0 0 1" );
vector ( 2, "0 X 9" );
vector ( 3, "Z 0 1" );
vector ( 4, "1 1 0" );
}"#,
r#"
liberty_db::library::items::Sensitization (sensitization_nand2) {
| vector (1, "0 0 1");
| vector (3, "Z 0 1");
| vector (4, "1 1 0");
| /* Undefined attributes from here */
| vector ("2, 0 X 9");
| /* Undefined attributes end here */
}"#,
);
assert!(sense1.undefined.len() == 1);
}
}
impl GroupFn for Sensitization {}
#[derive(Debug, Clone, Default)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone,Default);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct VoltageMap {
#[id]
pub name: ArcStr,
pub voltage: f64,
}
impl ComplexAttri for VoltageMap {
#[inline]
fn parse(v: &[&str]) -> Result<Self, ComplexParseError> {
let mut i = v.iter();
let name = match i.next() {
Some(&s) => ArcStr::from(s),
None => return Err(ComplexParseError::LengthDismatch),
};
let voltage = match i.next() {
Some(&s) => match s.parse() {
Ok(f) => f,
Err(e) => {
return Err(ComplexParseError::Float(
ordered_float::ParseNotNanError::ParseFloatError(e),
))
}
},
None => return Err(ComplexParseError::LengthDismatch),
};
if i.next().is_some() {
return Err(ComplexParseError::LengthDismatch);
}
Ok(Self { name, voltage })
}
#[inline]
fn fmt_self<T: Write, I: Indentation>(
&self,
f: &mut CodeFormatter<'_, T, I>,
) -> fmt::Result {
let mut buffer = ryu::Buffer::new();
write!(f, "{}, {}", self.name, buffer.format(self.voltage))
}
}
#[derive(Debug, Clone, Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone, Default);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct InputVoltage {
#[id]
#[liberty(name)]
pub name: ArcStr,
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[liberty(undefined)]
pub undefined: AttributeList,
#[liberty(simple)]
pub vil: Formula,
#[liberty(simple)]
pub vih: Formula,
#[liberty(simple)]
pub vimin: Formula,
#[liberty(simple)]
pub vimax: Formula,
}
impl GroupFn for InputVoltage {}
#[derive(Debug, Clone, Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone, Default);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct OutputVoltage {
#[id]
#[liberty(name)]
pub name: ArcStr,
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[liberty(undefined)]
pub undefined: AttributeList,
#[liberty(simple)]
pub vol: ArcStr,
#[liberty(simple)]
pub voh: ArcStr,
#[liberty(simple)]
pub vomin: ArcStr,
#[liberty(simple)]
pub vomax: ArcStr,
}
impl GroupFn for OutputVoltage {}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq, Default)]
#[derive(Ord, PartialOrd)]
#[derive(strum_macros::EnumString, strum_macros::EnumIter, strum_macros::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum DelayModel {
#[default]
#[strum(serialize = "table_lookup")]
TableLookup,
}
impl SimpleAttri for DelayModel {
#[inline]
fn nom_parse<'a>(
i: &'a str,
line_num: &mut usize,
) -> crate::ast::SimpleParseErr<'a, Self> {
crate::ast::nom_parse_from_str(i, line_num)
}
}
#[derive(Debug, Clone, derivative::Derivative)]
#[derivative(Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone);
derive(derivative::Derivative);
derivative(Default);),
attr_filter(derivative;)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct OperatingConditions {
#[id]
#[liberty(name)]
pub name: ArcStr,
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[liberty(undefined)]
pub undefined: AttributeList,
#[liberty(simple(type = Option))]
pub calc_mode: Option<ArcStr>,
#[liberty(simple(type = Option))]
pub parameteri: Option<f64>,
#[liberty(simple)]
pub process: f64,
#[liberty(simple(type = Option))]
pub process_label: Option<ArcStr>,
#[liberty(simple)]
pub temperature: f64,
#[liberty(simple(type = Option))]
pub tree_type: Option<TreeType>,
#[liberty(simple)]
#[derivative(Default(value = "5.0"))]
pub voltage: f64,
}
impl GroupFn for OperatingConditions {}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd)]
#[derive(strum_macros::EnumString, strum_macros::EnumIter, strum_macros::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum TreeType {
#[strum(serialize = "best_case_tree")]
BestCaseTree,
#[strum(serialize = "balanced_tree")]
BalancedTree,
#[strum(serialize = "worst_case_tree")]
WorstCaseTree,
}
impl SimpleAttri for TreeType {
#[inline]
fn nom_parse<'a>(
i: &'a str,
line_num: &mut usize,
) -> crate::ast::SimpleParseErr<'a, Self> {
crate::ast::nom_parse_from_str(i, line_num)
}
}
#[derive(Debug, Clone)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Define {
#[id]
pub attribute_name: ArcStr,
#[id]
pub group_name: ArcStr,
pub attribute_type: AttributeType,
}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd)]
#[derive(strum_macros::EnumString, strum_macros::EnumIter, strum_macros::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum AttributeType {
#[strum(serialize = "Boolean", serialize = "boolean")]
Boolean,
#[strum(serialize = "string")]
String,
#[strum(serialize = "integer")]
Integer,
#[strum(serialize = "float")]
Float,
}
impl ComplexAttri for Define {
#[inline]
fn parse(v: &[&str]) -> Result<Self, ComplexParseError> {
let mut i = v.iter();
let attribute_name = match i.next() {
Some(&s) => ArcStr::from(s),
None => return Err(ComplexParseError::LengthDismatch),
};
let group_name = match i.next() {
Some(&s) => ArcStr::from(s),
None => return Err(ComplexParseError::LengthDismatch),
};
let attribute_type = match i.next() {
Some(&s) => match s.parse() {
Ok(f) => f,
Err(_) => return Err(ComplexParseError::UnsupportedWord),
},
None => return Err(ComplexParseError::LengthDismatch),
};
if i.next().is_some() {
return Err(ComplexParseError::LengthDismatch);
}
Ok(Self { attribute_name, group_name, attribute_type })
}
#[inline]
fn fmt_self<T: Write, I: Indentation>(
&self,
f: &mut CodeFormatter<'_, T, I>,
) -> fmt::Result {
write!(f, "{}, {}, {}", self.attribute_name, self.group_name, self.attribute_type)
}
}
#[derive(Debug, Clone)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct DefineCellArea {
#[id]
pub area_name: ArcStr,
pub resource_type: ResourceType,
}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd)]
#[derive(strum_macros::EnumString, strum_macros::EnumIter, strum_macros::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum ResourceType {
#[strum(serialize = "pad_slots")]
PadSlots,
#[strum(serialize = "pad_input_driver_sites")]
PadInputDriverSites,
#[strum(serialize = "pad_output_driver_sites")]
PadOutputDriverSites,
#[strum(serialize = "pad_driver_sites")]
PadDriverSites,
}
impl ComplexAttri for DefineCellArea {
#[inline]
fn parse(v: &[&str]) -> Result<Self, ComplexParseError> {
let mut i = v.iter();
let area_name = match i.next() {
Some(&s) => ArcStr::from(s),
None => return Err(ComplexParseError::LengthDismatch),
};
let resource_type = match i.next() {
Some(&s) => match s.parse() {
Ok(f) => f,
Err(_) => return Err(ComplexParseError::UnsupportedWord),
},
None => return Err(ComplexParseError::LengthDismatch),
};
if i.next().is_some() {
return Err(ComplexParseError::LengthDismatch);
}
Ok(Self { area_name, resource_type })
}
#[inline]
fn fmt_self<T: Write, I: Indentation>(
&self,
f: &mut CodeFormatter<'_, T, I>,
) -> fmt::Result {
write!(f, "{}, {}", self.area_name, self.resource_type)
}
}
#[derive(Debug, Clone)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct DefineGroup {
#[id]
pub group: ArcStr,
#[id]
pub parent_name: ArcStr,
}
impl ComplexAttri for DefineGroup {
#[inline]
fn parse(v: &[&str]) -> Result<Self, ComplexParseError> {
let mut i = v.iter();
let group = match i.next() {
Some(&s) => ArcStr::from(s),
None => return Err(ComplexParseError::LengthDismatch),
};
let parent_name = match i.next() {
Some(&s) => ArcStr::from(s),
None => return Err(ComplexParseError::LengthDismatch),
};
if i.next().is_some() {
return Err(ComplexParseError::LengthDismatch);
}
Ok(Self { group, parent_name })
}
#[inline]
fn fmt_self<T: Write, I: Indentation>(
&self,
f: &mut CodeFormatter<'_, T, I>,
) -> fmt::Result {
write!(f, "{}, {}", self.group, self.parent_name)
}
}
#[derive(Debug, Clone, Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone,Default);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct WireLoad {
#[id]
#[liberty(name)]
pub name: ArcStr,
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[liberty(undefined)]
pub undefined: AttributeList,
#[liberty(simple)]
pub area: f64,
#[liberty(simple)]
pub capacitance: f64,
#[liberty(simple)]
pub resistance: f64,
#[liberty(simple)]
pub slope: f64,
#[liberty(complex(type = Set))]
pub fanout_length: GroupSet<FanoutLength>,
}
impl GroupFn for WireLoad {}
#[derive(Debug, Clone, Default, Copy)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone, Default, Copy);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct FanoutLength {
#[id]
pub fanout: u32,
pub length: f64,
pub average_capacitance: Option<f64>,
pub standard_deviation: Option<f64>,
pub number_of_nets: Option<u32>,
}
impl ComplexAttri for FanoutLength {
#[inline]
fn parse(v: &[&str]) -> Result<Self, ComplexParseError> {
let mut i = v.iter();
let fanout = match i.next() {
Some(&s) => match s.parse() {
Ok(f) => f,
Err(e) => return Err(ComplexParseError::Int(e)),
},
None => return Err(ComplexParseError::LengthDismatch),
};
let length = match i.next() {
Some(&s) => match s.parse() {
Ok(f) => f,
Err(e) => {
return Err(ComplexParseError::Float(
ordered_float::ParseNotNanError::ParseFloatError(e),
))
}
},
None => return Err(ComplexParseError::LengthDismatch),
};
let average_capacitance = i.next().and_then(|s| s.parse().ok());
let standard_deviation = i.next().and_then(|s| s.parse().ok());
let number_of_nets = i.next().and_then(|s| s.parse().ok());
if i.next().is_some() {
return Err(ComplexParseError::LengthDismatch);
}
Ok(Self {
fanout,
length,
average_capacitance,
standard_deviation,
number_of_nets,
})
}
#[inline]
fn fmt_self<T: Write, I: Indentation>(
&self,
f: &mut CodeFormatter<'_, T, I>,
) -> fmt::Result {
let mut buffer_f = ryu::Buffer::new();
let mut buffer_i = itoa::Buffer::new();
match (self.average_capacitance, self.standard_deviation, self.number_of_nets) {
(Some(average_capacitance), Some(standard_deviation), Some(number_of_nets)) => {
write!(
f,
"{}, {}, ",
buffer_i.format(self.fanout),
buffer_f.format(self.length),
)?;
write!(f, "{}, ", buffer_f.format(average_capacitance),)?;
write!(
f,
"{}, {}",
buffer_f.format(standard_deviation),
buffer_i.format(number_of_nets),
)
}
_ => {
write!(f, "{}, {}", buffer_i.format(self.fanout), buffer_f.format(self.length))
}
}
}
}
#[derive(Debug, Clone, Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone,Default);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct WireLoadSection {
#[id]
#[liberty(name)]
pub name: ArcStr,
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[liberty(undefined)]
pub undefined: AttributeList,
#[liberty(complex)]
pub wire_load_from_area: (f64, f64, ArcStr),
}
impl GroupFn for WireLoadSection {}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd, Default)]
#[derive(strum_macros::EnumString, strum_macros::EnumIter, strum_macros::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum BaseCurveType {
#[strum(serialize = "ccs_half_curve")]
#[default]
CcsHalfCurve,
#[strum(serialize = "ccs_timing_half_curve")]
CcsTimingHalfCurve,
}
impl SimpleAttri for BaseCurveType {
#[inline]
fn nom_parse<'a>(
i: &'a str,
line_num: &mut usize,
) -> crate::ast::SimpleParseErr<'a, Self> {
crate::ast::nom_parse_from_str(i, line_num)
}
}
#[derive(Debug, Clone, Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone, Default);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct BaseCurves {
#[id]
#[liberty(name)]
pub name: ArcStr,
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[liberty(undefined)]
pub undefined: AttributeList,
#[liberty(simple)]
pub base_curve_type: BaseCurveType,
#[liberty(complex)]
pub curve_x: Vec<NotNan<f64>>,
#[liberty(complex(type = Set))]
pub curve_y: GroupSet<crate::common::items::IdVector>,
}
impl GroupFn for BaseCurves {}
#[cfg(test)]
mod test {
#[test]
fn input_voltage() {
let g = crate::ast::test_parse_fmt::<super::InputVoltage>(
r#"(cmos_schmitt) {
vil : 0.3 * VDD ;
vih : 0.7 * VDD ;
vimin : -0.5 ;
vimax : VDD + 0.5 ;
}"#,
r#"
liberty_db::library::items::InputVoltage (cmos_schmitt) {
| vil : 0.3 * VDD ;
| vih : 0.7 * VDD ;
| vimin : -0.5 ;
| vimax : VDD + 0.5 ;
}"#,
);
}
#[test]
fn base_curves() {
let g = crate::ast::test_parse_fmt::<super::BaseCurves>(
r#"("nc_compact_ccs_curve_1") {
base_curve_type : "ccs_timing_half_curve";
curve_x("0.1000000, 0.2000000, 0.3000000, 0.4000000, 0.5000000, 0.6000000, 0.7000000, 0.8000000, 0.9000000");
curve_y(1, \
"0.9965371, 0.9930742, 0.9584770, 0.9165637, 0.8271961, 0.7425452, 0.6009643, 0.4459254, 0.2653107");
curve_y(2, \
"0.9887274, 0.9695129, 0.9443244, 0.9183546, 0.8705093, 0.8062681, 0.6984753, 0.5213233, 0.2657268");
curve_y(3, \
"0.9895478, 0.9774914, 0.9389569, 0.8934003, 0.8125975, 0.7144581, 0.5786802, 0.4298566, 0.2542494");
curve_y(4, \
"0.9944934, 0.9784088, 0.9620733, 0.9304195, 0.8888662, 0.8329558, 0.7240709, 0.5580780, 0.3037784");
curve_y(5, \
"0.9922672, 0.9664605, 0.9307680, 0.8888898, 0.8146837, 0.7076250, 0.5811826, 0.4366006, 0.2619239");
}"#,
r#"
liberty_db::library::items::BaseCurves (nc_compact_ccs_curve_1) {
| base_curve_type : ccs_timing_half_curve;
| curve_x ("0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9");
| curve_y (1, \
| | "0.9965371, 0.9930742, 0.958477, 0.9165637, 0.8271961, 0.7425452, 0.6009643, 0.4459254, 0.2653107");
| curve_y (2, \
| | "0.9887274, 0.9695129, 0.9443244, 0.9183546, 0.8705093, 0.8062681, 0.6984753, 0.5213233, 0.2657268");
| curve_y (3, \
| | "0.9895478, 0.9774914, 0.9389569, 0.8934003, 0.8125975, 0.7144581, 0.5786802, 0.4298566, 0.2542494");
| curve_y (4, \
| | "0.9944934, 0.9784088, 0.9620733, 0.9304195, 0.8888662, 0.8329558, 0.7240709, 0.558078, 0.3037784");
| curve_y (5, \
| | "0.9922672, 0.9664605, 0.930768, 0.8888898, 0.8146837, 0.707625, 0.5811826, 0.4366006, 0.2619239");
}"#,
);
}
}