use crate::{
Ctx,
ast::{
self, Attributes, ComplexAttri, ComplexParseError, GroupComments, GroupFn, GroupSet,
ParseScope,
},
};
#[cfg(feature = "lut_template")]
use alloc::sync::Arc;
use core::fmt::{self, Write};
#[cfg(not(feature = "lut_template"))]
use core::marker::PhantomData;
use strum::{Display, EnumString};
pub trait TableCtx<C: Ctx> {
#[cfg(feature = "lut_template")]
fn lut_template(&self) -> &Option<Arc<TableTemple<C>>>;
#[cfg(feature = "lut_template")]
fn set_lut_template(&mut self, template: Option<&Arc<TableTemple<C>>>);
}
pub trait CompactTableCtx<C: Ctx> {
#[cfg(feature = "lut_template")]
fn compact_lut_template(&self) -> &Option<Arc<CompactLutTemplate<C>>>;
#[cfg(feature = "lut_template")]
fn set_compact_lut_template(&mut self, template: Option<&Arc<CompactLutTemplate<C>>>);
}
macro_rules! use_common_template {
($table:tt, $scope:tt) => {
#[cfg(feature = "lut_template")]
crate::table::TableCtx::set_lut_template(
&mut $table.extra_ctx,
$scope.lu_table_template.get(&$table.name),
)
};
}
pub(crate) use use_common_template;
macro_rules! use_power_template {
($table:tt, $scope:tt) => {
#[cfg(feature = "lut_template")]
crate::table::TableCtx::set_lut_template(
&mut $table.extra_ctx,
$scope.power_lut_template.get(&$table.name),
)
};
}
pub(crate) use use_power_template;
macro_rules! use_current_template {
($table:tt, $scope:tt) => {
#[cfg(feature = "lut_template")]
crate::table::TableCtx::set_lut_template(
&mut $table.extra_ctx,
$scope.output_current_template.get(&$table.name),
)
};
}
pub(crate) use use_current_template;
macro_rules! use_compact_template {
($table:tt, $scope:tt) => {
#[cfg(feature = "lut_template")]
crate::table::CompactTableCtx::set_compact_lut_template(
&mut $table.extra_ctx,
$scope.compact_lut_template.get(&$table.name),
)
};
}
pub(crate) use use_compact_template;
#[derive(Clone, Default, Debug)]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound = "C::Other: serde::Serialize + serde::de::DeserializeOwned")]
pub struct DefaultTableCtx<C: Ctx> {
#[cfg(feature = "lut_template")]
pub lut_template: Option<Arc<TableTemple<C>>>,
#[cfg(not(feature = "lut_template"))]
___p: PhantomData<C::Other>,
}
impl<C: Ctx> TableCtx<C> for DefaultTableCtx<C> {
#[inline]
#[cfg(feature = "lut_template")]
fn lut_template(&self) -> &Option<Arc<TableTemple<C>>> {
&self.lut_template
}
#[inline]
#[cfg(feature = "lut_template")]
fn set_lut_template(&mut self, template: Option<&Arc<TableTemple<C>>>) {
self.lut_template = template.cloned();
}
}
#[derive(Clone, Default, Debug)]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound = "C::Other: serde::Serialize + serde::de::DeserializeOwned")]
pub struct DefaultCompactTableCtx<C: Ctx> {
#[cfg(feature = "lut_template")]
pub compact_lut_template: Option<Arc<CompactLutTemplate<C>>>,
#[cfg(not(feature = "lut_template"))]
___p: PhantomData<C::Other>,
}
impl<C: Ctx> CompactTableCtx<C> for DefaultCompactTableCtx<C> {
#[inline]
#[cfg(feature = "lut_template")]
fn compact_lut_template(&self) -> &Option<Arc<CompactLutTemplate<C>>> {
&self.compact_lut_template
}
#[inline]
#[cfg(feature = "lut_template")]
fn set_compact_lut_template(&mut self, template: Option<&Arc<CompactLutTemplate<C>>>) {
self.compact_lut_template = template.cloned();
}
}
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")]
pub struct TableLookUpMultiSegment<C: Ctx> {
#[liberty(name)]
#[id(borrow = str)]
pub name: String,
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::Table,
#[liberty(attributes)]
pub attributes: Attributes,
#[id]
#[liberty(simple)]
segment: usize,
#[liberty(complex)]
pub index_1: Vec<f64>,
#[liberty(complex)]
pub index_2: Vec<f64>,
#[liberty(complex)]
pub index_3: Vec<f64>,
#[liberty(complex)]
pub index_4: Vec<f64>,
#[liberty(complex)]
pub values: Values,
}
#[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 DriverWaveform<C: Ctx> {
#[liberty(name)]
#[id(borrow = str)]
pub name: String,
#[liberty(simple(type = Option))]
#[id]
pub driver_waveform_name: Option<String>,
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::Other,
#[liberty(attributes)]
pub attributes: Attributes,
#[liberty(complex)]
pub index_1: Vec<f64>,
#[liberty(complex)]
pub index_2: Vec<f64>,
#[liberty(complex)]
pub index_3: Vec<f64>,
#[liberty(complex)]
pub index_4: Vec<f64>,
#[liberty(complex)]
pub values: Values,
}
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")]
pub struct TableLookUp2D<C: Ctx> {
#[liberty(name)]
#[id(borrow = str)]
pub name: String,
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::Table,
#[liberty(attributes)]
pub attributes: Attributes,
#[liberty(complex)]
pub index_1: Vec<f64>,
#[liberty(complex)]
pub index_2: Vec<f64>,
#[liberty(complex)]
pub values: Values,
}
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct CompactLutTemplate<C: Ctx> {
#[liberty(name)]
#[id(borrow = str)]
pub name: String,
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::CompactTable,
#[liberty(attributes)]
pub attributes: Attributes,
#[liberty(simple(type = Option))]
pub base_curves_group: Option<String>,
#[liberty(simple(type = Option))]
pub variable_1: Option<VariableTypeCompactLutTemplateIndex12>,
#[liberty(complex)]
pub index_1: Vec<f64>,
#[liberty(simple(type = Option))]
pub variable_2: Option<VariableTypeCompactLutTemplateIndex12>,
#[liberty(complex)]
pub index_2: Vec<f64>,
#[liberty(simple(type = Option))]
pub variable_3: Option<VariableTypeCompactLutTemplateIndex3>,
#[liberty(complex)]
pub index_3: Vec<String>,
}
impl<C: Ctx> GroupFn<C> for CompactLutTemplate<C> {
#[cfg(feature = "lut_template")]
fn after_build(&mut self, scope: &mut ast::BuilderScope<C>) {
self
.extra_ctx
.set_compact_lut_template(scope.compact_lut_template.get(&self.name));
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(strum::Display, strum::EnumString)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum VariableTypeCompactLutTemplateIndex12 {
#[strum(serialize = "input_net_transition")]
InputNetTransition,
#[strum(serialize = "total_output_net_capacitance")]
TotalOutputNetCapacitance,
}
crate::ast::impl_self_builder!(VariableTypeCompactLutTemplateIndex12);
crate::ast::impl_simple!(VariableTypeCompactLutTemplateIndex12);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(strum::Display, strum::EnumString)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum VariableTypeCompactLutTemplateIndex3 {
#[strum(serialize = "curve_parameters")]
CurveParameters,
}
crate::ast::impl_self_builder!(VariableTypeCompactLutTemplateIndex3);
crate::ast::impl_simple!(VariableTypeCompactLutTemplateIndex3);
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")]
pub struct Vector3D<C: Ctx> {
#[liberty(name)]
#[id(borrow = str)]
pub name: String,
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::Table,
#[liberty(attributes)]
pub attributes: Attributes,
#[id(into_hash_ord_fn = crate::common::f64_into_hash_ord_fn)]
#[liberty(complex)]
pub index_1: f64,
#[id(into_hash_ord_fn = crate::common::f64_into_hash_ord_fn)]
#[liberty(complex)]
pub index_2: f64,
#[liberty(complex)]
pub index_3: Vec<f64>,
#[liberty(complex)]
pub values: Vec<f64>,
}
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")]
pub struct ReferenceTimeVector3D<C: Ctx> {
#[liberty(name)]
#[id(borrow = str)]
pub name: String,
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::Table,
#[liberty(attributes)]
pub attributes: Attributes,
#[id(into_hash_ord_fn = crate::common::f64_into_hash_ord_fn)]
#[liberty(simple)]
pub reference_time: f64,
#[id(into_hash_ord_fn = crate::common::f64_into_hash_ord_fn)]
#[liberty(complex)]
pub index_1: f64,
#[id(into_hash_ord_fn = crate::common::f64_into_hash_ord_fn)]
#[liberty(complex)]
pub index_2: f64,
#[liberty(complex)]
pub index_3: Vec<f64>,
#[liberty(complex)]
pub values: Vec<f64>,
}
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")]
pub struct Vector4D<C: Ctx> {
#[liberty(name)]
#[id(borrow = str)]
pub name: String,
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::Table,
#[liberty(attributes)]
pub attributes: Attributes,
#[id(into_hash_ord_fn = crate::common::f64_into_hash_ord_fn)]
#[liberty(complex)]
pub index_1: f64,
#[id(into_hash_ord_fn = crate::common::f64_into_hash_ord_fn)]
#[liberty(complex)]
pub index_2: f64,
#[id(into_hash_ord_fn = crate::common::f64_into_hash_ord_fn)]
#[liberty(complex)]
pub index_3: f64,
#[liberty(complex)]
pub index_4: Vec<f64>,
#[liberty(complex)]
pub values: Vec<f64>,
}
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")]
pub struct CompactCcsPower<C: Ctx> {
#[liberty(name)]
#[id(borrow = str)]
pub name: String,
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::CompactTable,
#[liberty(attributes)]
pub attributes: Attributes,
#[liberty(simple(type = Option))]
pub base_curves_group: Option<String>,
#[liberty(simple(type = Option))]
pub index_output: Option<String>,
#[liberty(complex)]
pub index_1: Vec<f64>,
#[liberty(complex)]
pub index_2: Vec<f64>,
#[liberty(complex)]
pub index_3: Vec<f64>,
#[liberty(complex)]
pub index_4: Vec<String>,
#[liberty(complex)]
pub values: Vec<CcsPowerValue>,
}
#[derive(Debug, Clone)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct CcsPowerValue {
pub init_time: f64,
pub init_current: f64,
pub points: Vec<CcsPowerPoint>,
}
#[derive(Debug, Clone, Copy)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct CcsPowerPoint {
pub bc_id: usize,
pub point_time: f64,
pub point_current: f64,
}
crate::ast::impl_self_builder!(Vec<CcsPowerValue>);
impl<C: Ctx> ComplexAttri<C> for Vec<CcsPowerValue> {
#[inline]
fn parse<'a, I: Iterator<Item = &'a &'a str>>(
_iter: I,
_scope: &mut ParseScope<'_>,
) -> Result<Self, ComplexParseError> {
unreachable!()
}
#[inline]
#[expect(clippy::arithmetic_side_effects)]
fn nom_parse<'a>(
i: &'a str,
scope: &mut ParseScope<'_>,
) -> ast::ComplexParseRes<'a, Self> {
match ast::parser::complex_ccs_power_values(i, &mut scope.loc.line_num) {
Ok((_i, vec)) => {
let res = vec
.into_iter()
.map(|(n, v)| {
scope.loc.line_num += n;
v
})
.collect();
Ok((_i, Ok(res)))
}
Err(_) => {
Err(nom::Err::Error(nom::error::Error::new(i, nom::error::ErrorKind::ManyMN)))
}
}
}
#[inline]
#[expect(clippy::items_after_statements)]
fn fmt_self<T: Write, I: ast::Indentation>(
&self,
f: &mut ast::CodeFormatter<'_, T, I>,
) -> fmt::Result {
let mut iter = self.iter();
#[inline]
fn fmt_point<T: Write, I: ast::Indentation>(
point: &CcsPowerPoint,
f: &mut ast::CodeFormatter<'_, T, I>,
) -> fmt::Result {
f.write_num(point.bc_id)?;
f.write_str(", ")?;
f.write_num(point.point_time)?;
f.write_str(", ")?;
f.write_num(point.point_current)
}
#[inline]
fn fmt_value<T: Write, I: ast::Indentation>(
value: &CcsPowerValue,
f: &mut ast::CodeFormatter<'_, T, I>,
) -> fmt::Result {
write!(f, "\"")?;
f.write_num(value.init_time)?;
f.write_str(", ")?;
f.write_num(value.init_current)?;
if !value.points.is_empty() {
f.write_str(", ")?;
ast::join_fmt_no_quote(
value.points.iter(),
f,
|point, ff| fmt_point(point, ff),
|ff| write!(ff, ", "),
)?;
}
write!(f, "\"")
}
if let Some(value) = iter.next() {
fmt_value(value, f)?;
}
while let Some(value) = iter.next() {
write!(f, ", \\")?;
f.write_new_line_indentation()?;
fmt_value(value, f)?;
}
Ok(())
}
}
#[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 Vector3DGrpup<C: 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(group(type = Set))]
#[liberty(after_build = use_common_template!)]
pub vector: GroupSet<Vector3D<C>>,
}
#[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 ReferenceTimeVector3DGrpup<C: 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(group(type = Set))]
#[liberty(after_build = use_current_template!)]
pub vector: GroupSet<ReferenceTimeVector3D<C>>,
}
#[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 Vector4DGrpup<C: 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(group(type = Set))]
#[liberty(after_build = use_common_template!)]
pub vector: GroupSet<Vector4D<C>>,
}
impl<C: Ctx> GroupFn<C> for Vector4DGrpup<C> {}
impl<C: Ctx> GroupFn<C> for Vector3DGrpup<C> {}
impl<C: Ctx> GroupFn<C> for Vector3D<C> {}
impl<C: Ctx> GroupFn<C> for Vector4D<C> {}
impl<C: Ctx> GroupFn<C> for ReferenceTimeVector3D<C> {}
impl<C: Ctx> GroupFn<C> for ReferenceTimeVector3DGrpup<C> {}
impl<C: Ctx> GroupFn<C> for CompactCcsPower<C> {}
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")]
pub struct OcvSigmaTable<C: Ctx> {
#[liberty(name)]
#[id(borrow = str)]
pub name: String,
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::Table,
#[liberty(attributes)]
pub attributes: Attributes,
#[liberty(simple)]
#[id]
pub sigma_type: SigmaType,
#[liberty(complex)]
pub index_1: Vec<f64>,
#[liberty(complex)]
pub index_2: Vec<f64>,
#[liberty(complex)]
pub values: Values,
}
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound = "C::CompactTable: serde::Serialize + serde::de::DeserializeOwned")]
pub struct CompactCcsTable<C: Ctx> {
#[liberty(name)]
#[id(borrow = str)]
pub name: String,
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::CompactTable,
#[liberty(attributes)]
pub attributes: Attributes,
#[liberty(simple)]
pub base_curves_group: String,
#[liberty(complex)]
pub values: Values,
}
impl<C: Ctx> GroupFn<C> for CompactCcsTable<C> {}
#[derive(Debug, Clone)]
#[derive(liberty_macros::Group)]
#[mut_set::derive::item]
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(bound = "C::Table: serde::Serialize + serde::de::DeserializeOwned")]
pub struct TableLookUp<C: Ctx> {
#[liberty(name)]
#[id(borrow = str)]
pub name: String,
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::Table,
#[liberty(attributes)]
pub attributes: Attributes,
#[liberty(complex)]
pub index_1: Vec<f64>,
#[liberty(complex)]
pub index_2: Vec<f64>,
#[liberty(complex)]
pub index_3: Vec<f64>,
#[liberty(complex)]
pub index_4: Vec<f64>,
#[liberty(complex)]
pub values: Values,
}
impl<C: Ctx> GroupFn<C> for TableLookUp<C> {
#[expect(clippy::arithmetic_side_effects)]
fn before_build(builder: &mut Self::Builder, _: &mut ast::BuilderScope<C>) {
if builder.values.chunk_size == builder.values.inner.len()
&& builder.values.inner.len() == builder.index_1.len() * builder.index_2.len()
{
builder.values.chunk_size = builder.index_2.len();
}
}
}
impl<C: Ctx> GroupFn<C> for TableLookUpMultiSegment<C> {
#[expect(clippy::arithmetic_side_effects)]
fn before_build(builder: &mut Self::Builder, _: &mut ast::BuilderScope<C>) {
if builder.values.chunk_size == builder.values.inner.len()
&& builder.values.inner.len() == builder.index_1.len() * builder.index_2.len()
{
builder.values.chunk_size = builder.index_2.len();
}
}
}
impl<C: Ctx> GroupFn<C> for TableLookUp2D<C> {
#[expect(clippy::arithmetic_side_effects)]
fn before_build(builder: &mut Self::Builder, _: &mut ast::BuilderScope<C>) {
if builder.values.chunk_size == builder.values.inner.len()
&& builder.values.inner.len() == builder.index_1.len() * builder.index_2.len()
{
builder.values.chunk_size = builder.index_2.len();
}
}
}
impl<C: Ctx> GroupFn<C> for OcvSigmaTable<C> {
#[expect(clippy::arithmetic_side_effects)]
fn before_build(builder: &mut Self::Builder, _: &mut ast::BuilderScope<C>) {
if builder.values.chunk_size == builder.values.inner.len()
&& builder.values.inner.len() == builder.index_1.len() * builder.index_2.len()
{
builder.values.chunk_size = builder.index_2.len();
}
}
}
impl<C: Ctx> GroupFn<C> for DriverWaveform<C> {
#[expect(clippy::arithmetic_side_effects)]
fn before_build(builder: &mut Self::Builder, _: &mut ast::BuilderScope<C>) {
if builder.values.chunk_size == builder.values.inner.len()
&& builder.values.inner.len() == builder.index_1.len() * builder.index_2.len()
{
builder.values.chunk_size = builder.index_2.len();
}
}
}
#[derive(Debug, Default, Clone)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Values {
pub chunk_size: usize,
pub inner: Vec<f64>,
}
crate::ast::impl_self_builder!(Values);
impl<C: Ctx> ComplexAttri<C> for Values {
#[inline]
fn parse<'a, I: Iterator<Item = &'a &'a str>>(
_iter: I,
_scope: &mut ParseScope<'_>,
) -> Result<Self, ComplexParseError> {
unreachable!()
}
#[inline]
#[expect(clippy::arithmetic_side_effects)]
fn nom_parse<'a>(
i: &'a str,
scope: &mut ParseScope<'_>,
) -> ast::ComplexParseRes<'a, Self> {
match ast::parser::complex_values(i, &mut scope.loc.line_num) {
Ok((_i, vec)) => {
let mut chunk_size = 0;
let mut table_len_mismatch = false;
let inner: Vec<f64> = vec
.into_iter()
.flat_map(|(n, v)| {
scope.loc.line_num += n;
let l = v.len();
#[expect(clippy::else_if_without_else)]
if l != 0 {
if chunk_size == 0 {
chunk_size = l;
} else if chunk_size != l {
table_len_mismatch = true;
}
}
v
})
.collect();
Ok((
_i,
if table_len_mismatch {
crate::error!("{} table of values is NOT aligned", scope.loc);
Ok(Self { chunk_size: inner.len(), inner })
} else {
Ok(Self { chunk_size, inner })
},
))
}
Err(_) => {
Err(nom::Err::Error(nom::error::Error::new(i, nom::error::ErrorKind::ManyMN)))
}
}
}
#[inline]
fn is_set(&self) -> bool {
!self.inner.is_empty()
}
#[inline]
fn fmt_self<T: Write, I: ast::Indentation>(
&self,
f: &mut ast::CodeFormatter<'_, T, I>,
) -> fmt::Result {
let mut iter = self.inner.chunks(self.chunk_size);
if let Some(v) = iter.next() {
ast::join_fmt(
v.iter(),
f,
|float, ff| ff.write_num(*float),
|ff| write!(ff, ", "),
)?;
}
while let Some(v) = iter.next() {
write!(f, ", \\")?;
f.write_new_line_indentation()?;
ast::join_fmt(
v.iter(),
f,
|float, ff| ff.write_num(*float),
|ff| write!(ff, ", "),
)?;
}
Ok(())
}
}
#[expect(clippy::field_scoped_visibility_modifiers)]
pub(crate) struct DisplayValues<V: Iterator<Item = f64>> {
pub(crate) len: usize,
pub(crate) chunk_size: usize,
pub(crate) inner: V,
}
impl<V: Iterator<Item = f64>> DisplayValues<V> {
#[inline]
fn fmt_self<T: Write, I: ast::Indentation>(
self,
f: &mut ast::CodeFormatter<'_, T, I>,
) -> fmt::Result {
use itertools::Itertools as _;
let chunks = self.inner.chunks(self.chunk_size);
let mut iter = chunks.into_iter();
if let Some(v) = iter.next() {
ast::join_fmt(
v.into_iter(),
f,
|float, ff| ff.write_num(float),
|ff| write!(ff, ", "),
)?;
}
while let Some(v) = iter.next() {
write!(f, ", \\")?;
f.write_new_line_indentation()?;
ast::join_fmt(
v.into_iter(),
f,
|float, ff| ff.write_num(float),
|ff| write!(ff, ", "),
)?;
}
Ok(())
}
}
#[expect(clippy::field_scoped_visibility_modifiers)]
pub(crate) struct DisplayTableLookUp<'a, V: Iterator<Item = f64>> {
pub(crate) name: &'a String,
pub(crate) index_1: &'a Vec<f64>,
pub(crate) index_2: &'a Vec<f64>,
pub(crate) values: DisplayValues<V>,
}
impl<V: Iterator<Item = f64>> DisplayTableLookUp<'_, V> {
#[inline]
pub(crate) fn fmt_self<T: Write, I: ast::Indentation, C: Ctx>(
self,
key1: &str,
key2: &str,
f: &mut ast::CodeFormatter<'_, T, I>,
) -> fmt::Result {
use core::fmt::Write as _;
f.write_new_line_indentation()?;
write!(f, "{key1}{key2} (")?;
ast::NameAttri::fmt_self(self.name, f)?;
write!(f, ") {{")?;
f.indent();
ComplexAttri::<C>::fmt_liberty(self.index_1, "index_1", f)?;
ComplexAttri::<C>::fmt_liberty(self.index_2, "index_2", f)?;
if self.values.len > 0 {
f.write_new_line_indentation()?;
write!(f, "values (")?;
f.indent();
self.values.fmt_self(f)?;
f.dedent();
write!(f, ");")?;
}
f.dedent();
f.write_new_line_indentation()?;
write!(f, "}}")
}
}
#[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 TableTemple<C: Ctx> {
#[liberty(name)]
#[id(borrow = str)]
pub name: String,
#[liberty(comments)]
comments: GroupComments,
#[liberty(extra_ctx)]
pub extra_ctx: C::Other,
#[liberty(attributes)]
pub attributes: Attributes,
#[liberty(simple(type = Option))]
pub variable_1: Option<Variable>,
#[liberty(simple(type = Option))]
pub variable_2: Option<Variable>,
#[liberty(simple(type = Option))]
pub variable_3: Option<Variable>,
#[liberty(simple(type = Option))]
pub variable_4: Option<Variable>,
#[liberty(complex(type = Option))]
pub index_1: Option<Vec<f64>>,
#[liberty(complex(type = Option))]
pub index_2: Option<Vec<f64>>,
#[liberty(complex(type = Option))]
pub index_3: Option<Vec<f64>>,
#[liberty(complex(type = Option))]
pub index_4: Option<Vec<f64>>,
}
impl<C: Ctx> GroupFn<C> for TableTemple<C> {}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum Variable {
Time(TimeVariable),
Voltage(VoltageVariable),
Capacitance(CapacitanceVariable),
RcProduct,
Length(LengthVariable),
Scalar(ScalarVariable),
}
crate::ast::impl_self_builder!(Variable);
crate::ast::impl_simple!(Variable);
impl Variable {
pub const INPUT_VOLTAGE: Self = Self::Voltage(VoltageVariable::InputVoltage);
pub const OUTPUT_VOLTAGE: Self = Self::Voltage(VoltageVariable::OutputVoltage);
pub const INPUT_NOISE_HEIGHT: Self = Self::Voltage(VoltageVariable::InputNoiseHeight);
pub const INPUT_TRANSITION_TIME: Self = Self::Time(TimeVariable::InputTransitionTime);
pub const INPUT_NET_TRANSITION: Self = Self::Time(TimeVariable::InputNetTransition);
pub const CONSTRAINED_PIN_TRANSITION: Self =
Self::Time(TimeVariable::ConstrainedPinTransition);
pub const RELATED_PIN_TRANSITION: Self = Self::Time(TimeVariable::RelatedPinTransition);
pub const DRIVER_SLEW: Self = Self::Time(TimeVariable::DriverSlew);
pub const OUTPUT_TRANSITION: Self = Self::Time(TimeVariable::OutputTransition);
pub const OUTPUT_PIN_TRANSITION: Self = Self::Time(TimeVariable::OutputPinTransition);
pub const CONNECT_DELAY: Self = Self::Time(TimeVariable::ConnectDelay);
pub const INPUT_NOISE_WIDTH: Self = Self::Time(TimeVariable::InputNoiseWidth);
pub const TIME: Self = Self::Time(TimeVariable::Time);
pub const TOTAL_OUTPUT_NET_CAPACITANCE: Self =
Self::Capacitance(CapacitanceVariable::TotalOutputNetCapacitance);
pub const OUTPUT_NET_WIRE_CAP: Self =
Self::Capacitance(CapacitanceVariable::OutputNetWireCap);
pub const OUTPUT_NET_PIN_CAP: Self =
Self::Capacitance(CapacitanceVariable::OutputNetPinCap);
pub const RELATED_OUT_TOTAL_OUTPUT_NET_CAPACI: Self =
Self::Capacitance(CapacitanceVariable::RelatedOutTotalOutputNetCapacitance);
pub const RELATED_OUT_OUTPUT_NET_WIRE_CAP: Self =
Self::Capacitance(CapacitanceVariable::RelatedOutOutputNetWireCap);
pub const RELATED_OUT_OUTPUT_NET_PIN_CAP: Self =
Self::Capacitance(CapacitanceVariable::RelatedOutOutputNetPinCap);
pub const FANOUT_PIN_CAPACITANCE: Self =
Self::Capacitance(CapacitanceVariable::FanoutPinCapacitance);
pub const OUTPUT_NET_LENGTH: Self = Self::Length(LengthVariable::OutputNetLength);
pub const RELATED_OUT_OUTPUT_NET_LENGTH: Self =
Self::Length(LengthVariable::RelatedOutOutputNetLength);
pub const FANOUT_NUMBER: Self = Self::Scalar(ScalarVariable::FanoutNumber);
pub const NORMALIZED_VOLTAGE: Self = Self::Scalar(ScalarVariable::NormalizedVoltage);
pub const RC_PRODUCT: Self = Self::RcProduct;
}
impl core::str::FromStr for Variable {
type Err = strum::ParseError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"input_voltage" => Self::INPUT_VOLTAGE,
"output_voltage" => Self::OUTPUT_VOLTAGE,
"input_noise_height" => Self::INPUT_NOISE_HEIGHT,
"input_transition_time" => Self::INPUT_TRANSITION_TIME,
"input_net_transition" => Self::INPUT_NET_TRANSITION,
"constrained_pin_transition" => Self::CONSTRAINED_PIN_TRANSITION,
"related_pin_transition" => Self::RELATED_PIN_TRANSITION,
"driver_slew" => Self::DRIVER_SLEW,
"output_transition" => Self::OUTPUT_TRANSITION,
"output_pin_transition" => Self::OUTPUT_PIN_TRANSITION,
"connect_delay" => Self::CONNECT_DELAY,
"input_noise_width" => Self::INPUT_NOISE_WIDTH,
"time" => Self::TIME,
"total_output_net_capacitance" => Self::TOTAL_OUTPUT_NET_CAPACITANCE,
"output_net_wire_cap" => Self::OUTPUT_NET_WIRE_CAP,
"output_net_pin_cap" => Self::OUTPUT_NET_PIN_CAP,
"related_out_total_output_net_capaci" => Self::RELATED_OUT_TOTAL_OUTPUT_NET_CAPACI,
"related_out_output_net_wire_cap" => Self::RELATED_OUT_OUTPUT_NET_WIRE_CAP,
"related_out_output_net_pin_cap" => Self::RELATED_OUT_OUTPUT_NET_PIN_CAP,
"fanout_pin_capacitance" => Self::FANOUT_PIN_CAPACITANCE,
"output_net_length" => Self::OUTPUT_NET_LENGTH,
"related_out_output_net_length" => Self::RELATED_OUT_OUTPUT_NET_LENGTH,
"fanout_number" => Self::FANOUT_NUMBER,
"normalized_voltage" => Self::NORMALIZED_VOLTAGE,
"rc_product" => Self::RC_PRODUCT,
_ => {
return Err(strum::ParseError::VariantNotFound);
}
})
}
}
impl fmt::Display for Variable {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match *self {
Self::INPUT_VOLTAGE => "input_voltage",
Self::OUTPUT_VOLTAGE => "output_voltage",
Self::INPUT_NOISE_HEIGHT => "input_noise_height",
Self::INPUT_TRANSITION_TIME => "input_transition_time",
Self::INPUT_NET_TRANSITION => "input_net_transition",
Self::CONSTRAINED_PIN_TRANSITION => "constrained_pin_transition",
Self::RELATED_PIN_TRANSITION => "related_pin_transition",
Self::DRIVER_SLEW => "driver_slew",
Self::OUTPUT_TRANSITION => "output_transition",
Self::OUTPUT_PIN_TRANSITION => "output_pin_transition",
Self::CONNECT_DELAY => "connect_delay",
Self::INPUT_NOISE_WIDTH => "input_noise_width",
Self::TIME => "time",
Self::TOTAL_OUTPUT_NET_CAPACITANCE => "total_output_net_capacitance",
Self::OUTPUT_NET_WIRE_CAP => "output_net_wire_cap",
Self::OUTPUT_NET_PIN_CAP => "output_net_pin_cap",
Self::RELATED_OUT_TOTAL_OUTPUT_NET_CAPACI => "related_out_total_output_net_capaci",
Self::RELATED_OUT_OUTPUT_NET_WIRE_CAP => "related_out_output_net_wire_cap",
Self::RELATED_OUT_OUTPUT_NET_PIN_CAP => "related_out_output_net_pin_cap",
Self::FANOUT_PIN_CAPACITANCE => "fanout_pin_capacitance",
Self::OUTPUT_NET_LENGTH => "output_net_length",
Self::RELATED_OUT_OUTPUT_NET_LENGTH => "related_out_output_net_length",
Self::FANOUT_NUMBER => "fanout_number",
Self::NORMALIZED_VOLTAGE => "normalized_voltage",
Self::RC_PRODUCT => "rc_product",
};
f.write_str(s)
}
}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd)]
#[derive(strum::EnumString, strum::EnumIter, strum::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum TimeVariable {
#[strum(serialize = "input_transition_time")]
InputTransitionTime,
#[strum(serialize = "input_net_transition")]
InputNetTransition,
#[strum(serialize = "constrained_pin_transition")]
ConstrainedPinTransition,
#[strum(serialize = "related_pin_transition")]
RelatedPinTransition,
#[strum(serialize = "driver_slew")]
DriverSlew,
#[strum(serialize = "output_transition")]
OutputTransition,
#[strum(serialize = "output_pin_transition")]
OutputPinTransition,
#[strum(serialize = "connect_delay")]
ConnectDelay,
#[strum(serialize = "input_noise_width")]
InputNoiseWidth,
#[strum(serialize = "time")]
Time,
}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd)]
#[derive(strum::EnumString, strum::EnumIter, strum::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum VoltageVariable {
#[strum(serialize = "input_voltage")]
InputVoltage,
#[strum(serialize = "output_voltage")]
OutputVoltage,
#[strum(serialize = "input_noise_height")]
InputNoiseHeight,
}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd)]
#[derive(strum::EnumString, strum::EnumIter, strum::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum CapacitanceVariable {
#[strum(serialize = "total_output_net_capacitance")]
TotalOutputNetCapacitance,
#[strum(serialize = "output_net_wire_cap")]
OutputNetWireCap,
#[strum(serialize = "output_net_pin_cap")]
OutputNetPinCap,
#[strum(serialize = "related_out_total_output_net_capaci")]
RelatedOutTotalOutputNetCapacitance,
#[strum(serialize = "related_out_output_net_wire_cap")]
RelatedOutOutputNetWireCap,
#[strum(serialize = "related_out_output_net_pin_cap")]
RelatedOutOutputNetPinCap,
#[strum(serialize = "fanout_pin_capacitance")]
FanoutPinCapacitance,
}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd)]
#[derive(strum::EnumString, strum::EnumIter, strum::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum LengthVariable {
#[strum(serialize = "output_net_length")]
OutputNetLength,
#[strum(serialize = "related_out_output_net_length")]
RelatedOutOutputNetLength,
}
#[derive(Debug, Clone, Copy)]
#[derive(Hash, PartialEq, Eq)]
#[derive(Ord, PartialOrd)]
#[derive(strum::EnumString, strum::EnumIter, strum::Display)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum ScalarVariable {
#[strum(serialize = "fanout_number")]
FanoutNumber,
#[strum(serialize = "normalized_voltage")]
NormalizedVoltage,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
#[derive(Display, EnumString)]
#[derive(serde::Serialize, serde::Deserialize)]
pub enum SigmaType {
#[strum(serialize = "early")]
Early,
#[strum(serialize = "late")]
Late,
#[default]
#[strum(serialize = "early_and_late")]
EarlyAndLate,
}
ast::impl_self_builder!(SigmaType);
ast::impl_simple!(SigmaType);
#[cfg(test)]
mod test {
use crate::{
DefaultCtx, Group as _,
ast::{ComplexAttri, test_parse, test_parse_fmt},
};
#[test]
fn values_vector32() {
let mut scope = crate::ast::ParseScope::default();
let (_, res) = <super::Values as ComplexAttri<DefaultCtx>>::nom_parse(
r#"("5.4283814e-01, 5.4289214e-01, 5.4298464e-01", \
"6.2226570e-01, 6.2225652e-01, 6.2212002e-01,");"#,
&mut scope,
)
.unwrap();
let values = res.unwrap();
assert_eq!(values.chunk_size, 3);
}
#[test]
fn values_vector31() {
let mut scope = crate::ast::ParseScope::default();
let (_, res) = <super::Values as ComplexAttri<DefaultCtx>>::nom_parse(
r#"("6.2226570e-01, 6.2225652e-01, 6.2212002e-01");"#,
&mut scope,
)
.unwrap();
let values = res.unwrap();
assert_eq!(values.chunk_size, 3);
}
#[test]
fn values_vector31_badiface() {
let mut scope = crate::ast::ParseScope::default();
let (_, res) = <super::Values as ComplexAttri<DefaultCtx>>::nom_parse(
r#"("6.2226570e-01 6.2225652e-01 6.2212002e-01");"#,
&mut scope,
)
.unwrap();
let values = res.unwrap();
assert_eq!(values.chunk_size, 3);
}
#[test]
fn values_scalar1() {
let mut scope = crate::ast::ParseScope::default();
let (_, res) = <super::Values as ComplexAttri<DefaultCtx>>::nom_parse(
r#"("6.2226570e-01");"#,
&mut scope,
)
.unwrap();
let values = res.unwrap();
assert_eq!(values.chunk_size, 1);
}
#[test]
fn values_scalar2() {
let mut scope = crate::ast::ParseScope::default();
let (_, res) = <super::Values as ComplexAttri<DefaultCtx>>::nom_parse(
r#"(6.2226570e-01);"#,
&mut scope,
)
.unwrap();
let values = res.unwrap();
assert_eq!(values.chunk_size, 1);
}
#[test]
fn table() {
let table = test_parse_fmt::<super::TableLookUp<DefaultCtx>>(
r#" ("CCS_RCV_TEMPLATE_0") {
index_1("0.0186051, 0.0372112, 0.0744591");
index_2("0.1000000, 0.2500000, 0.5000000");
values("5.4283814e-01, 5.4289214e-01, 5.4298464e-01", \
"6.0907950e-01, 6.0906120e-01, 6.0903281e-01,", \
"6.2226570e-01, 6.2225652e-01, 6.2212002e-01,");
}
"#,
r#"
liberty_db::table::TableLookUp (CCS_RCV_TEMPLATE_0) {
| index_1 ("0.0186051, 0.0372112, 0.0744591");
| index_2 ("0.1, 0.25, 0.5");
| values ("0.54283814, 0.54289214, 0.54298464", \
| | "0.6090795, 0.6090612, 0.60903281", \
| | "0.6222657, 0.62225652, 0.62212002");
}"#,
);
}
#[test]
fn compact_ccs_table() {
let table = test_parse_fmt::<super::CompactCcsTable<DefaultCtx>>(
r#" ("c_ccs_pwr_template_6") {
values("-0.0119931,-101.1912245,", \
"-0.0119953,-101.1912245,", \
"-0.0119957,-101.1912245,", \
"-0.0119957,-101.1912245,", \
"-0.0119957,-101.1912245,", \
"-0.0119953,-101.1912245,", \
"-0.0119953,-101.1912245,", \
"-0.7696603,-101.1912245,");
}
"#,
r#"
liberty_db::table::CompactCcsTable (c_ccs_pwr_template_6) {
| values ("-0.0119931, -101.1912245", \
| | "-0.0119953, -101.1912245", \
| | "-0.0119957, -101.1912245", \
| | "-0.0119957, -101.1912245", \
| | "-0.0119957, -101.1912245", \
| | "-0.0119953, -101.1912245", \
| | "-0.0119953, -101.1912245", \
| | "-0.7696603, -101.1912245");
}"#,
);
}
#[test]
fn compact_ccs_power_table() {
let table = test_parse_fmt::<super::CompactCcsPower<DefaultCtx>>(
r#" (c_ccs_pwr_template_3) {
values ("0.0358012, 0.0206745, 2505, 0.0480925, 1.1701594, 2506, 1.4011397, 0.0724034", \
"-0.0481277, 0.0206745, 13, -0.0477729, 0.0, 13, -0.026014, -1.267817, 1198, 71.4506979, 0.0698575", \
"-0.6273036, 0.0206745, 3, -0.1100034, 3.4377912, 294, 3.8867416, 0.0715863");
}
"#,
r#"
liberty_db::table::CompactCcsPower (c_ccs_pwr_template_3) {
| values ("0.0358012, 0.0206745, 2505, 0.0480925, 1.1701594, 2506, 1.4011397, 0.0724034", \
| | "-0.0481277, 0.0206745, 13, -0.0477729, 0.0, 13, -0.026014, -1.267817, 1198, 71.4506979, 0.0698575", \
| | "-0.6273036, 0.0206745, 3, -0.1100034, 3.4377912, 294, 3.8867416, 0.0715863");
}"#,
);
println!("{table:?}");
}
#[test]
#[cfg(feature = "lut_template")]
fn table_template() {
use super::TableCtx as _;
use crate::{ccsn::ReceiverCapacitanceId, pin::PinId};
let library = test_parse::<crate::Library<DefaultCtx>>(
r#" (ccsn) {
lu_table_template (receiver_cap_power_template_8x8) {
variable_1 : input_net_transition;
index_1 ("0.0018, 0.0086, 0.0223, 0.0497, 0.1045, 0.2141, 0.4332, 0.8715");
}
cell (AO21D1BWP30P140) {
pin (A1) {
receiver_capacitance () {
when : "A2*B";
receiver_capacitance1_fall (receiver_cap_power_template_8x8) {
index_1 ("0.0018, 0.0086, 0.0223, 0.0497, 0.1045, 0.2141, 0.4332, 0.8715");
values ("0.000301151, 0.000309383, 0.000310618, 0.000311444, 0.000313263, 0.000314142, 0.000314583, 0.000314953");
}
}
}
pin (A2) {}
pin (B) {}
}
}
"#,
);
let cell = library.cell.get("AO21D1BWP30P140").unwrap();
let when = cell.parse_logic_boolexpr("A2*B").unwrap();
let receiver_capacitance = cell
.pin
.get(&PinId::from("A1"))
.unwrap()
.receiver_capacitance
.get(&ReceiverCapacitanceId::new(None, Some(when)))
.unwrap();
let table_template = receiver_capacitance
.receiver_capacitance1_fall
.as_ref()
.unwrap()
.extra_ctx
.lut_template()
.as_ref()
.unwrap();
dev_utils::text_diff(
r#"
liberty_db::table::TableTemple (receiver_cap_power_template_8x8) {
| variable_1 : input_net_transition;
| index_1 ("0.0018, 0.0086, 0.0223, 0.0497, 0.1045, 0.2141, 0.4332, 0.8715");
}"#,
&table_template.display().to_string(),
);
}
}