diff --git a/lef21/resources/lef21.schema.json b/lef21/resources/lef21.schema.json index 99b6b2a..01728d9 100644 --- a/lef21/resources/lef21.schema.json +++ b/lef21/resources/lef21.schema.json @@ -373,6 +373,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": [ @@ -627,16 +676,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", diff --git a/lef21/src/data.rs b/lef21/src/data.rs index ffb59ac..0928fd2 100644 --- a/lef21/src/data.rs +++ b/lef21/src/data.rs @@ -218,12 +218,12 @@ pub struct LefMacro { #[builder(default)] pub properties: Vec, - // Unsupported - /// Density Objects (Unsupported) - #[serde(default, skip_serializing)] - #[builder(default)] - pub density: Option, + /// Density Objects + #[serde(default, skip_serializing_if = "Option::is_none")] + #[builder(default, setter(strip_option))] + pub density: Option>, } + impl LefMacro { /// Create a new and initially empty [LefMacro] with name `name` pub fn new(name: impl Into) -> LefMacro { @@ -406,6 +406,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. @@ -693,7 +724,8 @@ enumstr!( Property: "PROPERTY", ManufacturingGrid: "MANUFACTURINGGRID", ClearanceMeasure: "CLEARANCEMEASURE", - + Density: "DENSITY", + // UNITS Fields Units: "UNITS", Time: "TIME", diff --git a/lef21/src/read.rs b/lef21/src/read.rs index 3db0db5..ea25c9a 100644 --- a/lef21/src/read.rs +++ b/lef21/src/read.rs @@ -307,6 +307,7 @@ pub enum LefParseContext { Geometry, Site, Units, + Density, Unknown, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -689,6 +690,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; @@ -860,6 +864,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)?; @@ -905,7 +957,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() { @@ -960,7 +1012,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#" diff --git a/lef21/src/write.rs b/lef21/src/write.rs index dfb5a9a..036e8c2 100644 --- a/lef21/src/write.rs +++ b/lef21/src/write.rs @@ -292,8 +292,9 @@ impl<'wr> LefWriter<'wr> { for prop in mac.properties.iter() { self.write_property(prop)?; } - // DENSTITY would go here - // if mac.density.is_some() { } + if let Some(ref v) = mac.density { + self.write_density(v)?; + } self.indent -= 1; self.write_line(format_args_f!("{End} {} ", mac.name))?; @@ -451,6 +452,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<()> {