|
|
@ -3,6 +3,7 @@ This module contains data structures and functions for reading from and
|
|
|
|
writing to whole OASIS layout files, and provides a few additional
|
|
|
|
writing to whole OASIS layout files, and provides a few additional
|
|
|
|
abstractions for the data contained inside them.
|
|
|
|
abstractions for the data contained inside them.
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
from typing import List, Dict, Union, Optional
|
|
|
|
import io
|
|
|
|
import io
|
|
|
|
import logging
|
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
|
@ -23,17 +24,17 @@ class FileModals:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
File-scoped modal variables
|
|
|
|
File-scoped modal variables
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
cellname_implicit = None # type: bool or None
|
|
|
|
cellname_implicit: Optional[bool] = None
|
|
|
|
propname_implicit = None # type: bool or None
|
|
|
|
propname_implicit: Optional[bool] = None
|
|
|
|
xname_implicit = None # type: bool or None
|
|
|
|
xname_implicit: Optional[bool] = None
|
|
|
|
textstring_implicit = None # type: bool or None
|
|
|
|
textstring_implicit: Optional[bool] = None
|
|
|
|
propstring_implicit = None # type: bool or None
|
|
|
|
propstring_implicit: Optional[bool] = None
|
|
|
|
cellname_implicit = None # type: bool or None
|
|
|
|
cellname_implicit: Optional[bool] = None
|
|
|
|
|
|
|
|
|
|
|
|
within_cell = False # type: bool
|
|
|
|
within_cell: bool = False
|
|
|
|
within_cblock = False # type: bool
|
|
|
|
within_cblock: bool = False
|
|
|
|
end_has_offset_table = None # type: bool
|
|
|
|
end_has_offset_table: bool
|
|
|
|
started = False # type: bool
|
|
|
|
started: bool = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OasisLayout:
|
|
|
|
class OasisLayout:
|
|
|
@ -43,49 +44,51 @@ class OasisLayout:
|
|
|
|
Names and strings are stored in dicts, indexed by reference number.
|
|
|
|
Names and strings are stored in dicts, indexed by reference number.
|
|
|
|
Layer names and properties are stored directly using their associated
|
|
|
|
Layer names and properties are stored directly using their associated
|
|
|
|
record objects.
|
|
|
|
record objects.
|
|
|
|
Cells are stored using Cell objects (different from Cell record objects).
|
|
|
|
Cells are stored using `Cell` objects (different from `records.Cell`
|
|
|
|
|
|
|
|
record objects).
|
|
|
|
|
|
|
|
|
|
|
|
Properties:
|
|
|
|
Attributes:
|
|
|
|
File properties:
|
|
|
|
(File properties)
|
|
|
|
.version AString: Version string ('1.0')
|
|
|
|
version (AString): Version string ('1.0')
|
|
|
|
.unit real number: grid steps per micron
|
|
|
|
unit (real_t): grid steps per micron
|
|
|
|
.validation Validation: checksum data
|
|
|
|
validation (Validation): checksum data
|
|
|
|
|
|
|
|
|
|
|
|
Names:
|
|
|
|
(Names)
|
|
|
|
.cellnames Dict[int, NString]
|
|
|
|
cellnames (Dict[int, NString]): Cell names
|
|
|
|
.propnames Dict[int, NString]
|
|
|
|
propnames (Dict[int, NString]): Property names
|
|
|
|
.xnames Dict[int, XName]
|
|
|
|
xnames (Dict[int, XName]): Custom names
|
|
|
|
|
|
|
|
|
|
|
|
Strings:
|
|
|
|
(Strings)
|
|
|
|
.textstrings Dict[int, AString]
|
|
|
|
textstrings (Dict[int, AString]): Text strings
|
|
|
|
.propstrings Dict[int, AString]
|
|
|
|
propstrings (Dict[int, AString]): Property strings
|
|
|
|
|
|
|
|
|
|
|
|
Data:
|
|
|
|
(Data)
|
|
|
|
.layers List[records.LayerName]
|
|
|
|
layers (List[records.LayerName]): Layer definitions
|
|
|
|
.properties List[records.Property]
|
|
|
|
properties (List[records.Property]): Property values
|
|
|
|
.cells List[Cell]
|
|
|
|
cells (List[Cell]): Layout cells
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
version = None # type: AString
|
|
|
|
version: AString
|
|
|
|
unit = None # type: real_t
|
|
|
|
unit: real_t
|
|
|
|
validation = None # type: Validation
|
|
|
|
validation: Validation
|
|
|
|
|
|
|
|
|
|
|
|
properties = None # type: List[records.Property]
|
|
|
|
properties: List[records.Property]
|
|
|
|
cells = None # type: List[Cell]
|
|
|
|
cells: List['Cell']
|
|
|
|
|
|
|
|
|
|
|
|
cellnames = None # type: Dict[int, NString]
|
|
|
|
cellnames: Dict[int, NString]
|
|
|
|
propnames = None # type: Dict[int, NString]
|
|
|
|
propnames: Dict[int, NString]
|
|
|
|
xnames = None # type: Dict[int, XName]
|
|
|
|
xnames: Dict[int, 'XName']
|
|
|
|
|
|
|
|
|
|
|
|
textstrings = None # type: Dict[int, AString]
|
|
|
|
textstrings: Dict[int, AString]
|
|
|
|
propstrings = None # type: Dict[int, AString]
|
|
|
|
propstrings: Dict[int, AString]
|
|
|
|
layers = None # type: List[records.LayerName]
|
|
|
|
layers: List[records.LayerName]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, unit: real_t, validation: Validation = None):
|
|
|
|
def __init__(self, unit: real_t, validation: Validation = None):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
:param unit: Real number (i.e. int, float, or Fraction), grid steps per micron.
|
|
|
|
Args:
|
|
|
|
:param validation: Validation object containing checksum data.
|
|
|
|
unit: Real number (i.e. int, float, or `Fraction`), grid steps per micron.
|
|
|
|
Default creates a Validation object of the "no checksum" type.
|
|
|
|
validation: `Validation` object containing checksum data.
|
|
|
|
|
|
|
|
Default creates a `Validation` object of the "no checksum" type.
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
if validation is None:
|
|
|
|
if validation is None:
|
|
|
|
validation = Validation(0)
|
|
|
|
validation = Validation(0)
|
|
|
@ -105,10 +108,13 @@ class OasisLayout:
|
|
|
|
@staticmethod
|
|
|
|
@staticmethod
|
|
|
|
def read(stream: io.BufferedIOBase) -> 'OasisLayout':
|
|
|
|
def read(stream: io.BufferedIOBase) -> 'OasisLayout':
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Read an entire .oas file into an OasisLayout object.
|
|
|
|
Read an entire .oas file into an `OasisLayout` object.
|
|
|
|
|
|
|
|
|
|
|
|
:param stream: Stream to read from.
|
|
|
|
Args:
|
|
|
|
:return: New OasisLayout object.
|
|
|
|
stream: Stream to read from.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
New `OasisLayout` object.
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
file_state = FileModals()
|
|
|
|
file_state = FileModals()
|
|
|
|
modals = Modals()
|
|
|
|
modals = Modals()
|
|
|
@ -127,15 +133,20 @@ class OasisLayout:
|
|
|
|
) -> bool:
|
|
|
|
) -> bool:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Read a single record of unspecified type from a stream, adding its
|
|
|
|
Read a single record of unspecified type from a stream, adding its
|
|
|
|
contents into this OasisLayout object.
|
|
|
|
contents into this `OasisLayout` object.
|
|
|
|
|
|
|
|
|
|
|
|
:param stream: Stream to read from.
|
|
|
|
Args:
|
|
|
|
:param modals: Modal variable data, used to fill unfilled record
|
|
|
|
stream: Stream to read from.
|
|
|
|
fields and updated using filled record fields.
|
|
|
|
modals: Modal variable data, used to fill unfilled record
|
|
|
|
:param file_state: File status data.
|
|
|
|
fields and updated using filled record fields.
|
|
|
|
:return: True if EOF was reached without error, False otherwise.
|
|
|
|
file_state: File status data.
|
|
|
|
:raises: InvalidRecordError from unexpected records;
|
|
|
|
|
|
|
|
InvalidDataError from within record parsers.
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
`True` if EOF was reached without error, `False` otherwise.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
|
|
|
|
InvalidRecordError: from unexpected records
|
|
|
|
|
|
|
|
InvalidDataError: from within record parsers
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
record_id = read_uint(stream)
|
|
|
|
record_id = read_uint(stream)
|
|
|
@ -304,9 +315,14 @@ class OasisLayout:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Write this object in OASIS fromat to a stream.
|
|
|
|
Write this object in OASIS fromat to a stream.
|
|
|
|
|
|
|
|
|
|
|
|
:param stream: Stream to write to.
|
|
|
|
Args:
|
|
|
|
:return: Number of bytes written.
|
|
|
|
stream: Stream to write to.
|
|
|
|
:raises: InvalidDataError if contained records are invalid.
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
Number of bytes written.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
|
|
|
|
InvalidDataError: if contained records are invalid.
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
modals = Modals()
|
|
|
|
modals = Modals()
|
|
|
|
|
|
|
|
|
|
|
@ -357,21 +373,22 @@ class Cell:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Representation of an OASIS cell.
|
|
|
|
Representation of an OASIS cell.
|
|
|
|
|
|
|
|
|
|
|
|
Properties:
|
|
|
|
Attributes:
|
|
|
|
.name NString or int (CellName reference number)
|
|
|
|
name (Union[NString, int]): name or "CellName reference" number
|
|
|
|
|
|
|
|
|
|
|
|
.properties List of records.Property
|
|
|
|
properties (List[records.Property]): Properties of this cell
|
|
|
|
.placements List of records.Placement
|
|
|
|
placements (List[records.Placement]): Placement record objects
|
|
|
|
.geometry List of geometry record objectes
|
|
|
|
geometry: (List[records.geometry_t]): Geometry record objectes
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
name = None # type: NString or int
|
|
|
|
name: Union[NString, int]
|
|
|
|
properties = None # type: List[records.Property]
|
|
|
|
properties: List[records.Property]
|
|
|
|
placements = None # type: List[records.Placement]
|
|
|
|
placements: List[records.Placement]
|
|
|
|
geometry = None # type: List[records.geometry_t]
|
|
|
|
geometry: List[records.geometry_t]
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, name: NString or int):
|
|
|
|
def __init__(self, name: Union[NString, int]):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
:param name: NString or int (CellName reference number)
|
|
|
|
Args:
|
|
|
|
|
|
|
|
name: `NString` or "CellName reference" number
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
self.name = name
|
|
|
|
self.name = name
|
|
|
|
self.properties = []
|
|
|
|
self.properties = []
|
|
|
@ -383,10 +400,15 @@ class Cell:
|
|
|
|
Write this cell to a stream, using the provided modal variables to
|
|
|
|
Write this cell to a stream, using the provided modal variables to
|
|
|
|
deduplicate any repeated data.
|
|
|
|
deduplicate any repeated data.
|
|
|
|
|
|
|
|
|
|
|
|
:param stream: Stream to write to.
|
|
|
|
Args:
|
|
|
|
:param modals: Modal variables to use for deduplication.
|
|
|
|
stream: Stream to write to.
|
|
|
|
:return: Number of bytes written.
|
|
|
|
modals: Modal variables to use for deduplication.
|
|
|
|
:raises: InvalidDataError if contained records are invalid.
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
Number of bytes written.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
|
|
|
|
InvalidDataError: if contained records are invalid.
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
size = records.Cell(self.name).dedup_write(stream, modals)
|
|
|
|
size = records.Cell(self.name).dedup_write(stream, modals)
|
|
|
|
size += sum(p.dedup_write(stream, modals) for p in self.properties)
|
|
|
|
size += sum(p.dedup_write(stream, modals) for p in self.properties)
|
|
|
@ -399,16 +421,17 @@ class XName:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Representation of an XName.
|
|
|
|
Representation of an XName.
|
|
|
|
|
|
|
|
|
|
|
|
This class is effectively a simplified form of a records.XName,
|
|
|
|
This class is effectively a simplified form of a `records.XName`,
|
|
|
|
with the reference data stripped out.
|
|
|
|
with the reference data stripped out.
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
attribute = None # type: int
|
|
|
|
attribute: int
|
|
|
|
bstring = None # type: bytes
|
|
|
|
bstring: bytes
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, attribute: int, bstring: bytes):
|
|
|
|
def __init__(self, attribute: int, bstring: bytes):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
:param attribute: Attribute number.
|
|
|
|
Args:
|
|
|
|
:param bstring: Binary data.
|
|
|
|
attribute: Attribute number.
|
|
|
|
|
|
|
|
bstring: Binary data.
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
self.attribute = attribute
|
|
|
|
self.attribute = attribute
|
|
|
|
self.bstring = bstring
|
|
|
|
self.bstring = bstring
|
|
|
@ -416,10 +439,13 @@ class XName:
|
|
|
|
@staticmethod
|
|
|
|
@staticmethod
|
|
|
|
def from_record(record: records.XName) -> 'XName':
|
|
|
|
def from_record(record: records.XName) -> 'XName':
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Create an XName object from a records.XName record.
|
|
|
|
Create an `XName` object from a `records.XName` record.
|
|
|
|
|
|
|
|
|
|
|
|
:param record: XName record to use.
|
|
|
|
Args:
|
|
|
|
:return: XName object.
|
|
|
|
record: XName record to use.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
`XName` object.
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
return XName(record.attribute, record.bstring)
|
|
|
|
return XName(record.attribute, record.bstring)
|
|
|
|
|
|
|
|
|
|
|
|