Skip to content

Commit

Permalink
Merge pull request #54 from nanobowers/mask_and_iterate
Browse files Browse the repository at this point in the history
Mask and iterate
  • Loading branch information
dan-fritchman authored Feb 13, 2025
2 parents 6f4e228 + 3360796 commit 80b6dfd
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 69 deletions.
6 changes: 3 additions & 3 deletions layout21raw/src/lef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ impl<'lib> LefExporter<'lib> {
.iter()
.map(|p| self.export_point(p))
.collect::<Result<Vec<_>, _>>()?;
lef21::LefShape::Polygon(points)
lef21::LefShape::Polygon(None, points)
}
Shape::Path { .. } => {
unimplemented!("LefExporter::PATH");
Expand Down Expand Up @@ -380,8 +380,8 @@ impl LefImporter {
use lef21::LefShape::{Path, Polygon, Rect};
match lefshape {
Rect(_, ref p0, ref p1) => self.import_rect((p0, p1)),
Polygon(ref pts) => self.import_polygon(pts),
Path(ref pts) => self.import_path(pts, layer),
Polygon(_, ref pts) => self.import_polygon(pts),
Path(_, ref pts) => self.import_path(pts, layer),
}
}
/// Import a [Shape::Poly]
Expand Down
86 changes: 71 additions & 15 deletions lef21/resources/lef21.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -549,18 +549,12 @@
"Iterate": {
"type": "object",
"required": [
"pattern",
"shape"
],
"properties": {
"pattern": {
"anyOf": [
{
"$ref": "#/definitions/Unsupported"
},
{
"type": "null"
}
]
"$ref": "#/definitions/LefStepPattern"
},
"shape": {
"$ref": "#/definitions/LefShape"
Expand Down Expand Up @@ -1608,9 +1602,26 @@
"properties": {
"Polygon": {
"type": "array",
"items": {
"$ref": "#/definitions/LefPoint"
}
"items": [
{
"anyOf": [
{
"$ref": "#/definitions/LefMask"
},
{
"type": "null"
}
]
},
{
"type": "array",
"items": {
"$ref": "#/definitions/LefPoint"
}
}
],
"maxItems": 2,
"minItems": 2
}
},
"additionalProperties": false
Expand All @@ -1623,9 +1634,26 @@
"properties": {
"Path": {
"type": "array",
"items": {
"$ref": "#/definitions/LefPoint"
}
"items": [
{
"anyOf": [
{
"$ref": "#/definitions/LefMask"
},
{
"type": "null"
}
]
},
{
"type": "array",
"items": {
"$ref": "#/definitions/LefPoint"
}
}
],
"maxItems": 2,
"minItems": 2
}
},
"additionalProperties": false
Expand Down Expand Up @@ -1713,6 +1741,34 @@
}
]
},
"LefStepPattern": {
"title": "Lef Step Pattern for ITERATE",
"type": "object",
"required": [
"numx",
"numy",
"spacex",
"spacey"
],
"properties": {
"numx": {
"type": "string",
"pattern": "^-?[0-9]+(\\.[0-9]+)?$"
},
"numy": {
"type": "string",
"pattern": "^-?[0-9]+(\\.[0-9]+)?$"
},
"spacex": {
"type": "string",
"pattern": "^-?[0-9]+(\\.[0-9]+)?$"
},
"spacey": {
"type": "string",
"pattern": "^-?[0-9]+(\\.[0-9]+)?$"
}
}
},
"LefSymmetry": {
"description": "Specifies which MACRO orientations are valid for placement",
"oneOf": [
Expand Down Expand Up @@ -1808,7 +1864,7 @@
},
"LefVia": {
"title": "Lef Via Instance",
"description": "A located instance of via-type `via_name`, typically used as part of a [LefLayerGeometries] definition. The via-type is generally interpreted as a string-valued reference into tech-lef data. It is stored in each [LefVia] exactly as in LEF, as a string type-name.",
"description": "A located instance of via-type `via_name`, typically used as part of a [LefLayerGeometries] definition. The via-type is generally interpreted as a string-valued <reference into tech-lef data. It is stored in each [LefVia] exactly as in LEF, as a string type-name.",
"type": "object",
"required": [
"pt",
Expand Down
20 changes: 16 additions & 4 deletions lef21/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ pub struct LefDensityRectangle {
/// # Lef Via Instance
///
/// A located instance of via-type `via_name`, typically used as part of a [LefLayerGeometries] definition.
/// The via-type is generally interpreted as a string-valued reference into tech-lef data.
/// The via-type is generally interpreted as a string-valued <reference into tech-lef data.
/// It is stored in each [LefVia] exactly as in LEF, as a string type-name.
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
pub struct LefVia {
Expand Down Expand Up @@ -487,17 +487,26 @@ pub enum LefGeometry {
/// Repeated Iteration/ Array of Shapes (Unsupported)
Iterate {
shape: LefShape,
pattern: Option<Unsupported>,
pattern: LefStepPattern,
},
}

/// # Lef Step Pattern for ITERATE
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
pub struct LefStepPattern {
pub numx: LefDecimal,
pub numy: LefDecimal,
pub spacex: LefDecimal,
pub spacey: LefDecimal,
}
/// # Lef Shape Enumeration
/// Includes each of LEF's individual geometric primitives:
/// rectangles, polygons, and paths.
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
pub enum LefShape {
Rect(Option<LefMask>, LefPoint, LefPoint),
Polygon(Vec<LefPoint>),
Path(Vec<LefPoint>),
Polygon(Option<LefMask>, Vec<LefPoint>),
Path(Option<LefMask>, Vec<LefPoint>),
}
/// # Lef X-Y Spatial Point
///
Expand Down Expand Up @@ -698,6 +707,9 @@ enumstr!(
RowPattern: "ROWPATTERN",
Site: "SITE",
Size: "SIZE",
Do: "DO",
Iterate: "ITERATE",
Step: "STEP",
By: "BY",
BusBitChars: "BUSBITCHARS",
DividerChar: "DIVIDERCHAR",
Expand Down
80 changes: 59 additions & 21 deletions lef21/src/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -995,49 +995,87 @@ impl<'src> LefParser<'src> {
self.ctx.pop();
Ok(layer)
}

/// Parse optional ITERATE and return a wrapper boolean indicating success
fn parse_iterate(&mut self) -> LefResult<bool> {
if self.matches(TokenType::Name) {
if self.peek_key()? == LefKey::Iterate {
self.advance()?;
return Ok(true)
}
}
Ok(false)
}
/// Parse the [LefMask] statement on a [LefGeometry]
fn parse_geometry_mask(&mut self) -> LefResult<Option<LefMask>> {
//let mut mask: Option<LefMask> = None;
if self.matches(TokenType::Name) {
if self.peek_key()? == LefKey::Mask {
self.advance()?;
return Ok(Some(LefMask::new(self.parse_number()?)));
}
}
Ok(None)
}
fn parse_step_pattern(&mut self) -> LefResult<LefStepPattern> {
self.expect_key(LefKey::Do)?;
let numx = self.parse_number()?;
self.expect_key(LefKey::By)?;
let numy = self.parse_number()?;
self.expect_key(LefKey::Step)?;
let spacex = self.parse_number()?;
let spacey = self.parse_number()?;
Ok(LefStepPattern {numx, numy, spacex, spacey})
}
/// Parse a [LefGeometry] statement
/// Each can be a shape or iteration thereof
fn parse_geometry(&mut self) -> LefResult<LefGeometry> {
match self.peek_key()? {
match self.get_key()? {
LefKey::Rect => {
self.advance()?;
let mut mask = None;
if self.matches(TokenType::Name) {
if self.get_key()? == LefKey::Mask {
mask = Some(LefMask::new(self.parse_number()?));
} else {
// The ITERATE construction would go here, but is not supported.
self.fail(LefParseErrorType::Unsupported)?;
}
}
let mask = self.parse_geometry_mask()?;
let is_iterate = self.parse_iterate()?;
// Parse the two points
let p1 = 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)))
let p2 = self.parse_point()?;
let shape = LefShape::Rect(mask, p1, p2);
Ok(self.parse_geometry_tail(is_iterate, shape)?)
}
LefKey::Polygon => {
self.advance()?;
let mask = self.parse_geometry_mask()?;
let is_iterate = self.parse_iterate()?;
let points = self.parse_point_list()?;
if points.len() < 3 {
self.fail(LefParseErrorType::InvalidValue)?;
}
self.expect(TokenType::SemiColon)?;
Ok(LefGeometry::Shape(LefShape::Polygon(points)))
let shape = LefShape::Polygon(mask, points);
Ok(self.parse_geometry_tail(is_iterate, shape)?)
}
LefKey::Path => {
self.advance()?;
let mask = self.parse_geometry_mask()?;
let is_iterate = self.parse_iterate()?;
let points = self.parse_point_list()?;
if points.len() < 2 {
self.fail(LefParseErrorType::InvalidValue)?;
}
self.expect(TokenType::SemiColon)?;
Ok(LefGeometry::Shape(LefShape::Path(points)))
let shape = LefShape::Path(mask, points);
Ok(self.parse_geometry_tail(is_iterate, shape)?)
}
_ => self.fail(LefParseErrorType::InvalidKey)?,
}
}
/// Parse the tail end of a geometry statement after the point-set.
/// either it will end with a semicolon (non-iterate case)
/// or have a [LefStepPattern] in the iterate case.
fn parse_geometry_tail(&mut self, is_iterate: bool, shape: LefShape) -> LefResult<LefGeometry> {
if is_iterate {
let pattern = self.parse_step_pattern()?;
self.expect(TokenType::SemiColon)?;
Ok(LefGeometry::Iterate { shape, pattern })
} else {
self.expect(TokenType::SemiColon)?;
Ok(LefGeometry::Shape(shape)) // And return the Rect
}
}
/// Parse a space-separated list of [LefPoint]. Terminated by [TokenType::SemiColon].
fn parse_point_list(&mut self) -> LefResult<Vec<LefPoint>> {
let mut points = Vec::new();
Expand Down
26 changes: 26 additions & 0 deletions lef21/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,32 @@ fn it_parses_lib2() -> LefResult<()> {
Ok(())
}

#[test]
fn it_parses_colored_geometries() -> LefResult<()> {
let src = r#"
VERSION 5.8 ;
UNITS DATABASE MICRONS 2000 ; END UNITS
MACRO invx1
CLASS BLOCK ;
SIZE 1.0 BY 1.0 ;
PIN A
DIRECTION INPUT ;
PORT
LAYER metal1 ;
RECT MASK 1 0.000 0.100 1.000 0.150 ;
RECT MASK 2 0.000 0.200 1.000 0.250 ;
RECT MASK 3 0.000 0.300 1.000 0.350 ;
PATH MASK 4 0.000 0.425 1.000 0.425 ;
POLYGON MASK 5 0.000 0.600 0.000 0.700 0.500 0.700 0.500 0.750 0.000 0.750 ;
END
END A
END invx1
END LIBRARY
"#;
parse_str(src)?;
Ok(())
}

#[test]
fn it_parses_density_lib() -> LefResult<()> {
let src = r#"
Expand Down
Loading

0 comments on commit 80b6dfd

Please sign in to comment.