use crate::{
ast::{join_fmt, AttriValue, GroupComments, GroupFn, NamedGroup, SimpleAttri},
common::items::WordSet,
expression::IdBooleanExpression,
pin::Direction,
timing::items::Mode,
ArcStr,
};
use core::{
fmt::{self, Write},
hash::Hash,
str::FromStr,
};
#[derive(Default, Debug, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone,Default);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct LeakagePower {
#[id]
#[liberty(name)]
name: Vec<ArcStr>,
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[liberty(undefined)]
pub undefined: crate::ast::AttributeList,
#[id]
#[liberty(simple(type = Option))]
power_level: Option<ArcStr>,
#[id]
#[liberty(simple)]
related_pg_pin: WordSet,
#[id]
#[liberty(simple(type = Option))]
when: Option<IdBooleanExpression>,
#[liberty(simple)]
value: f64,
#[liberty(complex(type = Option))]
mode: Option<Mode>,
}
impl GroupFn for LeakagePower {}
#[cfg(test)]
mod test_sort {
use super::*;
#[test]
fn test_leakage_sort() {
let cell = crate::ast::test_parse::<crate::Cell>(
r#"(CELL) {
leakage_power () {
related_pg_pin : VDD;
value : 1;
}
leakage_power () {
related_pg_pin : VDD;
when : "A*B*Y";
value : 2;
}
leakage_power () {
related_pg_pin : VDD;
when : "!A*B*!Y";
value : 3;
}
leakage_power () {
related_pg_pin : VDD;
when : "A*!B*!Y";
value : 4;
}
leakage_power () {
related_pg_pin : VDD;
when : "!A*!B*!Y";
value : 5;
}
leakage_power () {
related_pg_pin : VSS;
value : 6;
}
leakage_power () {
related_pg_pin : VSS;
when : "A*B*Y";
value : 7;
}
leakage_power () {
related_pg_pin : VSS;
when : "!A*B*!Y";
value : 8;
}
leakage_power () {
related_pg_pin : VSS;
when : "A*!B*!Y";
value : 9;
}
leakage_power () {
related_pg_pin : VSS;
when : "!A*!B*!Y";
value : 10;
}
}
"#,
);
assert_eq!(
vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
cell
.leakage_power
.into_iter_sort()
.map(|leakage| leakage.value as i8)
.collect::<Vec<_>>()
);
}
}
#[derive(Default, Debug, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item(
sort,
macro(derive(Debug, Clone,Default);)
)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Statetable {
#[id]
#[liberty(name)]
pub input_nodes: Vec<ArcStr>,
#[id]
#[liberty(name)]
pub internal_nodes: Vec<ArcStr>,
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[liberty(undefined)]
pub undefined: crate::ast::AttributeList,
#[liberty(simple)]
pub table: Table,
}
impl GroupFn for Statetable {}
impl NamedGroup for Statetable {
#[inline]
fn parse(mut v: Vec<ArcStr>) -> Result<Self::Name, crate::ast::IdError> {
let l = v.len();
if l != 2 {
return Err(crate::ast::IdError::LengthDismatch(2, l, v));
}
v.pop()
.map_or(Err(crate::ast::IdError::Other("Unkown pop error".into())), |var2| {
v.pop().map_or(
Err(crate::ast::IdError::Other("Unkown pop error".into())),
|var1| {
Ok(Self::Name {
input_nodes: var1.split_ascii_whitespace().map(ArcStr::from).collect(),
internal_nodes: var2.split_ascii_whitespace().map(ArcStr::from).collect(),
})
},
)
})
}
#[inline]
fn name2vec(name: Self::Name) -> Vec<ArcStr> {
vec![name.input_nodes.join(" ").into(), name.internal_nodes.join(" ").into()]
}
}
#[derive(Default, Debug, Clone)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Table {
pub v: Vec<ArcStr>,
}
impl fmt::Display for Table {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.v, f)
}
}
impl FromStr for Table {
type Err = fmt::Error;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self {
v: s
.split("\\\n")
.filter_map(|line| {
let _l = line
.trim_start()
.trim_end_matches(|c: char| c == ',' || c.is_ascii_whitespace());
if _l.is_empty() {
None
} else {
Some(ArcStr::from(_l))
}
})
.collect(),
})
}
}
impl SimpleAttri for Table {
#[inline]
fn is_set(&self) -> bool {
!self.v.is_empty()
}
#[inline]
fn nom_parse<'a>(
i: &'a str,
line_num: &mut usize,
) -> nom::IResult<&'a str, Result<Self, AttriValue>, nom::error::Error<&'a str>> {
let (input, simple_multi) = crate::ast::parser::simple_multi(i, line_num)?;
simple_multi
.parse()
.map_or(Ok((input, Err(AttriValue::Simple(ArcStr::from(simple_multi))))), |s| {
Ok((input, Ok(s)))
})
}
#[inline]
fn fmt_self<T: Write, I: crate::ast::Indentation>(
&self,
f: &mut crate::ast::CodeFormatter<'_, T, I>,
) -> fmt::Result {
let indent = f.indentation();
join_fmt(
self.v.iter(),
f,
|i, ff| write!(ff, "{i}"),
format!(" ,\\\n{indent} ").as_str(),
)
}
}
#[cfg(test)]
mod test_statetable {
use super::*;
#[test]
fn statetable_test() {
_ = crate::ast::test_parse::<Statetable>(
r#"(" CLK EN SE",ENL) {
table : " H L L : - : L ,\
H L H : - : H ,\
H H L : - : H ,\
H H H : - : H ,\
L - - : - : N ";
}
"#,
);
}
}
#[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 PgPin {
#[liberty(name)]
#[id]
name: Option<ArcStr>,
#[liberty(comments)]
pub comments: GroupComments<Self>,
#[liberty(undefined)]
pub undefined: crate::ast::AttributeList,
#[liberty(simple(type = Option))]
pub direction: Option<Direction>,
#[liberty(simple)]
pub voltage_name: ArcStr,
#[liberty(simple)]
pub pg_type: PgType,
#[liberty(simple)]
pub user_pg_type: ArcStr,
#[liberty(simple)]
pub physical_connection: ArcStr,
#[liberty(simple)]
pub related_bias_pin: ArcStr,
}
impl GroupFn for PgPin {}
#[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 PgType {
#[strum(serialize = "primary_power")]
PrimaryPower,
#[strum(serialize = "primary_ground")]
PrimaryGround,
#[strum(serialize = "backup_power")]
BackupPower,
#[strum(serialize = "backup_ground")]
#[default]
BackupGround,
#[strum(serialize = "internal_power")]
InternalPower,
#[strum(serialize = "internal_ground")]
InternalGround,
#[strum(serialize = "pwell")]
Pwell,
#[strum(serialize = "nwell")]
Nwell,
#[strum(serialize = "deepnwell")]
DeepNwell,
#[strum(serialize = "deeppwell")]
DeepPwell,
}
impl SimpleAttri for PgType {
#[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)
}
}