use crate::{
ast::{
AttributeList, ComplexAttri, ComplexParseError, GroupComments, GroupFn, SimpleAttri,
},
common::table::{
TableLookUp, TableLookUp2D, TableLookUpMultiSegment, Vector3DGrpup, Vector4DGrpup,
},
expression::IdBooleanExpression,
timing::items::Mode,
ArcStr, GroupSet,
};
use num_traits::Zero;
#[derive(Debug, Default, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone,Default);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct CCSNStage {
#[liberty(name)]
#[id]
pub name: Vec<ArcStr>,
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[liberty(undefined)]
pub undefined: AttributeList,
#[liberty(simple(type = Option))]
pub load_cap_fall: Option<f64>,
#[liberty(simple(type = Option))]
pub load_cap_rise: Option<f64>,
#[liberty(simple)]
pub is_inverting: bool,
#[liberty(simple)]
pub is_needed: bool,
#[liberty(simple(type = Option))]
pub is_pass_gate: Option<bool>,
#[liberty(simple)]
pub miller_cap_fall: f64,
#[liberty(simple)]
pub miller_cap_rise: f64,
#[id]
#[liberty(simple(type = Option))]
pub related_ccb_node: Option<ArcStr>,
#[liberty(simple)]
pub stage_type: StageType,
#[id]
#[liberty(simple(type = Option))]
pub when: Option<IdBooleanExpression>,
#[liberty(complex(type = Option))]
pub mode: Option<Mode>,
#[liberty(group(type = Option))]
pub dc_current: Option<TableLookUp2D>,
#[liberty(group(type = Option))]
pub output_voltage_fall: Option<Vector3DGrpup>,
#[liberty(group(type = Option))]
pub output_voltage_rise: Option<Vector3DGrpup>,
#[liberty(group(type = Option))]
pub propagated_noise_low: Option<Vector4DGrpup>,
#[liberty(group(type = Option))]
pub propagated_noise_high: Option<Vector4DGrpup>,
}
impl GroupFn for CCSNStage {
#[inline]
fn post_process(&mut self) {
if self.miller_cap_fall.is_sign_negative() {
self.miller_cap_fall.set_zero();
warn!("miller_cap_fall is negative!");
}
if self.miller_cap_rise.is_sign_negative() {
self.miller_cap_rise.set_zero();
warn!("miller_cap_rise is negative!");
}
}
}
#[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 StageType {
#[strum(serialize = "pull_up")]
PullUp,
#[strum(serialize = "pull_down")]
PullDown,
#[strum(serialize = "both")]
#[default]
Both,
}
impl SimpleAttri for StageType {}
#[derive(Debug, Default, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone,Default);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct ReceiverCapacitance {
#[id]
#[liberty(name)]
name: Option<ArcStr>,
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[liberty(undefined)]
pub undefined: AttributeList,
#[id]
#[liberty(simple(type=Option))]
pub when: Option<IdBooleanExpression>,
#[liberty(group(type=Set))]
pub receiver_capacitance_fall: GroupSet<TableLookUpMultiSegment>,
#[liberty(group(type=Set))]
pub receiver_capacitance_rise: GroupSet<TableLookUpMultiSegment>,
#[liberty(group)]
pub receiver_capacitance1_fall: Option<TableLookUp>,
#[liberty(group)]
pub receiver_capacitance1_rise: Option<TableLookUp>,
#[liberty(group)]
pub receiver_capacitance2_fall: Option<TableLookUp>,
#[liberty(group)]
pub receiver_capacitance2_rise: Option<TableLookUp>,
}
impl GroupFn for ReceiverCapacitance {}
#[derive(Debug, Clone, Default)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct PropagatingCcb {
pub input_ccb_name: ArcStr,
pub output_ccb_name: Option<ArcStr>,
}
impl ComplexAttri for PropagatingCcb {
#[inline]
fn parse(v: &[&str]) -> Result<Self, ComplexParseError> {
let mut i = v.iter();
let input_ccb_name = match i.next() {
Some(&s) => ArcStr::from(s),
None => return Err(ComplexParseError::LengthDismatch),
};
let output_ccb_name = i.next().map(|&s| ArcStr::from(s));
if i.next().is_some() {
return Err(ComplexParseError::LengthDismatch);
}
Ok(Self { input_ccb_name, output_ccb_name })
}
#[allow(clippy::or_fun_call)]
#[inline]
fn to_wrapper(&self) -> crate::ast::ComplexWrapper {
self
.output_ccb_name
.as_ref()
.map_or(vec![vec![self.input_ccb_name.clone()]], |output_ccb_name| {
vec![vec![self.input_ccb_name.clone(), output_ccb_name.clone()]]
})
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn parse_file() -> anyhow::Result<()> {
use std::fs::File;
use std::io::{BufWriter, Write};
let filepath = "tests/tech/ccsn.lib";
let data = std::fs::read_to_string(filepath).expect("Failed to open file.");
match crate::library::Library::parse(&data) {
Ok(library) => {
let file = File::create("output.lib")?;
let mut writer = BufWriter::new(file);
write!(&mut writer, "{library}")?;
}
Err(e) => panic!("[ERROR] {e:?}"),
}
Ok(())
}
}