Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mask and iterate #54

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -522,18 +522,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 @@ -1392,9 +1386,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 @@ -1407,9 +1418,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 @@ -1497,6 +1525,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 @@ -1592,7 +1648,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 @@ -426,7 +426,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 All @@ -451,17 +451,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 @@ -662,6 +671,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 @@ -925,49 +925,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
Loading