liberty_db/pin/
items.rs

1use crate::{
2  Ctx,
3  ast::{
4    Attributes, CodeFormatter, ComplexAttri, ComplexParseError, GroupComments, GroupFn,
5    Indentation, ParseScope, SimpleAttri,
6  },
7  expression::logic::{Edge, Static},
8};
9use core::{
10  fmt::{self, Write},
11  str::FromStr,
12};
13use strum::{Display, EnumString};
14
15/// <a name ="reference_link" href="
16/// https://zao111222333.github.io/liberty-db/2020.09/reference_manual.html
17/// ?field=test
18/// &bgn
19/// =228.4
20/// &end
21/// =228.4
22/// ">Reference-Instance</a>
23#[derive(Debug, Clone, Copy, Eq, PartialEq, Display, EnumString)]
24#[derive(serde::Serialize, serde::Deserialize)]
25pub enum AntennaDiodeType {
26  /// `power`
27  #[strum(serialize = "power")]
28  Power,
29  /// `ground`
30  #[strum(serialize = "ground")]
31  Ground,
32  /// `power_and_ground`
33  #[strum(serialize = "power_and_ground")]
34  PowerAndGround,
35}
36crate::ast::impl_self_builder!(AntennaDiodeType);
37crate::ast::impl_simple!(AntennaDiodeType);
38
39/// In timing analysis, use a tlatch group to describe the relationship between the data pin
40/// and the enable pin on a transparent level-sensitive latch.
41/// You define the tlatch group in a pin group, but it is only effective if you also define the
42/// `timing_model_type` attribute in the cell that the pin belongs to. For more information
43/// about the `timing_model_type` attribute,
44/// <a name ="reference_link" href="
45/// https://zao111222333.github.io/liberty-db/2020.09/reference_manual.html?field=test&bgn=372.33&end=372.37
46/// ">Reference-Definition</a>
47/// <script>
48/// IFRAME('https://zao111222333.github.io/liberty-db/2020.09/reference_manual.html');
49/// </script>
50#[derive(Debug, Clone)]
51#[derive(liberty_macros::Group)]
52#[mut_set::derive::item]
53#[derive(serde::Serialize, serde::Deserialize)]
54#[serde(bound = "C::Other: serde::Serialize + serde::de::DeserializeOwned")]
55pub struct TLatch<C: 'static + Ctx> {
56  /// Name of the pin
57  #[liberty(name)]
58  #[id(borrow = str)]
59  pub name: String,
60  /// group comments
61  #[liberty(comments)]
62  comments: GroupComments,
63  #[liberty(extra_ctx)]
64  pub extra_ctx: C::Other,
65  /// group undefined attributes
66  #[liberty(attributes)]
67  pub attributes: Attributes,
68  /// Valid values are rising and falling.
69  #[liberty(simple)]
70  pub edge_type: Option<Edge>,
71  #[liberty(simple)]
72  pub tdisable: Option<bool>,
73}
74impl<C: 'static + Ctx> GroupFn<C> for TLatch<C> {}
75
76/// To specify hyperbolic noise immunity information, use the
77/// `hyperbolic_noise_above_high`, `hyperbolic_noise_below_low`,
78/// `hyperbolic_noise_high`, and `hyperbolic_noise_low` groups within the pin group.
79///
80/// Syntax
81/// ```text
82/// pin(namestring) {
83/// ...
84/// hyperbolic_noise_above_high() {
85/// height_coefficient : float;
86/// area_coefficient : float;
87/// width_coefficient : float;
88/// }
89/// hyperbolic_noise_below_low() {
90/// ...
91/// }
92/// hyperbolic_noise_high() {
93/// ...
94/// }
95/// hyperbolic_noise_low() {
96/// ...
97/// }
98/// ...
99/// }
100/// ```
101///
102/// The coefficient values for height, width, and area must be 0 or a positive number.
103///
104/// The following rules apply to noise immunity groups:
105/// + The hyperbolic noise groups are optional, and each can be defined separately from the
106/// other three.
107/// + For the same region (above-high, below-low, high, or low), the hyperbolic noise groups
108/// can coexist with normal noise immunity tables.
109/// + For different regions (above-high, below-low, high, or low), a combination of tables and
110/// hyperbolic functions is allowed. For example, you might have a hyperbolic function for
111/// below and above the rails and have tables for high and low tables on the same pin.
112/// + When no table or hyperbolic function is defined for a given pin, the application checks
113/// other measures for noise immunity, such as DC noise margins.
114/// + The unit for height and `height_coefficient` is the library unit of voltage. The
115/// unit for width and `width_coefficient` is the library unit of time. The unit for
116/// `area_coefficient` is the library unit of voltage multiplied by the library unit of time.
117/// <a name ="reference_link" href="
118/// https://zao111222333.github.io/liberty-db/2020.09/user_guide.html?field=null&bgn=620.3&end=620.46
119/// ">Reference-Definition</a>
120/// <script>
121/// IFRAME('https://zao111222333.github.io/liberty-db/2020.09/reference_manual.html');
122/// </script>
123#[derive(Debug, Clone)]
124#[derive(liberty_macros::Group)]
125#[mut_set::derive::item]
126#[derive(serde::Serialize, serde::Deserialize)]
127#[serde(bound = "C::Other: serde::Serialize + serde::de::DeserializeOwned")]
128pub struct HyperbolicNoise<C: 'static + Ctx> {
129  /// Name of the pin
130  #[liberty(name)]
131  #[id]
132  pub name: Option<String>,
133  /// group comments
134  #[liberty(comments)]
135  comments: GroupComments,
136  #[liberty(extra_ctx)]
137  pub extra_ctx: C::Other,
138  /// group undefined attributes
139  #[liberty(attributes)]
140  pub attributes: Attributes,
141  #[liberty(simple)]
142  pub height_coefficient: f64,
143  #[liberty(simple)]
144  pub area_coefficient: f64,
145  #[liberty(simple)]
146  pub width_coefficient: f64,
147}
148impl<C: 'static + Ctx> GroupFn<C> for HyperbolicNoise<C> {}
149
150/// The `memory_write` group is in the bus group. All data input requires a `memory_write`
151/// group to define how the data is written into the memory block. The attributes in this group
152/// are
153/// + address
154/// + `clocked_on`
155/// + enable
156///
157/// *Syntax*:
158/// ```text
159/// cell()
160///  bus() {
161///  ...
162///  memory_write() {
163///  address : bus ;
164///  clocked_on : name ;
165///  enable : name ;
166///  }
167///  }
168/// }
169/// ```
170#[derive(Debug, Clone)]
171#[derive(liberty_macros::Group)]
172#[derive(serde::Serialize, serde::Deserialize)]
173#[serde(bound = "C::Other: serde::Serialize + serde::de::DeserializeOwned")]
174pub struct MemoryWrite<C: 'static + Ctx> {
175  /// Name of the pin
176  #[liberty(name)]
177  pub name: Option<String>,
178  /// group comments
179  #[liberty(comments)]
180  comments: GroupComments,
181  #[liberty(extra_ctx)]
182  pub extra_ctx: C::Other,
183  /// group undefined attributes
184  #[liberty(attributes)]
185  pub attributes: Attributes,
186  #[liberty(simple)]
187  pub address: Option<String>,
188  #[liberty(simple)]
189  pub clocked_on: Option<String>,
190  #[liberty(simple)]
191  pub enable: Option<String>,
192}
193impl<C: 'static + Ctx> GroupFn<C> for MemoryWrite<C> {}
194
195/// The `memory_read` group is in the bus group. All memory-block output requires a
196/// `memory_read` group to define how the output functions. This group is allowed only on
197/// output buses and internal buses. It cannot be used in input bus groups.
198///
199/// Note: The bus cannot have a `state_function` attribute or an `internal_node` attribute.
200///
201/// *Syntax*:
202/// ```text
203/// cell()
204///  ...
205///  bus() {
206///  ...
207///  memory_read() {
208///  address : bus ;
209///  }
210///  }
211/// }
212/// ```
213#[derive(Debug, Clone)]
214#[derive(liberty_macros::Group)]
215#[derive(serde::Serialize, serde::Deserialize)]
216#[serde(bound = "C::Other: serde::Serialize + serde::de::DeserializeOwned")]
217pub struct MemoryRead<C: 'static + Ctx> {
218  /// Name of the pin
219  #[liberty(name)]
220  pub name: Option<String>,
221  /// group comments
222  #[liberty(comments)]
223  comments: GroupComments,
224  #[liberty(extra_ctx)]
225  pub extra_ctx: C::Other,
226  /// group undefined attributes
227  #[liberty(attributes)]
228  pub attributes: Attributes,
229  #[liberty(simple)]
230  pub address: Option<String>,
231}
232
233impl<C: 'static + Ctx> GroupFn<C> for MemoryRead<C> {}
234
235/// <a name ="reference_link" href="
236/// https://zao111222333.github.io/liberty-db/2020.09/reference_manual.html
237/// ?field=test
238/// &bgn
239/// =228.22
240/// &end
241/// =228.22
242/// ">Reference-Instance</a>
243#[derive(Debug, Clone, Copy, Eq, PartialEq, Display, EnumString)]
244#[derive(serde::Serialize, serde::Deserialize)]
245pub enum Direction {
246  #[strum(serialize = "input")]
247  Input,
248  #[strum(serialize = "output")]
249  Output,
250  #[strum(serialize = "inoutput", to_string = "inout")]
251  Inout,
252  #[strum(serialize = "internal")]
253  Internal,
254}
255crate::ast::impl_self_builder!(Direction);
256crate::ast::impl_simple!(Direction);
257
258#[derive(Debug, Clone, Copy, Eq, PartialEq, Display, EnumString)]
259#[derive(serde::Serialize, serde::Deserialize)]
260pub enum DontFault {
261  #[strum(serialize = "sa0")]
262  Sa0,
263  #[strum(serialize = "sa1")]
264  Sa1,
265  #[strum(serialize = "sao1")]
266  Sao1,
267}
268crate::ast::impl_self_builder!(DontFault);
269crate::ast::impl_simple!(DontFault);
270
271#[derive(Debug, Clone, Copy, Eq, PartialEq, Display, EnumString)]
272#[derive(serde::Serialize, serde::Deserialize)]
273pub enum DriverType {
274  #[strum(serialize = "pull_up")]
275  PullUp,
276  #[strum(serialize = "pull_down")]
277  PullDown,
278  #[strum(serialize = "open_drain")]
279  OpenDrain,
280  #[strum(serialize = "open_source")]
281  OpenSource,
282  #[strum(serialize = "bus_hold")]
283  BusHold,
284  #[strum(serialize = "resistive")]
285  Resistive,
286  #[strum(serialize = "resistive_0")]
287  Resistive0,
288  #[strum(serialize = "resistive_1")]
289  Resistive1,
290}
291
292bitflags::bitflags! {
293  /// Represents a set of flags.
294  #[derive(Debug, Clone, Copy, Eq, PartialEq)]
295  #[derive(serde::Serialize, serde::Deserialize)]
296  #[serde(transparent)]
297  pub struct AllDriverType: u8 {
298    const pull_up = 0b0000_0001;
299    const pull_down = 0b0000_0010;
300    const open_drain = 0b0000_0100;
301    const open_source = 0b0000_1000;
302    const bus_hold = 0b0000_1000;
303    const resistive = 0b0001_0000;
304    const resistive_0 = 0b0100_0000;
305    const resistive_1 = 0b1000_0000;
306  }
307}
308
309crate::ast::impl_self_builder!(AllDriverType);
310impl<C: 'static + Ctx> SimpleAttri<C> for AllDriverType {
311  #[inline]
312  fn nom_parse<'a>(
313    i: &'a str,
314    scope: &mut ParseScope<'_>,
315  ) -> crate::ast::SimpleParseRes<'a, Self> {
316    crate::ast::nom_parse_from_str::<C, _>(i, scope)
317  }
318  #[inline]
319  fn fmt_self<T: Write, I: Indentation>(
320    &self,
321    f: &mut CodeFormatter<'_, T, I>,
322  ) -> fmt::Result {
323    if self.bits().is_power_of_two() {
324      write!(f, "{self}")
325    } else {
326      write!(f, "\"{self}\"")
327    }
328  }
329}
330impl FromStr for AllDriverType {
331  type Err = <DriverType as FromStr>::Err;
332  #[inline]
333  fn from_str(s: &str) -> Result<Self, Self::Err> {
334    let mut out = Self::empty();
335    for t in s.split_ascii_whitespace() {
336      match t.parse()? {
337        DriverType::PullUp => out.insert(Self::pull_up),
338        DriverType::PullDown => out.insert(Self::pull_down),
339        DriverType::OpenDrain => out.insert(Self::open_drain),
340        DriverType::OpenSource => out.insert(Self::open_source),
341        DriverType::BusHold => out.insert(Self::bus_hold),
342        DriverType::Resistive => out.insert(Self::resistive),
343        DriverType::Resistive0 => out.insert(Self::resistive_0),
344        DriverType::Resistive1 => out.insert(Self::resistive_1),
345      }
346    }
347    Ok(out)
348  }
349}
350impl fmt::Display for AllDriverType {
351  #[inline]
352  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353    let mut has_write = false;
354    if self.contains(Self::pull_up) {
355      has_write = true;
356      write!(f, "{}", DriverType::PullUp)?;
357    }
358    if self.contains(Self::pull_down) {
359      if has_write {
360        write!(f, " ")?;
361      } else {
362        has_write = true;
363      }
364      write!(f, "{}", DriverType::PullDown)?;
365    }
366    if self.contains(Self::open_drain) {
367      if has_write {
368        write!(f, " ")?;
369      } else {
370        has_write = true;
371      }
372      write!(f, "{}", DriverType::OpenDrain)?;
373    }
374    if self.contains(Self::open_source) {
375      if has_write {
376        write!(f, " ")?;
377      } else {
378        has_write = true;
379      }
380      write!(f, "{}", DriverType::OpenSource)?;
381    }
382    if self.contains(Self::bus_hold) {
383      if has_write {
384        write!(f, " ")?;
385      } else {
386        has_write = true;
387      }
388      write!(f, "{}", DriverType::BusHold)?;
389    }
390    if self.contains(Self::resistive) {
391      if has_write {
392        write!(f, " ")?;
393      } else {
394        has_write = true;
395      }
396      write!(f, "{}", DriverType::Resistive)?;
397    }
398    if self.contains(Self::resistive_0) {
399      if has_write {
400        write!(f, " ")?;
401      } else {
402        has_write = true;
403      }
404      write!(f, "{}", DriverType::Resistive0)?;
405    }
406    if self.contains(Self::resistive_1) {
407      if has_write {
408        write!(f, " ")?;
409      }
410      write!(f, "{}", DriverType::Resistive1)?;
411    }
412    Ok(())
413  }
414}
415
416#[derive(Debug, Clone, Copy, Eq, PartialEq, Default, Display, EnumString)]
417#[derive(serde::Serialize, serde::Deserialize)]
418pub enum NextstateType {
419  /// Identifies the pin as a synchronous data pin. This is the default value.
420  #[default]
421  #[strum(serialize = "data")]
422  Data,
423  /// Identifies the pin as a synchronous preset pin.
424  #[strum(serialize = "preset")]
425  Preset,
426  /// Identifies the pin as a synchronous clear pin.
427  #[strum(serialize = "clear")]
428  Clear,
429  /// Identifies the pin as a synchronous load pin.
430  #[strum(serialize = "load")]
431  Load,
432  /// Identifies the pin as a synchronous scan-in pin.
433  #[strum(serialize = "scan_in")]
434  ScanIn,
435  /// Identifies the pin as a synchronous scan-enable pin.
436  #[strum(serialize = "scan_enable")]
437  ScanEnable,
438}
439crate::ast::impl_self_builder!(NextstateType);
440crate::ast::impl_simple!(NextstateType);
441
442#[derive(Debug, Clone, Copy, Eq, PartialEq, Display, EnumString)]
443#[derive(serde::Serialize, serde::Deserialize)]
444pub enum PinFuncType {
445  #[strum(serialize = "clock_enable")]
446  ClockEnable,
447  #[strum(serialize = "active_high")]
448  ActiveHigh,
449  #[strum(serialize = "active_low")]
450  ActiveLow,
451  #[strum(serialize = "active_rising")]
452  ActiveRising,
453  #[strum(serialize = "active_falling")]
454  ActiveFalling,
455}
456crate::ast::impl_self_builder!(PinFuncType);
457crate::ast::impl_simple!(PinFuncType);
458
459#[derive(Debug, Clone, Copy, Eq, PartialEq, Display, EnumString)]
460#[derive(serde::Serialize, serde::Deserialize)]
461pub enum RestoreEdgeType {
462  #[strum(serialize = "edge_trigger")]
463  EdgeTrigger,
464  #[strum(serialize = "leading")]
465  Leading,
466  #[strum(serialize = "trailing")]
467  Trailing,
468}
469crate::ast::impl_self_builder!(RestoreEdgeType);
470crate::ast::impl_simple!(RestoreEdgeType);
471
472#[derive(Debug, Clone, Copy, Eq, PartialEq, Display, EnumString)]
473#[derive(serde::Serialize, serde::Deserialize)]
474pub enum SignalType {
475  #[strum(serialize = "test_scan_in")]
476  TestScanIn,
477  #[strum(serialize = "test_scan_in_inverted")]
478  TestScanInInverted,
479  #[strum(serialize = "test_scan_out")]
480  TestScanOut,
481  #[strum(serialize = "test_scan_out_inverted")]
482  TestScanOutInverted,
483  #[strum(serialize = "test_scan_enable")]
484  TestScanEnable,
485  #[strum(serialize = "test_scan_enable_inverted")]
486  TestScanEnableInverted,
487  #[strum(serialize = "test_scan_clock")]
488  TestScanClock,
489  #[strum(serialize = "test_scan_clock_a")]
490  TestScanClockA,
491  #[strum(serialize = "test_scan_clock_b")]
492  TestScanClockB,
493  #[strum(serialize = "test_clock")]
494  TestClock,
495}
496crate::ast::impl_self_builder!(SignalType);
497crate::ast::impl_simple!(SignalType);
498
499#[derive(Default)]
500#[derive(Debug, Clone, Copy, Eq, PartialEq, Display, EnumString)]
501#[derive(serde::Serialize, serde::Deserialize)]
502pub enum SlewControl {
503  #[strum(serialize = "low")]
504  Low,
505  #[strum(serialize = "medium")]
506  Medium,
507  #[strum(serialize = "high")]
508  High,
509  #[default]
510  #[strum(serialize = "none")]
511  None,
512}
513crate::ast::impl_self_builder!(SlewControl);
514crate::ast::impl_simple!(SlewControl);
515
516/// The `prefer_tied` attribute describes an input pin of a flip-flop or latch.
517///
518/// It indicates what the library developer wants this pin connected to.
519/// <a name ="reference_link" href="
520/// https://zao111222333.github.io/liberty-db/2020.09/reference_manual.html
521/// ?field=test
522/// &bgn
523/// =229.4
524/// &end
525/// =229.4
526/// ">Reference-Instance</a>
527/// <a name ="reference_link" href="
528/// https://zao111222333.github.io/liberty-db/2020.09/reference_manual.html?field=test&bgn=267.24&end=267.26
529/// ">Reference-Instance</a>
530#[derive(Debug, Clone, Copy, Eq, PartialEq, Display, EnumString)]
531#[derive(serde::Serialize, serde::Deserialize)]
532pub enum OneZero {
533  /// 1
534  #[strum(serialize = "1")]
535  One,
536  /// 0
537  #[strum(serialize = "0")]
538  Zero,
539}
540crate::ast::impl_self_builder!(OneZero);
541crate::ast::impl_simple!(OneZero);
542
543#[derive(Debug, Clone, Copy, Eq, PartialEq, Display, EnumString)]
544#[derive(serde::Serialize, serde::Deserialize)]
545enum OneValue {
546  #[strum(serialize = "1")]
547  One,
548  #[strum(serialize = "0")]
549  Zero,
550  #[strum(serialize = "x")]
551  Unkown,
552}
553/// Two values that define the value of the differential signals.
554///
555/// when both inputs are driven to the same value. The first value
556/// represents the value when both input pins are at logic 0;
557/// the second value represents the value when both input pins are at logic 1.
558/// Valid values for the two-value string are any two-value combinations
559/// made up of 0, 1, and x.
560/// If you do not enter a `fault_model` attribute value, the signal
561/// pin value goes to x when both input pins are 0 or 1.
562/// <a name ="reference_link" href="
563/// https://zao111222333.github.io/liberty-db/2020.09/reference_manual.html?field=test&bgn=248.6&end=248.13
564/// ">Reference-Instance</a>
565#[derive(Debug, Clone, Eq, PartialEq, Copy)]
566#[derive(serde::Serialize, serde::Deserialize)]
567pub struct TwoValue(OneValue, OneValue);
568crate::ast::impl_self_builder!(TwoValue);
569crate::ast::impl_simple!(TwoValue);
570
571impl fmt::Display for TwoValue {
572  #[inline]
573  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
574    write!(f, "{}{}", self.0, self.1)
575  }
576}
577impl FromStr for TwoValue {
578  type Err = strum::ParseError;
579  #[inline]
580  fn from_str(s: &str) -> Result<Self, Self::Err> {
581    if s.len() != 2 {
582      return Err(strum::ParseError::VariantNotFound);
583    }
584    let mut i = s.chars();
585    if let Some(c1) = i.next()
586      && let Some(c2) = i.next()
587    {
588      let mut tmp = [0; 1];
589      return Ok(Self(
590        OneValue::from_str(c1.encode_utf8(&mut tmp))?,
591        OneValue::from_str(c2.encode_utf8(&mut tmp))?,
592      ));
593    }
594    Err(strum::ParseError::VariantNotFound)
595  }
596}
597
598/// ### Example
599/// ``` text
600/// retention_pin (save | restore | save_restore, enumerated_type) ;
601/// ```
602/// <a name ="reference_link" href="
603/// https://zao111222333.github.io/liberty-db/2020.09/reference_manual.html?field=null&bgn=282.3&end=282.23
604/// ">Reference-Definition</a>
605#[derive(Debug, Clone, Eq, PartialEq)]
606#[derive(serde::Serialize, serde::Deserialize)]
607pub enum PinClass {
608  /// `save`
609  Save,
610  /// `restore`
611  Restore,
612  /// `save_restore`
613  SaveRestore,
614  PinName(String),
615}
616impl FromStr for PinClass {
617  type Err = ();
618  #[inline]
619  fn from_str(s: &str) -> Result<Self, Self::Err> {
620    match s {
621      "save" => Ok(Self::Save),
622      "restore" => Ok(Self::Restore),
623      "save_restore" => Ok(Self::SaveRestore),
624      _ => Ok(Self::PinName(s.to_owned())),
625    }
626  }
627}
628impl fmt::Display for PinClass {
629  #[inline]
630  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
631    match self {
632      Self::Save => write!(f, "save"),
633      Self::Restore => write!(f, "restore"),
634      Self::SaveRestore => write!(f, "save_restore"),
635      Self::PinName(pin) => write!(f, "{pin}"),
636    }
637  }
638}
639/// The `retention_pin` complex attribute identifies the retention pins of a retention cell. The
640/// attribute defines the following information:
641/// + pin class
642///
643///   Valid values:
644///   + `restore`: Restores the state of the cell.
645///   + `save`: Saves the state of the cell.
646///   + `save_restore`: Saves and restores the state of the cell.
647/// + disable value
648///
649/// Defines the value of the retention pin when the cell works in normal mode. The valid
650/// values are 0 and 1.
651///
652/// ### Syntax
653/// ``` text
654/// retention_pin (pin_class, disable_value) ;
655/// ```
656/// ### Example
657/// ``` text
658/// retention_pin (save | restore | save_restore, enumerated_type) ;
659/// ```
660/// <a name ="reference_link" href="
661/// https://zao111222333.github.io/liberty-db/2020.09/reference_manual.html?field=null&bgn=282.3&end=282.23
662/// ">Reference-Definition</a>
663#[derive(Debug, Clone)]
664#[derive(serde::Serialize, serde::Deserialize)]
665pub struct RetentionPin {
666  /// `pin_class`
667  pub pin_class: PinClass,
668  /// `disable_value`
669  pub disable_value: Static,
670}
671crate::ast::impl_self_builder!(RetentionPin);
672impl<C: 'static + Ctx> ComplexAttri<C> for RetentionPin {
673  #[inline]
674  fn parse<'a, I: Iterator<Item = &'a &'a str>>(
675    mut iter: I,
676    _scope: &mut ParseScope<'_>,
677  ) -> Result<Self, ComplexParseError> {
678    let pin_class: PinClass = match iter.next() {
679      Some(&s) => match s.parse() {
680        Ok(f) => f,
681        Err(_) => return Err(ComplexParseError::Other),
682      },
683      None => return Err(ComplexParseError::LengthDismatch),
684    };
685    let disable_value = match iter.next() {
686      Some(&s) => match s {
687        "1" => Static::H,
688        "0" => Static::L,
689        "X" | "x" => Static::X,
690        "Z" | "z" => Static::Z,
691        _ => return Err(ComplexParseError::UnsupportedWord),
692      },
693      None => return Err(ComplexParseError::LengthDismatch),
694    };
695    if iter.next().is_some() {
696      Err(ComplexParseError::LengthDismatch)
697    } else {
698      Ok(Self { pin_class, disable_value })
699    }
700  }
701  #[inline]
702  fn fmt_self<T: Write, I: Indentation>(
703    &self,
704    f: &mut CodeFormatter<'_, T, I>,
705  ) -> fmt::Result {
706    write!(
707      f,
708      "{}, {}",
709      self.pin_class,
710      match self.disable_value {
711        Static::X => "x",
712        Static::Z => "z",
713        Static::H => "1",
714        Static::L => "0",
715      }
716    )
717  }
718}
719
720#[cfg(test)]
721mod test {
722  use crate::DefaultCtx;
723
724  use super::*;
725  #[test]
726  fn two_value() {
727    assert_eq!(Ok(TwoValue(OneValue::Unkown, OneValue::One)), TwoValue::from_str("x1"));
728    assert_eq!(Ok(TwoValue(OneValue::Zero, OneValue::One)), TwoValue::from_str("01"));
729    assert_eq!(Err(strum::ParseError::VariantNotFound), TwoValue::from_str("1"));
730    assert_eq!(Err(strum::ParseError::VariantNotFound), TwoValue::from_str("111"));
731    assert_eq!(Err(strum::ParseError::VariantNotFound), TwoValue::from_str("1-"));
732  }
733  #[test]
734  fn retention_pin() {
735    let cell = crate::ast::test_parse_fmt::<crate::Cell<DefaultCtx>>(
736      r#"(cell1){
737        pin(A){
738          retention_pin (save_restore, 1);
739        }
740        pin(B){
741          retention_pin (restore, 0);
742        }
743        pin(C){
744          retention_pin ("save", 0);
745        }
746      }"#,
747      r#"
748liberty_db::cell::Cell (cell1) {
749| pin (A) {
750| | retention_pin (save_restore, 1);
751| }
752| pin (B) {
753| | retention_pin (restore, 0);
754| }
755| pin (C) {
756| | retention_pin (save, 0);
757| }
758}"#,
759    );
760  }
761  #[test]
762  fn driver_type() {
763    let cell = crate::ast::test_parse_fmt::<crate::Cell<DefaultCtx>>(
764      r#"(cell1){
765        pin(A){
766          direction: inout;
767          driver_type : "pull_up pull_down open_drain open_source bus_hold";
768        }
769        pin(B){
770          driver_type : pull_up;
771        }
772        pin(C){
773          driver_type : "bus_hold";
774        }
775      }"#,
776      r#"
777liberty_db::cell::Cell (cell1) {
778| pin (A) {
779| | direction : inout;
780| | driver_type : "pull_up pull_down open_drain open_source bus_hold";
781| }
782| pin (B) {
783| | driver_type : pull_up;
784| }
785| pin (C) {
786| | driver_type : open_source bus_hold;
787| }
788}"#,
789    );
790  }
791}