From 76cb7ea289f44164b8232efb6869e6d371db8510 Mon Sep 17 00:00:00 2001 From: Ben Bowers Date: Wed, 10 Jul 2024 07:28:06 -0400 Subject: [PATCH 1/3] adding code and a test for parsing/storing DENSITY in a MACRO --- lef21/src/data.rs | 52 ++++++++++++++++++++++++++++++++++-------- lef21/src/read.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++-- lef21/src/tests.rs | 22 ++++++++++++++++++ 3 files changed, 119 insertions(+), 11 deletions(-) diff --git a/lef21/src/data.rs b/lef21/src/data.rs index 42ad0df..7073f94 100644 --- a/lef21/src/data.rs +++ b/lef21/src/data.rs @@ -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>, + // Unsupported - /// Density Objects (Unsupported) - #[serde(default, skip_serializing)] - #[builder(default)] - pub density: Option, /// Properties (Unsupported) #[serde(default, skip_serializing)] #[builder(default)] @@ -391,6 +392,37 @@ pub struct LefLayerGeometries { #[builder(default, setter(strip_option))] pub width: Option, } + +/// # 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, +} + +/// # 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. @@ -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", @@ -680,11 +719,6 @@ enumstr!( AntennaMaxCutCar: "ANTENNAMAXCUTCAR", // Unsupported - TaperRule: "TAPERRULE", - NetExpr: "NETEXPR", - SupplySensitivity: "SUPPLYSENSITIVITY", - GroundSensitivity: "GROUNDSENSITIVITY", - MustJoin: "MUSTJOIN", Property: "PROPERTY", ManufacturingGrid: "MANUFACTURINGGRID", ClearanceMeasure: "CLEARANCEMEASURE", diff --git a/lef21/src/read.rs b/lef21/src/read.rs index 5f2a9ce..9964ed0 100644 --- a/lef21/src/read.rs +++ b/lef21/src/read.rs @@ -305,6 +305,7 @@ pub enum LefParseContext { Geometry, Site, Units, + Density, Unknown, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -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; @@ -790,6 +794,54 @@ impl<'src> LefParser<'src> { self.ctx.pop(); Ok(LefPort { layers, class }) } + /// Parse a MACRO::DENSITY definition into a [Vec] + fn parse_density(&mut self) -> LefResult> { + self.ctx.push(LefParseContext::Density); + self.expect_key(LefKey::Density)?; + let mut dens_geoms: Vec = 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 = 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> { self.expect_key(LefKey::Obs)?; @@ -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 = Vec::new(); let mut vias = Vec::new(); loop { if self.peek_token().is_none() { @@ -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))) diff --git a/lef21/src/tests.rs b/lef21/src/tests.rs index aca566b..214b464 100644 --- a/lef21/src/tests.rs +++ b/lef21/src/tests.rs @@ -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#" From ed610fe9e0121d14021e3a36d9e9a5ed08d64663 Mon Sep 17 00:00:00 2001 From: Ben Bowers Date: Wed, 10 Jul 2024 07:57:27 -0400 Subject: [PATCH 2/3] adding density to schema --- lef21/resources/lef21.schema.json | 67 ++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/lef21/resources/lef21.schema.json b/lef21/resources/lef21.schema.json index 6f5d3bf..983e52c 100644 --- a/lef21/resources/lef21.schema.json +++ b/lef21/resources/lef21.schema.json @@ -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": [ @@ -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", From a5d3376f8a3d11bbb90b8334b946821c4857c70d Mon Sep 17 00:00:00 2001 From: Ben Bowers Date: Wed, 10 Jul 2024 08:16:11 -0400 Subject: [PATCH 3/3] added writer for DENSITY --- lef21/src/write.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/lef21/src/write.rs b/lef21/src/write.rs index c0baa01..baaaac7 100644 --- a/lef21/src/write.rs +++ b/lef21/src/write.rs @@ -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; @@ -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) -> 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<()> {