use core::fmt::{self, Write};
use strum_macros::{Display, EnumString};
use crate::{
ast::{
self, CodeFormatter, ComplexAttri, ComplexParseError, GroupComments, GroupFn,
GroupSet, Indentation, ParseScope, SimpleAttri,
},
Ctx,
};
use super::parse_f64;
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound = "C::Other: serde::Serialize + serde::de::DeserializeOwned")]
pub struct CharConfig<C: Ctx> {
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::Other,
#[liberty(attributes)]
pub attributes: ast::Attributes,
#[liberty(simple(type = Option))]
pub internal_power_calculation: Option<InternalPowerCalculation>,
#[liberty(simple(type = Option))]
pub three_state_disable_measurement_method: Option<ThreeStateDisableMeasurementMethod>,
#[liberty(simple(type = Option))]
pub three_state_disable_current_threshold_abs: Option<f64>,
#[liberty(simple(type = Option))]
pub three_state_disable_current_threshold_rel: Option<f64>,
#[liberty(simple(type = Option))]
pub three_state_disable_monitor_node: Option<String>,
#[liberty(simple(type = Option))]
pub three_state_cap_add_to_load_index: Option<bool>,
#[liberty(simple(type = Option))]
pub ccs_timing_segment_voltage_tolerance_rel: Option<f64>,
#[liberty(simple(type = Option))]
pub ccs_timing_delay_tolerance_rel: Option<f64>,
#[liberty(simple(type = Option))]
pub ccs_timing_voltage_margin_tolerance_rel: Option<f64>,
#[liberty(simple(type = Option))]
pub receiver_capacitance1_voltage_lower_threshold_pct_rise: Option<f64>,
#[liberty(simple(type = Option))]
pub receiver_capacitance1_voltage_upper_threshold_pct_rise: Option<f64>,
#[liberty(simple(type = Option))]
pub receiver_capacitance1_voltage_lower_threshold_pct_fall: Option<f64>,
#[liberty(simple(type = Option))]
pub receiver_capacitance1_voltage_upper_threshold_pct_fall: Option<f64>,
#[liberty(simple(type = Option))]
pub receiver_capacitance2_voltage_lower_threshold_pct_rise: Option<f64>,
#[liberty(simple(type = Option))]
pub receiver_capacitance2_voltage_upper_threshold_pct_rise: Option<f64>,
#[liberty(simple(type = Option))]
pub receiver_capacitance2_voltage_lower_threshold_pct_fall: Option<f64>,
#[liberty(simple(type = Option))]
pub receiver_capacitance2_voltage_upper_threshold_pct_fall: Option<f64>,
#[liberty(simple(type = Option))]
pub capacitance_voltage_lower_threshold_pct_rise: Option<f64>,
#[liberty(simple(type = Option))]
pub capacitance_voltage_lower_threshold_pct_fall: Option<f64>,
#[liberty(simple(type = Option))]
pub capacitance_voltage_upper_threshold_pct_rise: Option<f64>,
#[liberty(simple(type = Option))]
pub capacitance_voltage_upper_threshold_pct_fall: Option<f64>,
#[liberty(complex(type = Option))]
pub driver_waveform: Option<[String; 2]>,
#[liberty(complex(type = Option))]
pub driver_waveform_rise: Option<[String; 2]>,
#[liberty(complex(type = Option))]
pub driver_waveform_fall: Option<[String; 2]>,
#[liberty(complex(type = Set))]
#[serde(serialize_with = "GroupSet::<CharModeValue>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<CharModeValue>::deserialize_with")]
pub input_stimulus_transition: GroupSet<CharModeValue>,
#[liberty(complex(type = Set))]
#[serde(serialize_with = "GroupSet::<CharModeValue>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<CharModeValue>::deserialize_with")]
pub input_stimulus_interval: GroupSet<CharModeValue>,
#[liberty(complex(type = Set))]
#[serde(serialize_with = "GroupSet::<CharModeValue>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<CharModeValue>::deserialize_with")]
pub unrelated_output_net_capacitance: GroupSet<CharModeValue>,
#[liberty(complex(type = Set))]
#[serde(serialize_with = "GroupSet::<CharModeMethod>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<CharModeMethod>::deserialize_with")]
pub default_value_selection_method: GroupSet<CharModeMethod>,
#[liberty(complex(type = Set))]
#[serde(serialize_with = "GroupSet::<CharModeMethod>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<CharModeMethod>::deserialize_with")]
pub default_value_selection_method_rise: GroupSet<CharModeMethod>,
#[liberty(complex(type = Set))]
#[serde(serialize_with = "GroupSet::<CharModeMethod>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<CharModeMethod>::deserialize_with")]
pub default_value_selection_method_fall: GroupSet<CharModeMethod>,
#[liberty(complex(type = Set))]
#[serde(serialize_with = "GroupSet::<CharModeValue>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<CharModeValue>::deserialize_with")]
pub merge_tolerance_abs: GroupSet<CharModeValue>,
#[liberty(complex(type = Set))]
#[serde(serialize_with = "GroupSet::<CharModeValue>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<CharModeValue>::deserialize_with")]
pub merge_tolerance_rel: GroupSet<CharModeValue>,
#[liberty(complex(type = Set))]
#[serde(serialize_with = "GroupSet::<CharModeMethod>::serialize_with")]
#[serde(deserialize_with = "GroupSet::<CharModeMethod>::deserialize_with")]
pub merge_selection: GroupSet<CharModeMethod>,
}
impl<C: Ctx> GroupFn for CharConfig<C> {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(EnumString, Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum InternalPowerCalculation {
#[strum(serialize = "exclude_switching_rise", serialize = "exclude_switching_on_rise")]
ExcludeSwitchingOnRise,
#[strum(
serialize = "exclude_switching_rise_and_fall",
serialize = "exclude_switching_on_rise_and_fall"
)]
ExcludeSwitchingOnRiseAndFall,
#[strum(serialize = "include_switching")]
IncludeSwitching,
}
ast::impl_self_builder!(InternalPowerCalculation);
impl SimpleAttri for InternalPowerCalculation {
#[inline]
fn nom_parse<'a>(i: &'a str, scope: &mut ParseScope) -> ast::SimpleParseRes<'a, Self> {
ast::nom_parse_from_str(i, scope)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(EnumString, Display, Default, Hash)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum CharMode {
#[strum(serialize = "all")]
#[default]
All,
#[strum(serialize = "nldm")]
Nldm,
#[strum(serialize = "nldm_delay")]
NldmDelay,
#[strum(serialize = "nldm_transition")]
NldmTransition,
#[strum(serialize = "capacitance")]
Capacitance,
#[strum(serialize = "constraint")]
Constraint,
#[strum(serialize = "constraint_setup")]
ConstraintSetup,
#[strum(serialize = "constraint_hold")]
ConstraintHold,
#[strum(serialize = "constraint_recovery")]
ConstraintRecovery,
#[strum(serialize = "constraint_removal")]
ConstraintRemoval,
#[strum(serialize = "constraint_skew")]
ConstraintSkew,
#[strum(serialize = "constraint_min_pulse_width")]
ConstraintMinPulseWidth,
#[strum(serialize = "constraint_no_change")]
ConstraintNoChange,
#[strum(serialize = "constraint_non_seq_setup")]
ConstraintNonSeqSetup,
#[strum(serialize = "constraint_non_seq_hold")]
ConstraintNonSeqHold,
#[strum(serialize = "constraint_minimum_period")]
ConstraintMinimumPeriod,
#[strum(serialize = "nlpm")]
Nlpm,
#[strum(serialize = "nlpm_leakage")]
NlpmLeakage,
#[strum(serialize = "nlpm_input")]
NlpmInput,
#[strum(serialize = "nlpm_output")]
NlpmOutput,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(EnumString, Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum ThreeStateDisableMeasurementMethod {
#[strum(serialize = "voltage")]
Voltage,
#[strum(serialize = "current")]
Current,
}
ast::impl_self_builder!(ThreeStateDisableMeasurementMethod);
impl SimpleAttri for ThreeStateDisableMeasurementMethod {
#[inline]
fn nom_parse<'a>(i: &'a str, scope: &mut ParseScope) -> ast::SimpleParseRes<'a, Self> {
ast::nom_parse_from_str(i, scope)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(EnumString, Display, Default)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum SelectionMethod {
#[strum(serialize = "any")]
#[default]
Any,
#[strum(serialize = "min")]
Min,
#[strum(serialize = "max")]
Max,
#[strum(serialize = "average")]
Average,
#[strum(serialize = "min_mid_table ")]
MinMidTable,
#[strum(serialize = "max_mid_table")]
MaxMidTable,
#[strum(serialize = "follow_delay")]
FollowDelay,
}
#[derive(Debug, Clone, Default, Copy)]
#[mut_set::derive::item(sort)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct CharModeMethod {
#[id]
char_mode: CharMode,
method: SelectionMethod,
}
ast::impl_self_builder!(CharModeMethod);
impl ComplexAttri for CharModeMethod {
#[inline]
fn parse<'a, I: Iterator<Item = &'a &'a str>>(
iter: I,
_scope: &mut ParseScope,
) -> Result<Self, ComplexParseError> {
let mut i = iter;
let char_mode = match i.next() {
Some(&s) => s.parse()?,
None => return Err(ComplexParseError::LengthDismatch),
};
let method = match i.next() {
Some(s) => s.parse()?,
None => return Err(ComplexParseError::LengthDismatch),
};
if i.next().is_some() {
return Err(ComplexParseError::LengthDismatch);
}
Ok(Self { char_mode, method })
}
#[inline]
fn fmt_self<T: Write, I: Indentation>(
&self,
f: &mut CodeFormatter<'_, T, I>,
) -> fmt::Result {
write!(f, "{}", self.char_mode)?;
f.write_str(", ")?;
write!(f, "{}", self.method)
}
}
#[derive(Debug, Clone, Default, Copy)]
#[mut_set::derive::item(sort)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct CharModeValue {
#[id]
char_mode: CharMode,
value: f64,
}
ast::impl_self_builder!(CharModeValue);
impl ComplexAttri for CharModeValue {
#[inline]
fn parse<'a, I: Iterator<Item = &'a &'a str>>(
iter: I,
_scope: &mut ParseScope,
) -> Result<Self, ComplexParseError> {
let mut i = iter;
let char_mode = match i.next() {
Some(&s) => s.parse()?,
None => return Err(ComplexParseError::LengthDismatch),
};
let value = match i.next() {
Some(s) => parse_f64(s)?,
None => return Err(ComplexParseError::LengthDismatch),
};
if i.next().is_some() {
return Err(ComplexParseError::LengthDismatch);
}
Ok(Self { char_mode, value })
}
#[inline]
fn fmt_self<T: Write, I: Indentation>(
&self,
f: &mut CodeFormatter<'_, T, I>,
) -> fmt::Result {
write!(f, "{}", self.char_mode)?;
f.write_str(", ")?;
f.write_num(self.value)
}
}
#[cfg(test)]
mod test {
use crate::DefaultCtx;
#[test]
fn char_config() {
let g = crate::ast::test_parse_fmt::<super::CharConfig<DefaultCtx>>(
r#"() {
/* library level default attributes*/
driver_waveform(all, input_driver);
input_stimulus_transition(all, 0.1);
input_stimulus_interval(all, 100.0);
unrelated_output_net_capacitance(all, 1.0);
default_value_selection_method(all, any);
merge_tolerance_abs( nldm, 0.1) ;
merge_tolerance_abs( constraint, 0.1) ;
merge_tolerance_abs( capacitance, 0.01) ;
merge_tolerance_abs( nlpm, 0.05) ;
merge_tolerance_rel( all, 2.0) ;
merge_selection( all, max) ;
internal_power_calculation : exclude_switching_rise;
three_state_disable_measurement_method : current;
three_state_disable_current_threshold_abs : 0.05;
three_state_disable_current_threshold_rel : 2.0;
three_state_disable_monitor_node : tri_monitor;
three_state_cap_add_to_load_index : true;
ccs_timing_segment_voltage_tolerance_rel: 1.0 ;
ccs_timing_delay_tolerance_rel: 2.0 ;
ccs_timing_voltage_margin_tolerance_rel: 1.0 ;
receiver_capacitance1_voltage_lower_threshold_pct_rise : 20.0;
receiver_capacitance1_voltage_upper_threshold_pct_rise : 50.0;
receiver_capacitance1_voltage_lower_threshold_pct_fall : 50.0;
receiver_capacitance1_voltage_upper_threshold_pct_fall : 80.0;
receiver_capacitance2_voltage_lower_threshold_pct_rise : 20.0;
receiver_capacitance2_voltage_upper_threshold_pct_rise : 50.0;
receiver_capacitance2_voltage_lower_threshold_pct_fall : 50.0;
receiver_capacitance2_voltage_upper_threshold_pct_fall : 80.0;
capacitance_voltage_lower_threshold_pct_rise : 20.0;
capacitance_voltage_lower_threshold_pct_fall : 50.0;
capacitance_voltage_upper_threshold_pct_rise : 50.0;
capacitance_voltage_upper_threshold_pct_fall : 80.0;
}"#,
r#"
liberty_db::common::char_config::CharConfig () {
| internal_power_calculation : exclude_switching_on_rise;
| three_state_disable_measurement_method : current;
| three_state_disable_current_threshold_abs : 0.05;
| three_state_disable_current_threshold_rel : 2.0;
| three_state_disable_monitor_node : tri_monitor;
| three_state_cap_add_to_load_index : true;
| ccs_timing_segment_voltage_tolerance_rel : 1.0;
| ccs_timing_delay_tolerance_rel : 2.0;
| ccs_timing_voltage_margin_tolerance_rel : 1.0;
| receiver_capacitance1_voltage_lower_threshold_pct_rise : 20.0;
| receiver_capacitance1_voltage_upper_threshold_pct_rise : 50.0;
| receiver_capacitance1_voltage_lower_threshold_pct_fall : 50.0;
| receiver_capacitance1_voltage_upper_threshold_pct_fall : 80.0;
| receiver_capacitance2_voltage_lower_threshold_pct_rise : 20.0;
| receiver_capacitance2_voltage_upper_threshold_pct_rise : 50.0;
| receiver_capacitance2_voltage_lower_threshold_pct_fall : 50.0;
| receiver_capacitance2_voltage_upper_threshold_pct_fall : 80.0;
| capacitance_voltage_lower_threshold_pct_rise : 20.0;
| capacitance_voltage_lower_threshold_pct_fall : 50.0;
| capacitance_voltage_upper_threshold_pct_rise : 50.0;
| capacitance_voltage_upper_threshold_pct_fall : 80.0;
| input_stimulus_transition (all, 0.1);
| input_stimulus_interval (all, 100.0);
| unrelated_output_net_capacitance (all, 1.0);
| default_value_selection_method (all, any);
| merge_tolerance_abs (nldm, 0.1);
| merge_tolerance_abs (capacitance, 0.01);
| merge_tolerance_abs (constraint, 0.1);
| merge_tolerance_abs (nlpm, 0.05);
| merge_tolerance_rel (all, 2.0);
| merge_selection (all, max);
}"#,
);
}
}