use crate::{
Ctx,
ast::{
Attributes, BuilderScope, CodeFormatter, ComplexAttri, ComplexParseError,
GroupComments, GroupFn, Indentation, LibertySet, ParseScope,
},
expression::LogicBooleanExpression,
table::{
TableLookUp, TableLookUp2D, TableLookUpMultiSegment, Vector3DGrpup, Vector4DGrpup,
},
};
use core::fmt::{self, Write};
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound = "C::Other: serde::Serialize + serde::de::DeserializeOwned")]
pub struct CCSNStage<C: 'static + Ctx> {
#[liberty(name)]
#[id(borrow = [String])]
pub name: Vec<String>,
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::Other,
#[liberty(attributes)]
pub attributes: Attributes,
#[liberty(simple)]
pub load_cap_fall: Option<f64>,
#[liberty(simple)]
pub load_cap_rise: Option<f64>,
#[liberty(simple)]
pub is_inverting: Option<bool>,
#[liberty(simple)]
pub is_needed: Option<bool>,
#[liberty(simple)]
pub is_pass_gate: Option<bool>,
#[liberty(simple)]
pub miller_cap_fall: Option<f64>,
#[liberty(simple)]
pub miller_cap_rise: Option<f64>,
#[liberty(simple)]
#[id]
pub related_ccb_node: Option<String>,
#[liberty(simple)]
pub stage_type: Option<StageType>,
#[liberty(simple)]
#[id]
pub when: Option<LogicBooleanExpression>,
#[liberty(complex)]
pub mode: Option<[String; 2]>,
#[liberty(group)]
#[liberty(after_build = TableLookUp2D::use_common_template)]
pub dc_current: Option<TableLookUp2D<C>>,
#[liberty(group)]
pub output_voltage_fall: Option<Vector3DGrpup<C>>,
#[liberty(group)]
pub output_voltage_rise: Option<Vector3DGrpup<C>>,
#[liberty(group)]
pub propagated_noise_low: Option<Vector4DGrpup<C>>,
#[liberty(group)]
pub propagated_noise_high: Option<Vector4DGrpup<C>>,
}
impl<C: 'static + Ctx> GroupFn<C> for CCSNStage<C> {
#[inline]
fn before_build(builder: &mut Self::Builder, _scope: &mut BuilderScope<C>) {
if let Some(miller_cap_fall) = builder.miller_cap_fall.as_mut()
&& miller_cap_fall.is_sign_negative()
{
*miller_cap_fall = 0.0;
crate::warn!("miller_cap_fall is negative!");
}
if let Some(miller_cap_rise) = builder.miller_cap_rise.as_mut()
&& miller_cap_rise.is_sign_negative()
{
*miller_cap_rise = 0.0;
crate::warn!("miller_cap_rise is negative!");
}
}
}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd, Default)]
#[derive(strum::EnumString, strum::EnumIter, strum::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum StageType {
#[strum(serialize = "pull_up")]
PullUp,
#[strum(serialize = "pull_down")]
PullDown,
#[strum(serialize = "both")]
#[default]
Both,
}
crate::ast::impl_self_builder!(StageType);
crate::ast::impl_simple!(StageType);
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound = "C::Other: serde::Serialize + serde::de::DeserializeOwned")]
pub struct ReceiverCapacitance<C: 'static + Ctx> {
#[liberty(name)]
#[id]
pub name: Option<String>,
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::Other,
#[liberty(attributes)]
pub attributes: Attributes,
#[liberty(simple)]
#[id]
pub when: Option<LogicBooleanExpression>,
#[liberty(group)]
#[liberty(after_build = TableLookUpMultiSegment::use_common_template)]
pub receiver_capacitance_fall: LibertySet<TableLookUpMultiSegment<C>>,
#[liberty(group)]
#[liberty(after_build = TableLookUpMultiSegment::use_common_template)]
pub receiver_capacitance_rise: LibertySet<TableLookUpMultiSegment<C>>,
#[liberty(complex)]
pub active_input_ccb: Vec<String>,
#[liberty(group)]
#[liberty(after_build = TableLookUp::use_common_template)]
pub receiver_capacitance1_fall: Option<TableLookUp<C>>,
#[liberty(group)]
#[liberty(after_build = TableLookUp::use_common_template)]
pub receiver_capacitance1_rise: Option<TableLookUp<C>>,
#[liberty(group)]
#[liberty(after_build = TableLookUp::use_common_template)]
pub receiver_capacitance2_fall: Option<TableLookUp<C>>,
#[liberty(group)]
#[liberty(after_build = TableLookUp::use_common_template)]
pub receiver_capacitance2_rise: Option<TableLookUp<C>>,
}
impl<C: 'static + Ctx> GroupFn<C> for ReceiverCapacitance<C> {}
#[derive(Debug, Clone)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct PropagatingCcb {
pub input_ccb_name: String,
pub output_ccb_name: Option<String>,
}
crate::ast::impl_self_builder!(PropagatingCcb);
impl<C: 'static + Ctx> ComplexAttri<C> for PropagatingCcb {
#[inline]
fn parse<'a, I: Iterator<Item = &'a &'a str>>(
mut iter: I,
_scope: &mut ParseScope<'_>,
) -> Result<Self, ComplexParseError> {
let input_ccb_name = match iter.next() {
Some(&s) => String::from(s),
None => return Err(ComplexParseError::LengthDismatch),
};
let output_ccb_name = iter.next().map(|&s| String::from(s));
if iter.next().is_some() {
return Err(ComplexParseError::LengthDismatch);
}
Ok(Self { input_ccb_name, output_ccb_name })
}
#[expect(clippy::or_fun_call)]
#[inline]
fn fmt_self<T: Write, I: Indentation>(
&self,
f: &mut CodeFormatter<'_, T, I>,
) -> fmt::Result {
self
.output_ccb_name
.as_ref()
.map_or(write!(f, "{}", self.input_ccb_name), |output_ccb_name| {
write!(f, "{}, {}", self.input_ccb_name, output_ccb_name)
})
}
}