use std::convert::TryFrom;
use std::path::Path;
use derive_more::{Add, AddAssign, Sub, SubAssign};
use once_cell::sync::Lazy;
#[allow(unused_imports)]
use rust_decimal::prelude::*;
use serde::{Deserialize, Serialize};
#[macro_use]
extern crate derive_builder;
mod read;
mod write;
use layout21utils as utils;
pub use utils::{SerdeFile, SerializationFormat};
#[cfg(test)]
mod tests;
pub type LefDecimal = rust_decimal::Decimal;
static V5P4: Lazy<LefDecimal> = Lazy::new(|| LefDecimal::from_str("5.4").unwrap());
static V5P8: Lazy<LefDecimal> = Lazy::new(|| LefDecimal::from_str("5.8").unwrap());
#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[builder(pattern = "owned", setter(into), private)]
pub struct LefLibrary {
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub macros: Vec<LefMacro>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub sites: Vec<LefSite>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub version: Option<LefDecimal>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub names_case_sensitive: Option<LefOnOff>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub no_wire_extension_at_pin: Option<LefOnOff>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub bus_bit_chars: Option<(char, char)>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub divider_char: Option<char>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub units: Option<LefUnits>,
#[serde(default, skip_serializing)]
#[builder(default)]
pub vias: Unsupported,
#[serde(default, skip_serializing)]
#[builder(default)]
pub extensions: Unsupported,
}
impl LefLibrary {
pub fn new() -> LefLibrary {
LefLibrary::default()
}
pub fn open(fname: impl AsRef<Path>) -> LefResult<LefLibrary> {
read::parse_file(fname)
}
pub fn save(&self, fname: impl AsRef<Path>) -> LefResult<()> {
write::save(self, fname)
}
pub fn to_string(&self) -> LefResult<String> {
write::to_string(self)
}
}
#[derive(Default, Clone, Builder, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[builder(pattern = "owned", setter(into), private)]
pub struct LefMacro {
pub name: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[builder(default)]
pub pins: Vec<LefPin>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[builder(default)]
pub obs: Vec<LefLayerGeometries>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub class: Option<LefMacroClass>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub foreign: Option<LefForeign>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub origin: Option<LefPoint>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub size: Option<(LefDecimal, LefDecimal)>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub symmetry: Option<Vec<LefSymmetry>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub site: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub source: Option<LefDefSource>,
#[serde(default, skip_serializing)]
#[builder(default)]
pub fixed_mask: Unsupported,
#[serde(default, skip_serializing)]
#[builder(default)]
pub eeq: Unsupported,
#[serde(default, skip_serializing)]
#[builder(default)]
pub density: Unsupported,
#[serde(default, skip_serializing)]
#[builder(default)]
pub properties: Unsupported,
}
impl LefMacro {
pub fn new(name: impl Into<String>) -> LefMacro {
let name = name.into();
LefMacro {
name,
..Default::default()
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub enum LefMacroClass {
Cover { bump: bool },
Ring,
Block { tp: Option<LefBlockClassType> },
Pad { tp: Option<LefPadClassType> },
Core { tp: Option<LefCoreClassType> },
EndCap { tp: LefEndCapClassType },
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct LefForeign {
pub cell_name: String,
pub pt: Option<LefPoint>,
#[serde(default, skip_serializing)]
pub orient: Unsupported,
}
#[derive(Clone, Default, Builder, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[builder(pattern = "owned", setter(into), private)]
pub struct LefPin {
pub name: String,
pub ports: Vec<LefPort>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub direction: Option<LefPinDirection>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[serde(rename(serialize = "use", deserialize = "use"))]
#[builder(default, setter(strip_option))]
pub use_: Option<LefPinUse>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub shape: Option<LefPinShape>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub antenna_model: Option<LefAntennaModel>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub antenna_attrs: Vec<LefPinAntennaAttr>,
#[serde(default, skip_serializing)]
#[builder(default)]
pub taper_rule: Unsupported,
#[serde(default, skip_serializing)]
#[builder(default)]
pub net_expr: Unsupported,
#[serde(default, skip_serializing)]
#[builder(default)]
pub supply_sensitivity: Unsupported,
#[serde(default, skip_serializing)]
#[builder(default)]
pub ground_sensitivity: Unsupported,
#[serde(default, skip_serializing)]
#[builder(default)]
pub must_join: Unsupported,
#[serde(default, skip_serializing)]
#[builder(default)]
pub properties: Unsupported,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub enum LefPinDirection {
Input,
Output { tristate: bool },
Inout,
FeedThru,
}
impl std::fmt::Display for LefPinDirection {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let s = match self {
Self::Input => "INPUT",
Self::Inout => "INOUT",
Self::FeedThru => "FEEDTHRU",
Self::Output { tristate: false } => "OUTPUT",
Self::Output { tristate: true } => "OUTPUT TRISTATE",
};
write!(f, "{}", s)
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct LefPinAntennaAttr {
key: String,
val: LefDecimal,
layer: Option<String>,
}
#[derive(Clone, Default, Builder, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[builder(pattern = "owned", setter(into), private)]
pub struct LefPort {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub class: Option<LefPortClass>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub layers: Vec<LefLayerGeometries>,
}
#[derive(Clone, Default, Builder, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[builder(pattern = "owned", setter(into), private)]
pub struct LefLayerGeometries {
pub layer_name: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub geometries: Vec<LefGeometry>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub vias: Vec<LefVia>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub except_pg_net: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub spacing: Option<LefLayerSpacing>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub width: Option<LefDecimal>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct LefVia {
pub via_name: String,
pub pt: LefPoint,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub enum LefLayerSpacing {
Spacing(LefDecimal),
DesignRuleWidth(LefDecimal),
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub enum LefGeometry {
Shape(LefShape),
Iterate {
shape: LefShape,
pattern: Unsupported,
},
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub enum LefShape {
Rect(LefPoint, LefPoint),
Polygon(Vec<LefPoint>),
Path(Vec<LefPoint>),
}
#[derive(
Clone, Default, Debug, Deserialize, Serialize, PartialEq, Eq, Add, AddAssign, Sub, SubAssign,
)]
pub struct LefPoint {
pub x: LefDecimal,
pub y: LefDecimal,
}
impl LefPoint {
pub fn new(x: impl Into<LefDecimal>, y: impl Into<LefDecimal>) -> Self {
Self {
x: x.into(),
y: y.into(),
}
}
}
impl std::fmt::Display for LefPoint {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{} {}", self.x, self.y)
}
}
#[derive(Clone, Default, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct LefDbuPerMicron(u32);
impl LefDbuPerMicron {
pub fn try_new(x: LefDecimal) -> LefResult<Self> {
if !x.fract().is_zero() {
return Err("DBU per Micron must be an integer".into());
}
if ![100, 200, 400, 800, 1000, 2000, 4000, 8000, 10_000, 20_000].contains(&x.mantissa()) {
return Err("Invalid DBU per Micron value".into());
}
let val = u32::try_from(x.mantissa()).unwrap();
Ok(Self(val))
}
pub fn value(&self) -> u32 {
self.0
}
}
#[derive(Clone, Default, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct LefUnits {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub database_microns: Option<LefDbuPerMicron>,
#[serde(default, skip_serializing)]
pub time_ns: Unsupported,
#[serde(default, skip_serializing)]
pub capacitance_pf: Unsupported,
#[serde(default, skip_serializing)]
pub resistance_ohms: Unsupported,
#[serde(default, skip_serializing)]
pub power_mw: Unsupported,
#[serde(default, skip_serializing)]
pub current_ma: Unsupported,
#[serde(default, skip_serializing)]
pub voltage_volts: Unsupported,
#[serde(default, skip_serializing)]
pub frequency_mhz: Unsupported,
}
#[derive(Clone, Builder, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[builder(pattern = "owned", setter(into), private)]
pub struct LefSite {
pub name: String,
pub class: LefSiteClass,
pub size: (LefDecimal, LefDecimal),
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub symmetry: Option<Vec<LefSymmetry>>,
#[serde(default, skip_serializing)]
#[builder(default)]
pub row_pattern: Unsupported,
}
#[derive(Clone, Default, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct Unsupported;
trait LefEnum: std::marker::Sized {
fn to_str(&self) -> &'static str;
fn from_str(txt: &str) -> Option<Self>;
}
macro_rules! enumstr {
( $(#[$meta: meta])*
$enum_name: ident {
$( $variant: ident : $strval: literal ),* $(,)?
}) => {
$(#[$meta])*
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub enum $enum_name {
$( #[doc=$strval]
$variant ),*
}
impl LefEnum for $enum_name {
#[allow(dead_code)]
fn to_str(&self) -> &'static str {
match self {
$( Self::$variant => $strval),*,
}
}
fn from_str(txt: &str) -> Option<Self> {
match txt {
$( $strval => Some(Self::$variant)),*,
_ => None,
}
}
}
impl ::std::fmt::Display for $enum_name {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
let s = match self {
$( Self::$variant => $strval),*,
};
write!(f, "{}", s)
}
}
}
}
enumstr!(
LefKey {
Library: "LIBRARY",
Version: "VERSION",
Foreign: "FOREIGN",
Origin: "ORIGIN",
Source: "SOURCE",
NamesCaseSensitive: "NAMESCASESENSITIVE",
NoWireExtensionAtPin: "NOWIREEXTENSIONATPIN",
Macro: "MACRO",
End: "END",
Pin: "PIN",
Port: "PORT",
Obs: "OBS",
Layer: "LAYER",
Direction: "DIRECTION",
Use: "USE",
Shape: "SHAPE",
Path: "PATH",
Polygon: "POLYGON",
Rect: "RECT",
Via: "VIA",
Width: "WIDTH",
Class: "CLASS",
Symmetry: "SYMMETRY",
RowPattern: "ROWPATTERN",
Site: "SITE",
Size: "SIZE",
By: "BY",
BusBitChars: "BUSBITCHARS",
DividerChar: "DIVIDERCHAR",
Units: "UNITS",
BeginExtension: "BEGINEXT",
Tristate: "TRISTATE",
Input: "INPUT",
Output: "OUTPUT",
Inout: "INOUT",
FeedThru: "FEEDTHRU",
ExceptPgNet: "EXCEPTPGNET",
DesignRuleWidth: "DESIGNRULEWIDTH",
Spacing: "SPACING",
Bump: "BUMP",
AntennaModel: "ANTENNAMODEL",
AntennaDiffArea: "ANTENNADIFFAREA",
AntennaGateArea: "ANTENNAGATEAREA",
AntennaPartialMetalArea: "ANTENNAPARTIALMETALAREA",
AntennaPartialMetalSideArea: "ANTENNAPARTIALMETALSIDEAREA",
AntennaPartialCutArea: "ANTENNAPARTIALCUTAREA",
AntennaPartialDiffArea: "ANTENNAPARTIALDIFFAREA",
AntennaMaxAreaCar: "ANTENNAMAXAREACAR",
AntennaMaxSideAreaCar: "ANTENNAMAXSIDEAREACAR",
AntennaMaxCutCar: "ANTENNAMAXCUTCAR",
TaperRule: "TAPERRULE",
NetExpr: "NETEXPR",
SupplySensitivity: "SUPPLYSENSITIVITY",
GroundSensitivity: "GROUNDSENSITIVITY",
MustJoin: "MUSTJOIN",
Property: "PROPERTY",
}
);
impl LefKey {
fn parse(txt: &str) -> Option<Self> {
Self::from_str(&txt.to_ascii_uppercase())
}
}
enumstr!(
LefOnOff {
On: "ON",
Off: "OFF",
}
);
enumstr!(
LefDefSource {
Netlist: "NETLIST",
Dist: "DIST",
Timing: "TIMING",
User: "USER",
}
);
enumstr!(
LefSymmetry {
X: "X",
Y: "Y",
R90: "R90"
}
);
enumstr!(
LefPinUse {
Signal: "SIGNAL",
Analog: "ANALOG",
Power: "POWER",
Ground: "GROUND",
Clock: "CLOCK",
}
);
enumstr!(
LefPinShape {
Abutment: "ABUTMENT",
Ring: "RING",
FeedThru: "FEEDTHRU",
}
);
enumstr!(
LefMacroClassName {
Block: "BLOCK",
Pad: "PAD",
Core: "CORE",
EndCap: "ENDCAP",
Cover: "COVER",
Ring: "RING"
}
);
enumstr!(
LefPadClassType {
Input: "INPUT",
Output: "OUTPUT",
Inout: "INOUT",
Power: "POWER",
Spacer: "SPACER",
AreaIo: "AREAIO",
}
);
enumstr!(
LefEndCapClassType {
Pre: "PRE",
Post: "POST",
TopLeft: "TOPLEFT",
TopRight: "TOPRIGHT",
BottomLeft: "BOTTOMLEFT",
BottomRight: "BOTTOMRIGHT",
}
);
enumstr!(
LefBlockClassType {
BlackBox: "BLACKBOX",
Soft: "SOFT"
}
);
enumstr!(
LefCoreClassType {
FeedThru: "FEEDTHRU",
TieHigh: "TIEHIGH",
TieLow: "TIELOW",
Spacer: "SPACER",
AntennaCell: "ANTENNACELL",
WellTap: "WELLTAP",
}
);
enumstr!(
LefPortClass {
None: "NONE",
Core: "CORE",
Bump: "BUMP",
}
);
enumstr!(
LefSiteClass {
Pad: "PAD",
Core: "CORE",
}
);
enumstr!(
LefAntennaModel {
Oxide1: "OXIDE1",
Oxide2: "OXIDE2",
Oxide3: "OXIDE3",
Oxide4: "OXIDE4",
}
);
#[derive(Debug)]
pub enum LefError {
Lex {
next_char: Option<char>,
line: usize,
pos: usize,
},
Parse {
tp: read::LefParseErrorType,
ctx: Vec<read::LefParseContext>,
token: String,
line_content: String,
line_num: usize,
pos: usize,
},
Boxed(Box<dyn std::error::Error>),
Str(String),
}
impl From<utils::ser::Error> for LefError {
fn from(e: utils::ser::Error) -> Self {
Self::Boxed(Box::new(e))
}
}
impl From<std::io::Error> for LefError {
fn from(e: std::io::Error) -> Self {
Self::Boxed(Box::new(e))
}
}
impl From<rust_decimal::Error> for LefError {
fn from(e: rust_decimal::Error) -> Self {
Self::Boxed(Box::new(e))
}
}
impl From<String> for LefError {
fn from(e: String) -> Self {
Self::Str(e)
}
}
impl From<&str> for LefError {
fn from(e: &str) -> Self {
Self::Str(e.into())
}
}
pub type LefResult<T> = Result<T, LefError>;
impl utils::SerdeFile for LefLibrary {}
impl utils::SerdeFile for LefMacro {}