Skip to content

Commit

Permalink
Merge pull request dan-fritchman#52 from nanobowers/macro_density
Browse files Browse the repository at this point in the history
Macro density
  • Loading branch information
dan-fritchman authored Jul 31, 2024
2 parents c771aa7 + a5d3376 commit 0bf349f
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 24 deletions.
67 changes: 57 additions & 10 deletions lef21/resources/lef21.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,55 @@
}
]
},
"LefDensityGeometries": {
"title": "Lef Density Geometry Store",
"description": "Most LEF spatial data (e.g. ports, blockages) is organized by layer. [LefDensityGeometries] stores the combination of a layer (name) and a suite of rectangle density data on that layer.\n\n[LefDensityGeometries] are the primary building block of [LefDensity].",
"type": "object",
"required": [
"layer_name"
],
"properties": {
"geometries": {
"description": "Geometries",
"type": "array",
"items": {
"$ref": "#/definitions/LefDensityRectangle"
}
},
"layer_name": {
"description": "Layer Name",
"type": "string"
}
}
},
"LefDensityRectangle": {
"title": "Lef Density Rectangle",
"description": "Defined as a rectangle with a numeric density value. One or more of these geometries are associated with a layer name in [LefDensityGeometries]",
"type": "object",
"required": [
"density_value",
"pt1",
"pt2"
],
"properties": {
"density_value": {
"description": "Density Value",
"type": "string",
"pattern": "^-?[0-9]+(\\.[0-9]+)?$"
},
"pt1": {
"description": "Location",
"allOf": [
{
"$ref": "#/definitions/LefPoint"
}
]
},
"pt2": {
"$ref": "#/definitions/LefPoint"
}
}
},
"LefEndCapClassType": {
"description": "Sub-Types for Macros of Class [LefMacroClass::EndCap]",
"oneOf": [
Expand Down Expand Up @@ -600,16 +649,14 @@
]
},
"density": {
"description": "Density Objects (Unsupported)",
"writeOnly": true,
"anyOf": [
{
"$ref": "#/definitions/Unsupported"
},
{
"type": "null"
}
]
"description": "Density Objects",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/LefDensityGeometries"
}
},
"eeq": {
"description": "Electrically-Equivalent Cell",
Expand Down
52 changes: 43 additions & 9 deletions lef21/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,12 @@ pub struct LefMacro {
#[builder(default)]
pub fixed_mask: bool,

/// Density Objects
#[serde(default, skip_serializing_if = "Option::is_none")]
#[builder(default, setter(strip_option))]
pub density: Option<Vec<LefDensityGeometries>>,

// Unsupported
/// Density Objects (Unsupported)
#[serde(default, skip_serializing)]
#[builder(default)]
pub density: Option<Unsupported>,
/// Properties (Unsupported)
#[serde(default, skip_serializing)]
#[builder(default)]
Expand Down Expand Up @@ -391,6 +392,37 @@ pub struct LefLayerGeometries {
#[builder(default, setter(strip_option))]
pub width: Option<LefDecimal>,
}

/// # Lef Density Geometry Store
///
/// Most LEF spatial data (e.g. ports, blockages) is organized by layer.
/// [LefDensityGeometries] stores the combination of a layer (name)
/// and a suite of rectangle density data on that layer.
///
/// [LefDensityGeometries] are the primary building block of [LefDensity].
///
#[derive(Clone, Default, Builder, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
#[builder(pattern = "owned", setter(into))]
pub struct LefDensityGeometries {
// Required
/// Layer Name
pub layer_name: String,
/// Geometries
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub geometries: Vec<LefDensityRectangle>,
}

/// # Lef Density Rectangle
/// Defined as a rectangle with a numeric density value. One or more of these geometries are associated
/// with a layer name in [LefDensityGeometries]
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
pub struct LefDensityRectangle {
/// Location
pub pt1: LefPoint,
pub pt2: LefPoint,
/// Density Value
pub density_value: LefDecimal,
}
/// # Lef Via Instance
///
/// A located instance of via-type `via_name`, typically used as part of a [LefLayerGeometries] definition.
Expand Down Expand Up @@ -648,6 +680,13 @@ enumstr!(
Mask: "MASK",
UseMinSpacing: "USEMINSPACING",

Density: "DENSITY",
TaperRule: "TAPERRULE",
NetExpr: "NETEXPR",
SupplySensitivity: "SUPPLYSENSITIVITY",
GroundSensitivity: "GROUNDSENSITIVITY",
MustJoin: "MUSTJOIN",

// UNITS Fields
Units: "UNITS",
Time: "TIME",
Expand Down Expand Up @@ -680,11 +719,6 @@ enumstr!(
AntennaMaxCutCar: "ANTENNAMAXCUTCAR",

// Unsupported
TaperRule: "TAPERRULE",
NetExpr: "NETEXPR",
SupplySensitivity: "SUPPLYSENSITIVITY",
GroundSensitivity: "GROUNDSENSITIVITY",
MustJoin: "MUSTJOIN",
Property: "PROPERTY",
ManufacturingGrid: "MANUFACTURINGGRID",
ClearanceMeasure: "CLEARANCEMEASURE",
Expand Down
56 changes: 54 additions & 2 deletions lef21/src/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ pub enum LefParseContext {
Geometry,
Site,
Units,
Density,
Unknown,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
Expand Down Expand Up @@ -623,6 +624,9 @@ impl<'src> LefParser<'src> {
self.expect(TokenType::SemiColon)?;
mac.source(e)
}
LefKey::Density => {
mac.density(self.parse_density()?)
}
LefKey::End => {
self.advance()?; // End of Macro. Eat the END key
break;
Expand Down Expand Up @@ -790,6 +794,54 @@ impl<'src> LefParser<'src> {
self.ctx.pop();
Ok(LefPort { layers, class })
}
/// Parse a MACRO::DENSITY definition into a [Vec<LefDensityGeometries>]
fn parse_density(&mut self) -> LefResult<Vec<LefDensityGeometries>> {
self.ctx.push(LefParseContext::Density);
self.expect_key(LefKey::Density)?;
let mut dens_geoms: Vec<LefDensityGeometries> = Vec::new();

// Parse attributes and geometries
// Note this peeks rather than taking the next token,
// largely to accommodate the closing-delimeter-free `LAYER` / [LefDensityGeometries] definitions.
// Other keys generally advance by a Token *after* matching.

loop {
match self.peek_key()? {
LefKey::Layer => {
self.expect_key(LefKey::Layer)?; // Eat the opening LAYER keyword
let mut layer = LefDensityGeometriesBuilder::default();
layer = layer.layer_name(self.parse_ident()?); // Parse the layer-name
self.expect(TokenType::SemiColon)?;
let mut rects: Vec<LefDensityRectangle> = Vec::new();

loop {
match self.peek_key()? {
LefKey::Layer | LefKey::End => break, // End of geometries. (Really start/end of something else.)
LefKey::Rect => {
self.advance()?; // Eat the RECT keyword
let p1: LefPoint = self.parse_point()?;
let p2: LefPoint = self.parse_point()?;
let dens_value: LefDecimal = self.parse_number()?;
rects.push(LefDensityRectangle { pt1: p1, pt2: p2, density_value: dens_value });
self.expect(TokenType::SemiColon)?;
}
_ => self.fail(LefParseErrorType::InvalidKey)?,
}
}
layer = layer.geometries(rects);
let layer = layer.build()?;
dens_geoms.push(layer);
}
LefKey::End => {
self.advance()?; // Eat the END Token
break;
}
_ => self.fail(LefParseErrorType::InvalidKey)?,
}
}
self.ctx.pop();
Ok(dens_geoms)
}
/// Parse a [LefMacro]'s obstruction definitions
fn parse_obstructions(&mut self) -> LefResult<Vec<LefLayerGeometries>> {
self.expect_key(LefKey::Obs)?;
Expand Down Expand Up @@ -835,7 +887,7 @@ impl<'src> LefParser<'src> {
// and exit when another LAYER or END (of a higher-level thing) turn up.
// Note that on end-of-file, i.e. `peek_token` returning `None`, this will exit and return a valid [LefLayerGeometries].
// (Objects above it in the tree may error instead.)
let mut geoms = Vec::new();
let mut geoms: Vec<LefGeometry> = Vec::new();
let mut vias = Vec::new();
loop {
if self.peek_token().is_none() {
Expand Down Expand Up @@ -890,7 +942,7 @@ impl<'src> LefParser<'src> {
}
// Parse the two points
let p1 = self.parse_point()?;
let p2 = self.parse_point()?;
let p2: LefPoint = self.parse_point()?;
self.expect(TokenType::SemiColon)?;
// And return the Rect
Ok(LefGeometry::Shape(LefShape::Rect(mask, p1, p2)))
Expand Down
22 changes: 22 additions & 0 deletions lef21/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,28 @@ fn it_parses_lib2() -> LefResult<()> {
Ok(())
}

#[test]
fn it_parses_density_lib() -> LefResult<()> {
let src = r#"
VERSION 5.8 ;
UNITS DATABASE MICRONS 2000 ; END UNITS
MACRO macro_dens
CLASS BLOCK ;
SIZE 100.0 BY 100.0 ;
DENSITY
LAYER met6 ;
RECT 0.0 0.0 40.0 50.0 46.6 ;
RECT 0.0 50.0 100.0 100.0 90 ;
LAYER met2 ;
RECT 1.0 2.0 3.0 4.0 5.55 ;
END
END macro_dens
"#;
let lib = parse_str(src)?;
//check_yaml(&lib, &resource("lib2.yaml"));
Ok(())
}

#[test]
fn it_parses_no_end_library_5p6() -> LefResult<()> {
let src = r#"
Expand Down
24 changes: 21 additions & 3 deletions lef21/src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,10 @@ impl<'wr> LefWriter<'wr> {
self.indent -= 1;
self.write_line(format_args_f!("{End} "))?;
}

// DENSTITY and PROPERTIES would go here
// if mac.density.is_some() { }
if let Some(ref v) = mac.density {
self.write_density(v)?;
}
// PROPERTIES would go here
// if mac.properties.is_some() { }

self.indent -= 1;
Expand Down Expand Up @@ -354,6 +355,23 @@ impl<'wr> LefWriter<'wr> {
self.write_line(format_args_f!("{Symmetry} {symmstr} ;"))?;
Ok(())
}

/// Write the DENSITY construct which includes LAYER and density RECT statements.
fn write_density(&mut self, dens_geoms: &Vec<LefDensityGeometries>) -> LefResult<()> {
use LefKey::{Density, End, Layer, Rect};
self.write_line(format_args_f!("{Density} "))?;
self.indent += 1;
for layer_geom_set in dens_geoms.iter() {
self.write_line(format_args_f!("{Layer} {layer_geom_set.layer_name} ; "))?;
for dens_rect in layer_geom_set.geometries.iter() {
self.write_line(format_args_f!("{Rect} {dens_rect.pt1} {dens_rect.pt2} {dens_rect.density_value} ; "))?;
}
}
self.indent -= 1;
self.write_line(format_args_f!("{End} "))?;
Ok(())
}

/// Write the [LefMacroClass] enumerations.
/// Note most sub-types use their macro-generated [Display] implementations.
fn write_macro_class(&mut self, class: &LefMacroClass) -> LefResult<()> {
Expand Down

0 comments on commit 0bf349f

Please sign in to comment.