use crate::{
ast::{
Attributes, CodeFormatter, ComplexAttri, ComplexParseError, DefinedType,
GroupComments, GroupFn, GroupSet, Indentation, ParseScope, SimpleAttri,
},
common::{
items::{Formula, IdVector},
parse_f64,
},
expression::logic,
ArcStr, NotNan,
};
use core::fmt::{self, Write};
#[derive(Debug, Clone, Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(sort)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Sensitization {
#[id(borrow = "&str")]
#[size = 8]
#[liberty(name)]
pub name: ArcStr,
#[size = 48]
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[size = 48]
#[liberty(attributes)]
pub attributes: Attributes,
#[size = 24]
#[liberty(complex)]
pub pin_names: Vec<ArcStr>,
#[size = 24]
#[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<'a, I: Iterator<Item = &'a Vec<&'a str>>>(
iter: I,
_scope: &mut ParseScope,
) -> Result<Self, ComplexParseError> {
let mut i = iter.flat_map(IntoIterator::into_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(|t| match t {
"1" => Ok(logic::Static::H),
"0" => Ok(logic::Static::L),
"X" => Ok(logic::Static::X),
"Z" => Ok(logic::Static::Z),
_ => Err(ComplexParseError::UnsupportedWord),
})
.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 {
f.write_int(self.id)?;
f.write_str(", ")?;
crate::ast::join_fmt(
self.states.iter(),
f,
|state, ff| {
write!(
ff,
"{}",
match state {
logic::Static::Z => "Z",
logic::Static::X => "X",
logic::Static::H => "1",
logic::Static::L => "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::L, logic::Static::L, logic::Static::H,]
},
SensitizationVector {
id: 2,
states: vec![logic::Static::L, logic::Static::X, logic::Static::H,]
},
SensitizationVector {
id: 3,
states: vec![logic::Static::Z, logic::Static::L, logic::Static::H,]
},
SensitizationVector {
id: 4,
states: vec![logic::Static::H, logic::Static::H, logic::Static::L,]
}
]
);
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");
| vector (2, "0 X 9"); /* user defined attribute */
}"#,
);
assert!(sense1.attributes.len() == 1);
}
}
impl GroupFn for Sensitization {}
#[derive(Debug, Clone, Default)]
#[mut_set::derive::item(sort)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct VoltageMap {
#[id(borrow = "&str")]
#[size = 8]
pub name: ArcStr,
pub voltage: NotNan<f64>,
}
impl ComplexAttri for VoltageMap {
#[inline]
fn parse<'a, I: Iterator<Item = &'a Vec<&'a str>>>(
iter: I,
_scope: &mut ParseScope,
) -> Result<Self, ComplexParseError> {
let mut i = iter.flat_map(IntoIterator::into_iter);
let name = match i.next() {
Some(&s) => ArcStr::from(s),
None => return Err(ComplexParseError::LengthDismatch),
};
let voltage = match i.next() {
Some(s) => parse_f64(s)?,
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 {
write!(f, "{}, ", self.name)?;
f.write_float(self.voltage.into_inner())
}
}
#[derive(Debug, Clone, Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(sort)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct InputVoltage {
#[id(borrow = "&str")]
#[size = 8]
#[liberty(name)]
pub name: ArcStr,
#[size = 120]
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[size = 48]
#[liberty(attributes)]
pub attributes: Attributes,
#[size = 8]
#[liberty(simple)]
pub vil: Formula,
#[size = 8]
#[liberty(simple)]
pub vih: Formula,
#[size = 8]
#[liberty(simple)]
pub vimin: Formula,
#[size = 8]
#[liberty(simple)]
pub vimax: Formula,
}
impl GroupFn for InputVoltage {}
#[derive(Debug, Clone, Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(sort)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct OutputVoltage {
#[id(borrow = "&str")]
#[size = 8]
#[liberty(name)]
pub name: ArcStr,
#[size = 120]
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[size = 48]
#[liberty(attributes)]
pub attributes: Attributes,
#[size = 8]
#[liberty(simple)]
pub vol: Formula,
#[size = 8]
#[liberty(simple)]
pub voh: Formula,
#[size = 8]
#[liberty(simple)]
pub vomin: Formula,
#[size = 8]
#[liberty(simple)]
pub vomax: Formula,
}
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,
scope: &mut ParseScope,
) -> crate::ast::SimpleParseRes<'a, Self> {
crate::ast::nom_parse_from_str(i, scope)
}
}
#[derive(Debug, Clone, derivative::Derivative)]
#[derivative(Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(sort)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct OperatingConditions {
#[id(borrow = "&str")]
#[size = 8]
#[liberty(name)]
pub name: ArcStr,
#[size = 192]
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[size = 48]
#[liberty(attributes)]
pub attributes: Attributes,
#[size = 8]
#[liberty(simple(type = Option))]
pub calc_mode: Option<ArcStr>,
#[size = 16]
#[liberty(simple(type = Option))]
pub parameteri: Option<NotNan<f64>>,
#[size = 8]
#[liberty(simple)]
pub process: NotNan<f64>,
#[size = 8]
#[liberty(simple(type = Option))]
pub process_label: Option<ArcStr>,
#[size = 8]
#[liberty(simple)]
pub temperature: NotNan<f64>,
#[size = 1]
#[liberty(simple(type = Option))]
pub tree_type: Option<TreeType>,
#[size = 8]
#[liberty(simple)]
#[derivative(Default(value = "unsafe { NotNan::<f64>::new_unchecked(5.0) }"))]
pub voltage: NotNan<f64>,
}
impl GroupFn for OperatingConditions {}
#[derive(Debug, Clone, derivative::Derivative)]
#[derivative(Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(sort)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct FpgaIsd {
#[size = 8]
#[liberty(name)]
#[id(borrow = "&str")]
pub name: ArcStr,
#[size = 96]
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[size = 48]
#[liberty(attributes)]
pub attributes: Attributes,
#[size = 8]
#[liberty(simple)]
pub drive: ArcStr,
#[size = 8]
#[liberty(simple)]
pub io_type: ArcStr,
#[size = 1]
#[liberty(simple(type = Option))]
pub slew: Option<FPGASlew>,
}
impl GroupFn for FpgaIsd {}
#[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 FPGASlew {
#[strum(serialize = "FAST")]
FAST,
#[strum(serialize = "SLOW")]
SLOW,
}
impl SimpleAttri for FPGASlew {
#[inline]
fn nom_parse<'a>(
i: &'a str,
scope: &mut ParseScope,
) -> crate::ast::SimpleParseRes<'a, Self> {
crate::ast::nom_parse_from_str(i, scope)
}
}
#[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,
scope: &mut ParseScope,
) -> crate::ast::SimpleParseRes<'a, Self> {
crate::ast::nom_parse_from_str(i, scope)
}
}
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone, Default)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Define {
#[id(borrow = "&str")]
#[size = 8]
pub attribute_name: ArcStr,
#[id(borrow = "&str")]
#[size = 8]
pub group_name: ArcStr,
#[size = 1]
pub attribute_type: AttributeType,
}
#[derive(Debug, Clone, Copy, Default)]
#[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 {
#[default]
#[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<'a, I: Iterator<Item = &'a Vec<&'a str>>>(
iter: I,
scope: &mut ParseScope,
) -> Result<Self, ComplexParseError> {
let mut i = iter.flat_map(IntoIterator::into_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);
}
let define_id =
crate::ast::define_id(scope.define_map.hasher(), &group_name, &attribute_name);
_ = scope
.define_map
.insert(define_id, DefinedType::Simple(attribute_type));
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)
}
}
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone, Default)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct DefineGroup {
#[id(borrow = "&str")]
#[size = 8]
pub group: ArcStr,
#[id(borrow = "&str")]
#[size = 8]
pub parent_name: ArcStr,
}
impl ComplexAttri for DefineGroup {
#[inline]
fn parse<'a, I: Iterator<Item = &'a Vec<&'a str>>>(
iter: I,
scope: &mut ParseScope,
) -> Result<Self, ComplexParseError> {
let mut i = iter.flat_map(IntoIterator::into_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);
}
let define_id =
crate::ast::define_id(scope.define_map.hasher(), &parent_name, &group);
_ = scope.define_map.insert(define_id, DefinedType::Group);
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)
}
}
#[mut_set::derive::item(sort)]
#[derive(Debug, Clone, Default)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct DefineCellArea {
#[id(borrow = "&str")]
#[size = 8]
pub area_name: ArcStr,
pub resource_type: ResourceType,
}
#[derive(Debug, Clone, Copy, Default)]
#[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 {
#[default]
#[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<'a, I: Iterator<Item = &'a Vec<&'a str>>>(
iter: I,
_scope: &mut ParseScope,
) -> Result<Self, ComplexParseError> {
let mut i = iter.flat_map(IntoIterator::into_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, Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(sort)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct WireLoad {
#[id(borrow = "&str")]
#[size = 8]
#[liberty(name)]
pub name: ArcStr,
#[size = 120]
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[size = 48]
#[liberty(attributes)]
pub attributes: Attributes,
#[size = 8]
#[liberty(simple)]
pub area: NotNan<f64>,
#[size = 8]
#[liberty(simple)]
pub capacitance: NotNan<f64>,
#[size = 8]
#[liberty(simple)]
pub resistance: NotNan<f64>,
#[size = 8]
#[liberty(simple)]
pub slope: NotNan<f64>,
#[size = 48]
#[liberty(complex(type = Set))]
#[serde(serialize_with = "GroupSet::<FanoutLength>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<FanoutLength>::deserialize_with")]
pub fanout_length: GroupSet<FanoutLength>,
}
impl GroupFn for WireLoad {}
#[derive(Debug, Clone, Default, Copy)]
#[mut_set::derive::item(sort)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct FanoutLength {
#[id]
pub fanout: u32,
pub length: NotNan<f64>,
pub average_capacitance: Option<NotNan<f64>>,
pub standard_deviation: Option<NotNan<f64>>,
pub number_of_nets: Option<u32>,
}
impl ComplexAttri for FanoutLength {
#[inline]
fn parse<'a, I: Iterator<Item = &'a Vec<&'a str>>>(
iter: I,
_scope: &mut ParseScope,
) -> Result<Self, ComplexParseError> {
let mut i = iter.flat_map(IntoIterator::into_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) => parse_f64(s)?,
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 {
f.write_int(self.fanout)?;
f.write_str(", ")?;
f.write_float(self.length.into_inner())?;
if let (Some(average_capacitance), Some(standard_deviation), Some(number_of_nets)) =
(self.average_capacitance, self.standard_deviation, self.number_of_nets)
{
f.write_str(", ")?;
f.write_float(average_capacitance.into_inner())?;
f.write_str(", ")?;
f.write_float(standard_deviation.into_inner())?;
f.write_str(", ")?;
f.write_int(number_of_nets)?;
}
Ok(())
}
}
#[derive(Debug, Clone, Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(sort)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct WireLoadSection {
#[id(borrow = "&str")]
#[size = 8]
#[liberty(name)]
pub name: ArcStr,
#[size = 48]
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[size = 48]
#[liberty(attributes)]
pub attributes: Attributes,
#[size = 24]
#[liberty(complex)]
pub wire_load_from_area: (NotNan<f64>, NotNan<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,
scope: &mut ParseScope,
) -> crate::ast::SimpleParseRes<'a, Self> {
crate::ast::nom_parse_from_str(i, scope)
}
}
#[derive(Debug, Clone, Default)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(sort)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct BaseCurves {
#[size = 8]
#[liberty(name)]
#[id(borrow = "&str")]
pub name: ArcStr,
#[size = 72]
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[size = 48]
#[liberty(attributes)]
pub attributes: Attributes,
#[size = 1]
#[liberty(simple)]
pub base_curve_type: BaseCurveType,
#[size = 24]
#[liberty(complex)]
pub curve_x: Vec<NotNan<f64>>,
#[size = 48]
#[liberty(complex(type = Set))]
#[serde(serialize_with = "GroupSet::<IdVector>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<IdVector>::deserialize_with")]
pub curve_y: GroupSet<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");
}"#,
);
}
}