#!/usr/bin/python
########################################################################################################################
#
# Copyright (c) 2020, Nifty Chips Laboratory, Hanyang University
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
# following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
# disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
# following disclaimer in the documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
########################################################################################################################
"""
**laygo2.object.database** module consists of the classes implementing a hierarchical structure database that manages design and library.
"""
__author__ = "Jaeduk Han"
__maintainer__ = "Jaeduk Han"
__status__ = "Prototype"
import laygo2.object
import numpy as np
from laygo2.object.physical import PhysicalObject
from laygo2.object.grid import Grid
from laygo2.object.template import Template
from laygo2._typing import T
from typing import overload, Generic, Dict, Type, Union
[docs]
class BaseDatabase(Generic[T]):
"""
A base class that implements basic functions for
various database objects, such as libraries and designs.
"""
name = None
"""str: Name of BaseDatabase object.
Example
-------
>>> import laygo2
>>> base = laygo2.object.database.BaseDatabase(name="mycell")
>>> base.name
"mycell"
"""
params = None
"""dict or None: BaseDatabase object's parameter dictionary.
Example
-------
>>> import laygo2
>>> base = laygo2.object.database.BaseDatabase(name="mycell",
params={'ivdd': 0.001})
>>> base.params
{'ivdd': 0.001}
"""
elements: Dict[str, Type[Union[PhysicalObject, T]]] = None
"""dict: Element object dictionary.
Example
-------
>>> import laygo2
>>> from laygo2.object.database import BaseDatabase
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> # Create a design.
>>> dsn = BaseDatabase(name="mycell")
>>> # Create layout objects.
>>> r0 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
>>> p0 = Pin(xy=[[0, 0], [50, 50]], layer=["M1", "pin"], name="P")
>>> i0 = Instance(libname="tlib", cellname="t0", name="I0", xy=[0, 0])
>>> t0 = Text(xy=[[50, 50], [100, 100]], layer=["text", "drawing"], text="T")
>>> # Add layout objects to the design.
>>> dsn.append(r0)
>>> dsn.append(p0)
>>> dsn.append(i0)
>>> dsn.append(t0)
>>> #
>>> # Display elements of the design.
>>> print(dsn.elements)
{'NoName_0': <laygo2.object.physical.Rect object at 0x0000024C6C230F40>,
'P': <laygo2.object.physical.Pin object at 0x0000024C6C2EFF40>,
'I0': <laygo2.object.physical.Instance object at 0x0000024C6C2EFDC0>,
'NoName_1': <laygo2.object.physical.Text object at 0x0000024C6C2EF8B0>}
"""
noname_index = 0
"""
int: Unique identifier index for unnamed objects.
Example
-------
>>> import laygo2
>>> from laygo2.object.database import BaseDatabase
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> # Create a design
>>> dsn = BaseDatabase(name="mycell")
>>> # Create layout objects
>>> r0 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
>>> dsn.append(r0)
>>> print(base.noname_index)
0
>>> r1 = Rect(xy=[[100, 100], [200, 200]], layer=["M1", "drawing"])
>>> dsn.append(r1)
>>> print(base.noname_index)
1
"""
# @property
[docs]
def keys(self):
"""Keys of elements.
Example
-------
>>> import laygo2
>>> from laygo2.object.database import BaseDatabase
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> # Create a design
>>> dsn = BaseDatabase(name="mycell")
>>> # Create layout objects
>>> r0 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
>>> p0 = Pin(xy=[[0, 0], [50, 50]], layer=["M1", "pin"], name="P")
>>> i0 = Instance(libname="tlib", cellname="t0", name="I0", xy=[0, 0])
>>> t0 = Text(xy=[[50, 50], [100, 100]], layer=["text", "drawing"], text="T")
>>> dsn.append(r0)
>>> dsn.append(p0)
>>> dsn.append(i0)
>>> dsn.append(t0)
>>> print(dsn.keys())
dict_keys(['NoName_0', 'P', 'I0', 'NoName_1'])
"""
return self.elements.keys()
[docs]
def items(self):
"""
Key-object pairs of elements.
Parameters
----------
None
Returns
-------
dict_items
Example
-------
>>> import laygo2
>>> from laygo2.object.database import BaseDatabase
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> # Create a design
>>> dsn = BaseDatabase(name="mycell")
>>> # Create layout objects
>>> r0 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
>>> p0 = Pin(xy=[[0, 0], [50, 50]], layer=["M1", "pin"], name="P")
>>> i0 = Instance(libname="tlib", cellname="t0", name="I0", xy=[0, 0])
>>> t0 = Text(xy=[[50, 50], [100, 100]], layer=["text", "drawing"], text="T")
>>> dsn.append(r0)
>>> dsn.append(p0)
>>> dsn.append(i0)
>>> dsn.append(t0)
>>> print(dsn.items())
dict_items([('NoName_0', <laygo2.object.physical.Rect object at 0x0000024C6C230F40>),
('P', <laygo2.object.physical.Pin object at 0x0000024C6C2EFF40>),
('I0', <laygo2.object.physical.Instance object at 0x0000024C6C2EFDC0>),
('NoName_1', <laygo2.object.physical.Text object at 0x0000024C6C2EF8B0>)])
"""
return self.elements.items()
@overload
def __getitem__(self: "BaseDatabase[T]", pos) -> Type[T]: ...
@overload
def __getitem__(self: "BaseDatabase[None]", pos) -> Type[PhysicalObject]: ...
def __getitem__(self, pos):
"""
Return the object corresponding to pos.
Parameters
----------
pos : str
Name of object.
Returns
-------
laygo2.object.physical : corresponding object.
Example
-------
>>> import laygo2
>>> from laygo2.object.database import BaseDatabase
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> # Create a design
>>> dsn = BaseDatabase(name="mycell")
>>> # Create layout objects
>>> r0 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
>>> p0 = Pin(xy=[[0, 0], [50, 50]], layer=["M1", "pin"], name="P")
>>> i0 = Instance(libname="tlib", cellname="t0", name="I0", xy=[0, 0])
>>> t0 = Text(xy=[[50, 50], [100, 100]], layer=["text", "drawing"], text="T")
>>> dsn.append(r0)
>>> dsn.append(p0)
>>> dsn.append(i0)
>>> dsn.append(t0)
>>> print(dsn["I0"])
<laygo2.object.physical.Instance object at 0x0000024C6C2EFDC0>
name: I0,
class: Instance,
xy: [0, 0],
params: None,
size: [0, 0]
shape: None
pitch: [0, 0]
transform: R0
pins: {}
"""
return self.elements[pos]
def __setitem__(self, key, item):
"""
Add key/object pair.
Parameters
----------
key : str
Object key (name).
Example
-------
>>> import laygo2
>>> from laygo2.object.database import BaseDatabase
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> # Create a design
>>> dsn = BaseDatabase(name="mycell")
>>> # Create layout objects
>>> r1 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
>>> dsn.append(r1)
>>> r2 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
>>> dsn["R2"] = r2
>>> print(dsn["R2"])
<laygo2.object.physical.Rect object at 0x0000024C6C107C40>
name: R2,
class: Rect,
xy: [[0, 0], [100, 100]],
params: None, , layer: ['M1', 'drawing'], netname: None
"""
item.name = key
self.append(item)
[docs]
def append(self, item):
"""Add physical object to BaseDatabase without taking any further actions.
Parameters
----------
item : laygo2.object.physical.PhysicalObject
Physical object to be added.
Returns
-------
list :
List of item name and item ([item.name, item]).
Example
-------
>>> import laygo2
>>> from laygo2.object.database import BaseDatabase
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> # Create a design
>>> dsn = Design(name="mycell", libname="genlib")
>>> # Create layout objects
>>> r0 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
>>> p0 = Pin(xy=[[0, 0], [50, 50]], layer=["M1", "pin"], name="P")
>>> i0 = Instance(libname="tlib", cellname="t0", name="I0", xy=[0, 0])
>>> t0 = Text(xy=[[50, 50], [100, 100]], layer=["text", "drawing"], text="T")
>>> dsn.append(r0)
>>> dsn.append(p0)
>>> dsn.append(i0)
>>> dsn.append(t0)
>>> print(dsn)
<laygo2.object.database.BaseDatabase object at 0x0000024C6C2EF010>
name: mycell, params: None
elements: {
'NoName_0': <laygo2.object.physical.Rect object at 0x0000024C6C230F40>,
'P': <laygo2.object.physical.Pin object at 0x0000024C6C2EFF40>,
'I0': <laygo2.object.physical.Instance object at 0x0000024C6C2EFDC0>,
'NoName_1': <laygo2.object.physical.Text object at 0x0000024C6C2EF8B0>}
See Also
--------
laygo2.object.database.Library.append
laygo2.object.database.Design.append
"""
if isinstance(item, list) or isinstance(item, np.ndarray):
item_name_list = []
item_list = []
for i in item:
_item_name, _item = self.append(i)
item_name_list.append(_item_name)
item_list.append(_item)
return item_name_list, item_list
# return [i[0] for i in item_list], [i[1] for i in item_list]
else:
item_name = item.name
if item_name is None: # NoName object. Put a name on it.
while "NoName_" + str(self.noname_index) in self.elements.keys():
self.noname_index += 1
item_name = "NoName_" + str(self.noname_index)
self.noname_index += 1
errstr = item_name + " cannot be added to " + self.name + ", as a child object with the same name exists."
if item_name in self.elements.keys():
raise KeyError(errstr)
else:
if item_name in self.elements.keys():
raise KeyError(errstr)
else:
self.elements[item_name] = item
return item_name, item
def __iter__(self):
"""Element-mapped direct iterator function.
Example
-------
>>> import laygo2
>>> from laygo2.object.database import BaseDatabase
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> # Create a design
>>> dsn = BaseDatabase(name="mycell")
>>> # Create layout objects
>>> r0 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
>>> p0 = Pin(xy=[[0, 0], [50, 50]], layer=["M1", "pin"], name="P")
>>> i0 = Instance(libname="tlib", cellname="t0", name="I0", xy=[0, 0])
>>> t0 = Text(xy=[[50, 50], [100, 100]], layer=["text", "drawing"], text="T")
>>> dsn.append(r0)
>>> dsn.append(p0)
>>> dsn.append(i0)
>>> for o in dsn.items():
>>> print(o)
('NoName_0', <laygo2.object.physical.Rect object at 0x0000024C6C230F40>)
('P', <laygo2.object.physical.Pin object at 0x0000024C6C2EFF40>)
('I0', <laygo2.object.physical.Instance object at 0x0000024C6C2EFDC0>)
('NoName_1', <laygo2.object.physical.Text object at 0x0000024C6C2EF8B0>)
"""
return self.elements.__iter__()
def __str__(self):
return self.summarize()
[docs]
def summarize(self):
"""Get object information summary."""
return (
self.__repr__() + " " + "name: " + self.name + ", " + "params: " + str(self.params) + " \n"
" elements: " + str(self.elements) + ""
)
[docs]
def __init__(self, name, params=None, elements=None):
"""
BaseDatabase class constructor function.
Parameters
----------
name : str
BaseDatabase object name.
params : dict, optional
parameters of BaseDatabase.
elements : dict, optional
dictionary having the elements of BaseDatabase.
Returns
-------
laygo2.object.BaseDatabase
Example
-------
>>> import laygo2
>>> base = laygo2.object.database.BaseDatabase(name='mycell')
>>> print(base)
<laygo2.object.database.BaseDatabase object>
name: mycell, params: None elements: {}>
"""
self.name = name
self.params = params
self.elements = dict()
if elements is not None:
for e in elements:
self.elements[e] = elements[e]
class LibraryWrapper(BaseDatabase[T]):
def get_libname(self):
"""getter function of libname property."""
return self.name
def set_libname(self, val):
"""setter function of libname property."""
self.name = val
libname = property(get_libname, set_libname)
"""str: The name of library.
Example
-------
>>> import laygo2
>>> lib = laygo2.object.database.Library(name='mylib')
>>> print(lib.name)
"mylib"
"""
def append(self, item: T):
"""Add physical object to Library without taking any further actions.
"""
if isinstance(item, list) or isinstance(item, np.ndarray):
item_name_list = []
item_list = []
for i in item:
_item_name, _item = self.append(i)
item_name_list.append(_item_name)
item_list.append(_item)
return item_name_list, item_list
else:
item_name, item = BaseDatabase.append(self, item)
item.libname = self.name # update library name
return item_name, item
def __init__(self, name, params=None, elements=None):
"""Constructor function of Library class.
Parameters
----------
name : str
Library object name.
params : dict, optional
Library parameters.
elements : dict, optional
Dictionary having the elements of Library.
Returns
-------
laygo2.object.Library
Example
-------
>>> import laygo2
>>> lib = laygo2.object.database.Library(name='mylib')
>>> print(lib)
<laygo2.object.database.Library > name: mylib, params: None elements: {} >
"""
BaseDatabase.__init__(self, name=name, params=params, elements=elements)
def summarize(self):
"""Get object information summary."""
return BaseDatabase.summarize(self)
[docs]
class Library(LibraryWrapper["Design"]):
"""
Class for library management function implementation.
Example
-------
>>> import laygo2
>>> lib = laygo2.object.database.Library(name="mylib")
>>> dsn0 = laygo2.object.database.Design(name="mycell0")
>>> dsn1 = laygo2.object.database.Design(name="mycell1")
>>> lib.append(dsn0)
>>> lib.append(dsn1)
>>> print(lib)
<laygo2.object.database.Library object at 0x0000025F2D25B8B0>
name: mylib, params: None
elements: {
'mycell0': <laygo2.object.database.Design object at 0x0000025F2D25B010>,
'mycell1': <laygo2.object.database.Design object at 0x0000025F2D25BF70>}
See Also
--------
laygo2.object.databse.Design: Check for more comprehensive Example.
"""
pass
class TemplateLibrary(LibraryWrapper[Template]):
"""Class implementing template libraries with templates as child objects."""
# TODO: implement this.
pass
class GridLibrary(LibraryWrapper[Grid]):
"""Class implementing grid libraries with grids as child objects."""
# TODO: implement this.
pass
[docs]
class Design(BaseDatabase):
"""
Class for design management function implementation.
Example
-------
A physical (non-abstract) grid example:
>>> import laygo2
>>> from laygo2.object.database import Design
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> # Create a design.
>>> dsn = Design(name="mycell", libname="genlib")
>>> # Create layout objects.
>>> r0 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
>>> p0 = Pin(xy=[[0, 0], [50, 50]], layer=["M1", "pin"], name="P")
>>> i0 = Instance(libname="tlib", cellname="t0", name="I0", xy=[0, 0])
>>> t0 = Text(xy=[[50, 50], [100, 100]], layer=["text", "drawing"], text="T")
>>> # Add the layout objects to the design object.
>>> dsn.append(r0)
>>> dsn.append(p0)
>>> dsn.append(i0)
>>> dsn.append(t0)
>>> print(dsn)
<laygo2.object.database.Design object at 0x0000024C6C2EF010>
name: mycell, params: None
elements: {
'NoName_0': <laygo2.object.physical.Rect object at 0x0000024C6C230F40>,
'P': <laygo2.object.physical.Pin object at 0x0000024C6C2EFF40>,
'I0': <laygo2.object.physical.Instance object at 0x0000024C6C2EFDC0>,
'NoName_1': <laygo2.object.physical.Text object at 0x0000024C6C2EF8B0>}
libname:genlib
rects:{
'NoName_0': <laygo2.object.physical.Rect object at 0x0000024C6C230F40>}
paths:{}
pins:{
'P': <laygo2.object.physical.Pin object at 0x0000024C6C2EFF40>}
texts:{
'NoName_1': <laygo2.object.physical.Text object at 0x0000024C6C2EF8B0>}
instances:{
'I0': <laygo2.object.physical.Instance object at 0x0000024C6C2EFDC0>}
virtual instances:{}
>>> #
>>> # Export to a NativeInstanceTemplate for reuse in higher levels.
>>> nt0 = dsn.export_to_template()
>>> nt0.dsn.export_to_template()
>>> print(nt0)
<laygo2.object.template.NativeInstanceTemplate object at 0x000001CB5A9CE380>
name: mycell,
class: NativeInstanceTemplate,
bbox: [[0, 0], [0, 0]],
pins: {'P': <laygo2.object.physical.Pin object at 0x000001CB5A9CFF40>},
>>> #
>>> # Export to a skill script.
>>> lib = laygo2.object.database.Library(name="mylib")
>>> lib.append(dsn)
>>> scr = laygo2.interface.skill.export(lib, filename="myscript.il")
>>> print(scr)
; (definitions of laygo2 skill functions)
; exporting mylib__mycell
cv = _laygo2_open_layout("mylib" "mycell" "layout")
_laygo2_generate_rect(cv, list( "M1" "drawing" ), list( list( 0.0000 0.0000 ) list( 0.1000 0.1000 ) ), "None")
_laygo2_generate_pin(cv, "P", list( "M1" "pin" ), list( list( 0.0000 0.0000 ) list( 0.0500 0.0500 ) ) )
_laygo2_generate_instance(cv, "I0", "tlib", "t0", "layout", list( 0.0000 0.0000 ), "R0", 1, 1, 0, 0, nil, nil)
_laygo2_save_and_close_layout(cv)
An abstract grid example:
>>> import laygo2
>>> from laygo2.object.grid import CircularMapping as CM
>>> from laygo2.object.grid import CircularMappingArray as CMA
>>> from laygo2.object.grid import OneDimGrid, PlacementGrid, RoutingGrid
>>> from laygo2.object.template import NativeInstanceTemplate
>>> from laygo2.object.database import Design
>>> from laygo2.object.physical import Instance
>>> # Placement grid construction (not needed if laygo2_tech is set up).
>>> gx = OneDimGrid(name="gx", scope=[0, 20], elements=[0])
>>> gy = OneDimGrid(name="gy", scope=[0, 100], elements=[0])
>>> gp = PlacementGrid(name="test", vgrid=gx, hgrid=gy)
>>> # Routing grid construction (not needed if laygo2_tech is set up).
>>> gv = OneDimGrid(name="gv", scope=[0, 50], elements=[0])
>>> gh = OneDimGrid(name="gv", scope=[0, 100], elements=[0, 40, 60])
>>> wv = CM([10]) # vertical (xgrid) width
>>> wh = CM([20, 10, 10]) # horizontal (ygrid) width
>>> ev = CM([10]) # vertical (xgrid) extension
>>> eh = CM([10, 10, 10]) # horizontal (ygrid) extension
>>> e0v = CM([15]) # vert. extension (for zero-length wires)
>>> e0h = CM([15, 15, 15]) # hori. extension (for zero-length wires)
>>> lv = CM([['M1', 'drawing']], dtype=object) # layer information
>>> lh = CM([['M2', 'drawing']]*3, dtype=object)
>>> plv = CM([['M1', 'pin']], dtype=object) # pin layers
>>> plh = CM([['M2', 'pin']]*3, dtype=object)
>>> xcolor = CM([None], dtype=object) # not multipatterned
>>> ycolor = CM([None]*3, dtype=object)
>>> primary_grid = 'horizontal'
>>> tvia = NativeInstanceTemplate(libname='tlib', cellname='via0') # via
>>> viamap = CMA(elements=[[tvia, tvia, tvia]], dtype=object)
>>> gr = laygo2.object.grid.RoutingGrid(name='mygrid', vgrid=gv, hgrid=gh,
vwidth=wv, hwidth=wh,
vextension=ev, hextension=eh,
vlayer=lv, hlayer=lh,
pin_vlayer=plv, pin_hlayer=plh,
viamap=viamap, primary_grid=primary_grid,
xcolor=xcolor, ycolor=ycolor,
vextension0=e0v, hextension0=e0h)
>>> # Create a design
>>> dsn = Design(name="mycell", libname="genlib")
>>> # Create an instance
>>> i0 = Instance(libname="tlib", cellname="t0", name="I0", xy=[0, 0])
>>> print(inst0.xy)
[100, 100]
>>> # Place the instance
>>> dsn.place(inst=i0, grid=gp, mn=[10,10])
>>> # Routing on grid
>>> mn_list = [[0, -2], [0, 1], [2, 1], [5,1] ]
>>> route = dsn.route(grid=gr, mn=mn_list,
via_tag=[True, None, True, True])
>>> #
>>> # Display generated design.
>>> print(dsn)
<laygo2.object.database.Design object at 0x000001C71AE3A110>
...
>>> #
>>> # Export to a NativeInstanceTemplate for reuse in higher levels.
>>> nt0 = dsn.export_to_template()
>>> nt0.dsn.export_to_template()
>>> print(nt0)
...
>>> #
>>> # Export to a skill script.
>>> lib = laygo2.object.database.Library(name="mylib")
>>> lib.append(dsn)
>>> scr = laygo2.interface.skill.export(lib, filename="myscript.il")
>>> print(scr)
...
An abstract template/grid example with technology setup (laygo2_tech):
>>> import laygo2
>>> import laygo2.interface
>>> import laygo2_tech_quick_start as tech # target tech's laygo2_tech
>>> from laygo2.object.database import Design
>>> templates = tech.load_templates()
>>> mytemplate = templates['nmos']
>>> grids = tech.load_grids(templates=templates)
>>> gp = grids['placement_basic']
>>> gr = grids['routing_23_cmos']
>>> # Create a design
>>> dsn = Design(name="mycell", libname="genlib")
>>> # Create an instance
>>> i0 = tnmos.generate(name='MN0', params={'nf': 4})
>>> # Place the instance
>>> dsn.place(inst=i0, grid=gp, mn=[10,10])
>>> # Routing on grid
>>> mn_list = [[0, -2], [0, 1], [2, 1], [5,1] ]
>>> route = dsn.route(grid=gr, mn=mn_list,
via_tag=[True, None, True, True])
>>> #
>>> # Display generated design.
>>> print(dsn)
<laygo2.object.database.Design object at 0x000001C71AE3A110>
...
>>> #
>>> # Export to a NativeInstanceTemplate for reuse in higher levels.
>>> nt0 = dsn.export_to_template()
>>> nt0.dsn.export_to_template()
>>> print(nt0)
...
>>> #
>>> # Export to a skill script.
>>> lib = laygo2.object.database.Library(name="mylib")
>>> lib.append(dsn)
>>> scr = laygo2.interface.skill.export(lib, filename="myscript.il")
>>> print(scr)
...
"""
@property
def bbox(self):
"""Get design bounding box by taking union of instances' bounding boxes."""
libname = self.libname
cellname = self.cellname
# Compute boundaries
xy = [None, None]
for n, i in self.instances.items():
if xy[0] is None:
xy[0] = i.bbox[0] # bl
xy[1] = i.bbox[1] # tr
else:
#xy = np.minimum(xy, i.bbox)
xy[0][0] = min(xy[0][0], i.bbox[0, 0])
xy[0][1] = min(xy[0][1], i.bbox[0, 1])
xy[1][0] = max(xy[1][0], i.bbox[1, 0])
xy[1][1] = max(xy[1][1], i.bbox[1, 1])
for n, i in self.virtual_instances.items():
if xy[0] is None:
xy[0] = i.bbox[0]
xy[1] = i.bbox[1]
else:
#y = np.minimum(xy, i.bbox)
xy[0][0] = min(xy[0][0], i.bbox[0, 0])
xy[0][1] = min(xy[0][1], i.bbox[0, 1])
xy[1][0] = max(xy[1][0], i.bbox[1, 0])
xy[1][1] = max(xy[1][1], i.bbox[1, 1])
xy = np.array(xy)
return xy
[docs]
def get_libname(self):
return self._libname
[docs]
def set_libname(self, val):
self._libname = val
libname = property(get_libname, set_libname)
"""str: Design object's library name.
Example
-------
>>> import laygo2
>>> dsn = laygo2.object.database.Design(name="dsn", libname="testlib")
>>> print(dsn.libname)
“testlib”
"""
[docs]
def get_cellname(self):
return self.name
[docs]
def set_cellname(self, val):
self.name = val
cellname = property(get_cellname, set_cellname)
"""str: Design object's cell name.
Example
-------
>>> import laygo2
>>> dsn = laygo2.object.database.Design(name="dsn", libname="testlib")
>>> print(dsn.cellname)
“dsn”
"""
rects = None
"""dict: Dictionary containing Rectangle object affiliated with the
Design object.
Example
-------
>>> import laygo2
>>> from laygo2.object.database import Design
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> dsn = Design(name="dsn", libname="testlib")
>>> r0 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
>>> dsn.append(r0)
>>> print(dsn.rects)
{'R0': <laygo2.object.physical.Rect object>}
"""
[docs]
def get_r(self):
return self.rects
[docs]
def set_r(self, val):
self.rects = val
r = property(get_r, set_r)
"""str: Alias of rects."""
paths = None
pins = None
"""dict: Dictionary having the collection of Pin objects affiliated
with the Design object.
Example
-------
>>> import laygo2
>>> from laygo2.object.database import Design
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> dsn = Design(name="dsn", libname="testlib")
>>> p0 = Pin(xy=[[0, 0], [50, 50]], layer=["M1", "pin"], name="P")
>>> dsn.append(p0)
>>> print(dsn.pins)
{'NoName_0': <laygo2.object.physical.Pin object>}
"""
[docs]
def get_p(self):
return self.pins
[docs]
def set_p(self, val):
self.pins = val
p = property(get_p, set_p)
"""str: Alias of pins."""
texts = None
"""dict: Dictionary containing Text objects affiliated with Design object.
Example
-------
>>> import laygo2
>>> from laygo2.object.database import Design
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> dsn = Design(name="dsn", libname="testlib")
>>> t0 = Text(xy=[[50, 50], [100, 100]], layer=["text", "drawing"], text="T")
>>> dsn.append(t0)
>>> print(dsn.texts)
{'NoName_1': <laygo2.object.physical.Text object>}
"""
instances = None
"""dict: Dictionary containing Instance objects affiliated with Design object.
Example
-------
>>> import laygo2
>>> from laygo2.object.database import Design
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> dsn = Design(name="dsn", libname="testlib")
>>> i0 = Instance(libname="tlib", cellname="t0", name="I0", xy=[0, 0])
>>> dsn.append(i0)
>>> print(dsn.instances)
{'I0': <laygo2.object.physical.Instance object>}
"""
[docs]
def get_i(self):
return self.instances
[docs]
def set_i(self, val):
self.instances = val
i = property(get_i, set_i)
"""str: Alias of instances."""
virtual_instances = None
"""dict: Dictionary containing VirtualInstance objects affiliated with
Design object.
See Also
--------
instances
"""
[docs]
def get_vi(self):
return self.virtual_instances
[docs]
def set_vi(self, val):
self.virtual_instances = val
vi = property(get_vi, set_vi)
"""str: Alias of virtual_instances."""
def __iter__(self):
"""Element-mapped direct iterator function.
Example
-------
>>> import laygo2
>>> from laygo2.object.database import Design
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> # Create a design
>>> dsn = Design(name="mycell", libname="genlib")
>>> # Create layout objects
>>> r0 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
>>> p0 = Pin(xy=[[0, 0], [50, 50]], layer=["M1", "pin"], name="P")
>>> i0 = Instance(libname="tlib", cellname="t0", name="I0", xy=[0, 0])
>>> t0 = Text(xy=[[50, 50], [100, 100]], layer=["text", "drawing"], text="T")
>>> dsn.append(r0)
>>> dsn.append(p0)
>>> dsn.append(i0)
>>> for o in dsn.items():
>>> print(o)
('NoName_0', <laygo2.object.physical.Rect object at 0x0000024C6C230F40>)
('P', <laygo2.object.physical.Pin object at 0x0000024C6C2EFF40>)
('I0', <laygo2.object.physical.Instance object at 0x0000024C6C2EFDC0>)
('NoName_1', <laygo2.object.physical.Text object at 0x0000024C6C2EF8B0>)
"""
return self.elements.__iter__()
[docs]
def __init__(self, name, params=None, elements=None, libname=None):
"""
Design class constructor function.
Parameters
----------
name : str
Design object name.
params : dict, optional
Design object parameters.
elements : dict, optional
Design object elements.
Returns
-------
laygo2.object.BaseDatabase
Example
-------
>>> import laygo2
>>> dsn = laygo2.object.database.Design(name='dsn', libname="testlib")
>>> print(dsn)
<laygo2.object.database.Design object> name: dsn, params: None
elements: {}
libname:testlib
rects:{}
paths:{}
pins:{}
texts:{}
instances:{}
virtual instances:{}
"""
self.libname = libname
self.rects = dict()
self.paths = dict()
self.pins = dict()
self.texts = dict()
self.instances = dict()
self.virtual_instances = dict()
BaseDatabase.__init__(self, name=name, params=params, elements=elements)
[docs]
def append(self, item):
"""Add physical object to Design without taking any further actions.
Parameters
----------
item : laygo2.object.physical.PhysicalObject
The physical object to be added.
Returns
-------
list :
A list containing the name of item and the item itself ([item.name, item]).
Example
-------
>>> import laygo2
>>> from laygo2.object.database import Design
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> # Create a design
>>> dsn = Design(name="mycell", libname="genlib")
>>> # Create layout objects
>>> r0 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
>>> p0 = Pin(xy=[[0, 0], [50, 50]], layer=["M1", "pin"], name="P")
>>> i0 = Instance(libname="tlib", cellname="t0", name="I0", xy=[0, 0])
>>> t0 = Text(xy=[[50, 50], [100, 100]], layer=["text", "drawing"], text="T")
>>> dsn.append(r0)
>>> dsn.append(p0)
>>> dsn.append(i0)
>>> dsn.append(t0)
>>> print(dsn)
<laygo2.object.database.Design object at 0x0000024C6C2EF010>
name: mycell, params: None
elements: {
'NoName_0': <laygo2.object.physical.Rect object at 0x0000024C6C230F40>,
'P': <laygo2.object.physical.Pin object at 0x0000024C6C2EFF40>,
'I0': <laygo2.object.physical.Instance object at 0x0000024C6C2EFDC0>,
'NoName_1': <laygo2.object.physical.Text object at 0x0000024C6C2EF8B0>}
libname:genlib
rects:{
'NoName_0': <laygo2.object.physical.Rect object at 0x0000024C6C230F40>}
paths:{}
pins:{
'P': <laygo2.object.physical.Pin object at 0x0000024C6C2EFF40>}
texts:{
'NoName_1': <laygo2.object.physical.Text object at 0x0000024C6C2EF8B0>}
instances:{
'I0': <laygo2.object.physical.Instance object at 0x0000024C6C2EFDC0>}
virtual instances:{}
See Also
--------
laygo2.object.database.Design.place : Place a (virtual) instance
on a grid and append to the design.
laygo2.object.database.Design.route : Route on a grid and append
to the design.
laygo2.object.database.Design.route_via_track : Route on a track
on a grid and append.
laygo2.object.database.Design.pin : Place a pin on a grid and
append to the design.
"""
if isinstance(item, list) or isinstance(item, np.ndarray):
return [self.append(i) for i in item]
else:
if item is None:
return None, None # don't do anything
item_name, _item = BaseDatabase.append(self, item)
if item.__class__ == laygo2.object.Rect:
self.rects[item_name] = item
elif item.__class__ == laygo2.object.Path:
self.paths[item_name] = item
elif item.__class__ == laygo2.object.Pin:
self.pins[item_name] = item
elif item.__class__ == laygo2.object.Text:
self.texts[item_name] = item
elif item.__class__ == laygo2.object.Instance:
self.instances[item_name] = item
elif item.__class__ == laygo2.object.VirtualInstance:
self.virtual_instances[item_name] = item
return item_name, item
[docs]
def summarize(self):
"""Get object information summary."""
return (
BaseDatabase.summarize(self)
+ " \n"
+ " libname:"
+ str(self.libname)
+ " \n"
+ " rects:"
+ str(self.rects)
+ " \n"
+ " paths:"
+ str(self.paths)
+ " \n"
+ " pins:"
+ str(self.pins)
+ " \n"
+ " texts:"
+ str(self.texts)
+ " \n"
+ " instances:"
+ str(self.instances)
+ "\n"
+ " virtual instances:"
+ str(self.virtual_instances)
+ ""
)
# Object creation and manipulation functions.
[docs]
def place(self, inst, grid, mn=[0, 0], anchor_xy=None):
"""
Place instance at abstract coordinate mn on abstract grid.
Parameters
----------
inst : laygo2.object.physical.Instance or laygo2.object.physical.VirtualInstance or list
Instance(s) to be placed (when list, placed in order).
grid : laygo2.object.grid.PlacementGrid
Placement grid for instance placement.
mn : numpy.ndarray or list
Abstract coordinate value [m, n] for instance placement.
anchor_xy : list
A list that contains two overlap coordinates for placement
(1st for absolute physical grid, 2nd for relative instance position).
Returns
-------
laygo2.object.physical.Instance or laygo2.object.physical.VirtualInstance or list(laygo2.object.physical.Instance):
Placed instance(s) (list if multiple).
Example
-------
>>> import laygo2
>>> from laygo2.object.grid import OneDimGrid, PlacementGrid
>>> from laygo2.object.database import Design
>>> from laygo2.object.physical import Instance
>>> # Create a grid (not needed if laygo2_tech is set up).
>>> gx = OneDimGrid(name="gx", scope=[0, 20], elements=[0])
>>> gy = OneDimGrid(name="gy", scope=[0, 100], elements=[0])
>>> g = PlacementGrid(name="test", vgrid=gx, hgrid=gy)
>>> # Create a design
>>> dsn = Design(name="mycell", libname="genlib")
>>> # Create an instance
>>> i0 = Instance(libname="tlib", cellname="t0", name="I0", xy=[0, 0])
>>> print(inst0.xy)
[100, 100]
>>> ######################
>>> # Place the instance #
>>> ######################
>>> dsn.place(inst=i0, grid=g, mn=[10,10])
>>> # Print parameters of the placed instance.
>>> print(i0.xy)
[200, 1000]
>>> print(dsn)
<laygo2.object.database.Design object at 0x000002803D4C0F40>
name: mycell
params: None
elements:
{'I0': <laygo2.object.physical.Instance object at
0x000002803D57F010>}
libname:genlib
rects:{}
paths:{}
pins:{}
texts:{}
instances:
{'I0': <laygo2.object.physical.Instance object at 0x000002803D57F010>}
virtual instances:{}
>>> # When placing multiple instances by wrapping them with a list:
>>> i1 = Instance(libname="tlib", cellname="t1", name="I1", xy=[0, 0])
>>> i2 = Instance(libname="tlib", cellname="t2", name="I2", xy=[0, 0])
>>> i3 = Instance(libname="tlib", cellname="t3", name="I3", xy=[0, 0])
>>> dsn.place(inst= [i1, i2, i3], grid=g, mn=[10,10])
>>> print(dsn)
<laygo2.object.database.Design object at 0x000002803D4C0F40>
name: mycell
params: None
elements:
{'I0': <laygo2.object.physical.Instance object at
0x000002803D57F010>,
'I1': <laygo2.object.physical.Instance object at
0x000002803D57F011>,
'I2': <laygo2.object.physical.Instance object at
0x000002803D57F012>,
'I3': <laygo2.object.physical.Instance object at
0x000002803D57F013>
}
libname:genlib
rects:{}
paths:{}
pins:{}
texts:{}
instances:
{'I0': <laygo2.object.physical.Instance object at 0x000002803D57F010>,
'I1': <laygo2.object.physical.Instance object at 0x000002803D57F011>,
'I2': <laygo2.object.physical.Instance object at 0x000002803D57F012>,
'I3': <laygo2.object.physical.Instance object at 0x000002803D57F013>
}
virtual instances:{}
See Also
--------
laygo2.object.grid.PlacementGrid.place : place a (virtual) instance
on the grid.
"""
if isinstance(inst, (laygo2.object.Instance, laygo2.object.VirtualInstance)):
# single instance
if anchor_xy is None:
_mn = mn
else:
_xy = anchor_xy[0] - anchor_xy[1]
_mn = mn + grid.mn(_xy)
inst = grid.place(inst, _mn)
self.append(inst)
return inst
else:
# multiple instances (anchor_xy is not supported yet)
matrix = np.asarray(inst)
size = matrix.shape
if len(size) == 2:
m, n = size
else: # when 1-dimentional array
m, n = 1, size[0]
matrix = [matrix]
mn_ref = np.array(mn)
for index in range(m):
row = matrix[index]
if index != 0:
ns = 0
ms = index - 1
while row[ns] == None: # Right search
ns = ns + 1
while matrix[ms][ns] == None: # Down search
ms = ms - 1
mn_ref = grid.mn.top_left(matrix[ms][ns])
for element in row:
if isinstance(element, (laygo2.object.Instance, laygo2.object.VirtualInstance)):
mn_bl = grid.mn.bottom_left(element)
mn_comp = mn_ref - mn_bl
inst_sub = grid.place(element, mn_comp)
self.append(inst_sub)
mn_ref = grid.mn.bottom_right(element)
else:
if element == None:
pass
elif isinstance(element, int):
mn_ref = mn_ref + [element, 0] # offset
return inst
[docs]
def route(self, grid, mn, direction=None, via_tag=None):
"""
Create wire object(s) for routing at abstract coordinate **mn**.
Parameters
----------
grid : laygo2.object.grid.RoutingGrid
Placement grid for wire placement.
mn : list(numpy.ndarray)
List containing two or more **mn** coordinates to be connected.
direction : str, optional.
None or “vertical” or "horizontal". The direction of the routing
object.
via_tag : list(Boolean), optional.
The list containing switches deciding whether to place via at
the edges.
Returns
-------
laygo2.object.physical.Rect or list :
The generated routing object(s).
Check the example code in laygo2.object.grid.RoutingGrid.route
for details.
Example
-------
>>> import laygo2
>>> from laygo2.object.grid import CircularMapping as CM
>>> from laygo2.object.grid import CircularMappingArray as CMA
>>> from laygo2.object.grid import OneDimGrid, RoutingGrid
>>> from laygo2.object.template import NativeInstanceTemplate
>>> from laygo2.object.database import Design
>>> from laygo2.object.physical import Instance
>>> # Routing grid construction (not needed if laygo2_tech is set up).
>>> gv = OneDimGrid(name="gv", scope=[0, 50], elements=[0])
>>> gh = OneDimGrid(name="gv", scope=[0, 100], elements=[0, 40, 60])
>>> wv = CM([10]) # vertical (xgrid) width
>>> wh = CM([20, 10, 10]) # horizontal (ygrid) width
>>> ev = CM([10]) # vertical (xgrid) extension
>>> eh = CM([10, 10, 10]) # horizontal (ygrid) extension
>>> e0v = CM([15]) # vert. extension (for zero-length wires)
>>> e0h = CM([15, 15, 15]) # hori. extension (for zero-length wires)
>>> lv = CM([['M1', 'drawing']], dtype=object) # layer information
>>> lh = CM([['M2', 'drawing']]*3, dtype=object)
>>> plv = CM([['M1', 'pin']], dtype=object) # pin layers
>>> plh = CM([['M2', 'pin']]*3, dtype=object)
>>> xcolor = CM([None], dtype=object) # not multipatterned
>>> ycolor = CM([None]*3, dtype=object)
>>> primary_grid = 'horizontal'
>>> tvia = NativeInstanceTemplate(libname='tlib', cellname='via0') # via
>>> viamap = CMA(elements=[[tvia, tvia, tvia]], dtype=object)
>>> g = laygo2.object.grid.RoutingGrid(name='mygrid', vgrid=gv, hgrid=gh,
vwidth=wv, hwidth=wh,
vextension=ev, hextension=eh,
vlayer=lv, hlayer=lh,
pin_vlayer=plv, pin_hlayer=plh,
viamap=viamap, primary_grid=primary_grid,
xcolor=xcolor, ycolor=ycolor,
vextension0=e0v, hextension0=e0h)
>>> # Create a design
>>> dsn = Design(name="mycell", libname="genlib")
>>> #################
>>> # Route on grid #
>>> #################
>>> mn_list = [[0, -2], [0, 1], [2, 1], [5,1] ]
>>> route = dsn.route(grid=g, mn=mn_list,
via_tag=[True, None, True, True])
>>> # Display generated design.
>>> print(dsn)
<laygo2.object.database.Design object at 0x000001C71AE3A110>
name: mycell, params: None
elements: {
'NoName_0': <laygo2.object.physical.Instance object at 0x000001C71AE3BA90>,
'NoName_1': <laygo2.object.physical.Rect object at 0x000001C71AE3B820>,
'NoName_2': <laygo2.object.physical.Rect object at 0x000001C71AE3ABF0>,
'NoName_3': <laygo2.object.physical.Instance object at 0x000001C71AE3A140>,
'NoName_4': <laygo2.object.physical.Rect object at 0x000001C71AE39DB0>,
'NoName_5': <laygo2.object.physical.Instance object at 0x000001C71AE3AB60>}
libname:genlib
rects: { # wires
'NoName_1': <laygo2.object.physical.Rect object at 0x000001C71AE3B820>,
'NoName_2': <laygo2.object.physical.Rect object at 0x000001C71AE3ABF0>,
'NoName_4': <laygo2.object.physical.Rect object at 0x000001C71AE39DB0>}
paths:{}
pins:{}
texts:{}
instances:{ # vias
'NoName_0': <laygo2.object.physical.Instance object at 0x000001C71AE3BA90>,
'NoName_3': <laygo2.object.physical.Instance object at 0x000001C71AE3A140>,
'NoName_5': <laygo2.object.physical.Instance object at 0x000001C71AE3AB60>}
virtual instances:{}
.. image:: ../assets/img/object_grid_RoutingGrid_route.png
:height: 250
See Also
--------
laygo2.object.grid.RoutingGrid.route : route wire(s) on the grid.
"""
r = grid.route(mn=mn, direction=direction, via_tag=via_tag)
self.append(r)
return r
[docs]
def via(self, grid, mn, params=None):
"""
Create Via object(s) on abstract grid.
Parameters
----------
mn : list(numpy.ndarray)
Abstract coordinate(s) that specify location(s) to insert via(s).
Returns
-------
list(physical.PhysicalObject):
The list containing the generated via objects.
Example
-------
>>> import laygo2
>>> from laygo2.object.grid import CircularMapping as CM
>>> from laygo2.object.grid import CircularMappingArray as CMA
>>> from laygo2.object.grid import OneDimGrid, RoutingGrid
>>> from laygo2.object.template import NativeInstanceTemplate
>>> from laygo2.object.database import Design
>>> from laygo2.object.physical import Instance
>>> # Routing grid construction (not needed if laygo2_tech is set up).
>>> gv = OneDimGrid(name="gv", scope=[0, 50], elements=[0])
>>> gh = OneDimGrid(name="gv", scope=[0, 100], elements=[0, 40, 60])
>>> wv = CM([10]) # vertical (xgrid) width
>>> wh = CM([20, 10, 10]) # horizontal (ygrid) width
>>> ev = CM([10]) # vertical (xgrid) extension
>>> eh = CM([10, 10, 10]) # horizontal (ygrid) extension
>>> e0v = CM([15]) # vert. extension (for zero-length wires)
>>> e0h = CM([15, 15, 15]) # hori. extension (for zero-length wires)
>>> lv = CM([['M1', 'drawing']], dtype=object) # layer information
>>> lh = CM([['M2', 'drawing']]*3, dtype=object)
>>> plv = CM([['M1', 'pin']], dtype=object) # pin layers
>>> plh = CM([['M2', 'pin']]*3, dtype=object)
>>> xcolor = CM([None], dtype=object) # Not multipatterned
>>> ycolor = CM([None]*3, dtype=object)
>>> primary_grid = 'horizontal'
>>> tvia = NativeInstanceTemplate(libname='tlib', cellname='via0')
>>> viamap = CMA(elements=[[tvia, tvia, tvia]], dtype=object)
>>> g = laygo2.object.grid.RoutingGrid(name='mygrid', vgrid=gv, hgrid=gh,
vwidth=wv, hwidth=wh,
vextension=ev, hextension=eh,
vlayer=lv, hlayer=lh,
pin_vlayer=plv, pin_hlayer=plh,
viamap=viamap, primary_grid=primary_grid,
xcolor=xcolor, ycolor=ycolor,
vextension0=e0v, hextension0=e0h)
>>> # Create a design
>>> dsn = Design(name="mycell", libname="genlib")
>>> ##############
>>> # Place vias #
>>> ##############
>>> mn_list = [[0, -2], [1, 0], [2, 5]]
>>> via = dsn.via(grid=g, mn=mn_list)
>>> # Display generated design.
>>> print(dsn)
<laygo2.object.database.Design object at 0x0000015A77C6A110>
name: mycell, params: None,
elements: {
'NoName_0': <laygo2.object.physical.Instance object at 0x0000015A77C6AC20>,
'NoName_1': <laygo2.object.physical.Instance object at 0x0000015A77C6AD10>,
'NoName_2': <laygo2.object.physical.Instance object at 0x0000015A77C6AD40>}
libname:genlib
rects:{}
paths:{}
pins:{}
texts:{}
instances:{
'NoName_0': <laygo2.object.physical.Instance object at 0x0000015A77C6AC20>,
'NoName_1': <laygo2.object.physical.Instance object at 0x0000015A77C6AD10>,
'NoName_2': <laygo2.object.physical.Instance object at 0x0000015A77C6AD40>}
virtual instances:{}
.. image:: ../assets/img/object_grid_RoutingGrid_via.png
:height: 250
See Also
--------
laygo2.object.grid.RoutingGrid.via
"""
v = grid.via(mn=mn, params=params)
self.append(v)
return v
[docs]
def route_via_track(self, grid, mn, track, via_tag=[None, True]):
"""
Perform routing on the specified track with accessing wires to mn.
Parameters
----------
grid : laygo2.object.grid.RoutingGrid
The placement grid where the wire is placed on.
mn : list(numpy.ndarray)
list containing coordinates of the points being connected through a track
track : numpy.ndarray
list containing coordinate values and direction of a track.
Vertical tracks have [v, None] format, while horizontal tracks have [None, v] format
(v is the coordinates of the track).
via_tag : list(Boolean), optional.
The list containing switches deciding whether to place via at
the edges of individual stubs.
Returns
-------
list:
The list containing the generated routing objects;
The last object corresponds to the routing object on the track.
Example
-------
>>> import laygo2
>>> from laygo2.object.grid import CircularMapping as CM
>>> from laygo2.object.grid import CircularMappingArray as CMA
>>> from laygo2.object.grid import OneDimGrid, RoutingGrid
>>> from laygo2.object.template import NativeInstanceTemplate
>>> from laygo2.object.database import Design
>>> from laygo2.object.physical import Instance
>>> # Routing grid construction (not needed if laygo2_tech is set up).
>>> gv = OneDimGrid(name="gv", scope=[0, 50], elements=[0])
>>> gh = OneDimGrid(name="gv", scope=[0, 100], elements=[0, 40, 60])
>>> wv = CM([10]) # vertical (xgrid) width
>>> wh = CM([20, 10, 10]) # horizontal (ygrid) width
>>> ev = CM([10]) # vertical (xgrid) extension
>>> eh = CM([10, 10, 10]) # horizontal (ygrid) extension
>>> e0v = CM([15]) # vert. extension (for zero-length wires)
>>> e0h = CM([15, 15, 15]) # hori. extension (for zero-length wires)
>>> lv = CM([['M1', 'drawing']], dtype=object) # layer information
>>> lh = CM([['M2', 'drawing']]*3, dtype=object)
>>> plv = CM([['M1', 'pin']], dtype=object) # pin layers
>>> plh = CM([['M2', 'pin']]*3, dtype=object)
>>> xcolor = CM([None], dtype=object) # not multipatterned
>>> ycolor = CM([None]*3, dtype=object)
>>> primary_grid = 'horizontal'
>>> tvia = NativeInstanceTemplate(libname='tlib', cellname='via0') # via
>>> viamap = CMA(elements=[[tvia, tvia, tvia]], dtype=object)
>>> g = laygo2.object.grid.RoutingGrid(name='mygrid', vgrid=gv, hgrid=gh,
vwidth=wv, hwidth=wh,
vextension=ev, hextension=eh,
vlayer=lv, hlayer=lh,
pin_vlayer=plv, pin_hlayer=plh,
viamap=viamap, primary_grid=primary_grid,
xcolor=xcolor, ycolor=ycolor,
vextension0=e0v, hextension0=e0h)
>>> # Create a design
>>> dsn = Design(name="mycell", libname="genlib")
>>> # Do routing
>>> mn_list = [[0, -2], [1, 0], [2, 5], [3, 4], [4, 5], [5, 5]]
>>> track = dsn.route_via_track(grid=g, mn=mn_list, track=[None,0])
>>> # Display design
>>> print(dsn)
<laygo2.object.database.Design object at 0x0000015A77C6BA60>
name: mycell, params: None
elements: {
'NoName_0': <laygo2.object.physical.Rect object at 0x0000015A77C6B790>,
'NoName_1': <laygo2.object.physical.Instance object at 0x0000015A77C6B820>,
'NoName_2': <laygo2.object.physical.Instance object at 0x0000015A77C6B7C0>,
'NoName_3': <laygo2.object.physical.Rect object at 0x0000015A77C6B760>,
'NoName_4': <laygo2.object.physical.Instance object at 0x0000015A77C6A2F0>,
'NoName_5': <laygo2.object.physical.Rect object at 0x0000015A77C6BA90>}
libname:genlib
rects:{
'NoName_0': <laygo2.object.physical.Rect object at 0x0000015A77C6B790>,
'NoName_3': <laygo2.object.physical.Rect object at 0x0000015A77C6B760>,
'NoName_5': <laygo2.object.physical.Rect object at 0x0000015A77C6BA90>}
paths:{}
pins:{}
texts:{}
instances:{
'NoName_1': <laygo2.object.physical.Instance object at 0x0000015A77C6B820>,
'NoName_2': <laygo2.object.physical.Instance object at 0x0000015A77C6B7C0>,
'NoName_4': <laygo2.object.physical.Instance object at 0x0000015A77C6A2F0>}
virtual instances:{}
>>> print(track[-1])
<laygo2.object.physical.Rect object at 0x0000015A77C6BA90>
name: None,
class: Rect,
xy: [[0, 0], [100, 0]],
params: None, , layer: ['M2' 'drawing'], netname: None
.. image:: ../assets/img/object_grid_RoutingGrid_route_via_track.png
:height: 250
See Also
--------
laygo2.object.grid.RoutingGrid.route_via_track
"""
r = grid.route_via_track(mn=mn, track=track, via_tag=via_tag)
self.append(r)
return r
[docs]
def pin(self, name, grid, mn, direction=None, netname=None, params=None):
"""
Create a Pin object over the abstract coordinates specified by mn,
on the specified routing grid.
Parameters
----------
name : str
Pin name.
mn : numpy.ndarray
Abstract coordinates for generating Pin.
direction : str, optional.
Direction.
netname : str, optional.
Net name of Pin.
params : dict, optional
Pin attributes.
Returns
-------
laygo2.physical.Pin: The generated pin object.
Example
-------
>>> import laygo2
>>> from laygo2.object.grid import CircularMapping as CM
>>> from laygo2.object.grid import CircularMappingArray as CMA
>>> from laygo2.object.grid import OneDimGrid, RoutingGrid
>>> from laygo2.object.template import NativeInstanceTemplate
>>> from laygo2.object.database import Design
>>> from laygo2.object.physical import Instance
>>> # Routing grid construction (not needed if laygo2_tech is set up).
>>> gv = OneDimGrid(name="gv", scope=[0, 50], elements=[0])
>>> gh = OneDimGrid(name="gv", scope=[0, 100], elements=[0, 40, 60])
>>> wv = CM([10]) # vertical (xgrid) width
>>> wh = CM([20, 10, 10]) # horizontal (ygrid) width
>>> ev = CM([10]) # vertical (xgrid) extension
>>> eh = CM([10, 10, 10]) # horizontal (ygrid) extension
>>> e0v = CM([15]) # vert. extension (for zero-length wires)
>>> e0h = CM([15, 15, 15]) # hori. extension (for zero-length wires)
>>> lv = CM([['M1', 'drawing']], dtype=object) # layer information
>>> lh = CM([['M2', 'drawing']]*3, dtype=object)
>>> plv = CM([['M1', 'pin']], dtype=object) # pin layers
>>> plh = CM([['M2', 'pin']]*3, dtype=object)
>>> xcolor = CM([None], dtype=object) # Not multipatterned
>>> ycolor = CM([None]*3, dtype=object)
>>> primary_grid = 'horizontal'
>>> tvia = NativeInstanceTemplate(libname='tlib', cellname='via0') # via
>>> viamap = CMA(elements=[[tvia, tvia, tvia]], dtype=object)
>>> g = laygo2.object.grid.RoutingGrid(name='mygrid', vgrid=gv, hgrid=gh,
vwidth=wv, hwidth=wh,
vextension=ev, hextension=eh,
vlayer=lv, hlayer=lh,
pin_vlayer=plv, pin_hlayer=plh,
viamap=viamap, primary_grid=primary_grid,
xcolor=xcolor, ycolor=ycolor,
vextension0=e0v, hextension0=e0h)
>>> # Create a design
>>> dsn = Design(name="mycell", libname="genlib")
>>> ###############
>>> # Place a pin #
>>> ###############
>>> mn = [[0, 0], [10, 10]]
>>> pin = dsn.pin(name="pin", grid=g, mn=mn)
>>> print(pin)
<laygo2.object.physical.Pin object at 0x0000028DABE3AB90>
name: pin,
class: Pin,
xy: [[0, -10], [500, 350]],
params: None, , layer: ['M2' 'pin'], netname: pin, shape: None,
master: None
>>> print(dsn)
<laygo2.object.database.Design object at 0x0000028DABE3A110> name: mycell, params: None
elements: {'pin': <laygo2.object.physical.Pin object at
0x0000028DABE3AB90>}
libname:genlib
rects:{}
paths:{}
pins:{'pin': <laygo2.object.physical.Pin object at 0x0000028DABE3AB90>}
texts:{}
instances:{}
virtual instances:{}
"""
p = grid.pin(name=name, mn=mn, direction=direction, netname=netname, params=params)
self.append(p)
return p
# I/O functions
[docs]
def export_to_template(self, libname=None, cellname=None):
"""
Generate a NativeInstanceTemplate object corresponding to Design object.
Parameters
----------
libname: str
The library name.
cellname: str
The cell name.
Returns
-------
laygo2.NativeInstanceTemplate: The generated template object.
Example
-------
>>> import laygo2
>>> from laygo2.object.database import Design
>>> from laygo2.object.physical import Rect, Pin, Instance, Text
>>> # Create a design
>>> dsn = Design(name="mycell", libname="genlib")
>>> # Create layout objects
>>> r0 = Rect(xy=[[0, 0], [100, 100]], layer=["M1", "drawing"])
>>> p0 = Pin(xy=[[0, 0], [50, 50]], layer=["M1", "pin"], name="P")
>>> i0 = Instance(libname="tlib", cellname="t0", name="I0", xy=[0, 0])
>>> t0 = Text(xy=[[50, 50], [100, 100]], layer=["text", "drawing"], text="T")
>>> dsn.append(r0)
>>> dsn.append(p0)
>>> dsn.append(i0)
>>> dsn.append(t0)
>>> # Export the design to a template.
>>> nt0 = dsn.export_to_template()
>>> print(nt0)
<laygo2.object.template.NativeInstanceTemplate object at XXXX>
name: mycell, class: NativeInstanceTemplate,
bbox: [[0, 0], [0, 0]],
pins: {'P': <laygo2.object.physical.Pin object at YYYY>},
>>> # Save the template into a yaml file.
>>> laygo2.interface.yaml.export_template(nt0, filename='mytemp.yaml')
See Also
--------
laygo2.interface.yaml.export_template : Export a template to
a yaml file.
"""
if libname is None:
libname = self.libname
if cellname is None:
cellname = self.cellname
xy = self.bbox
pins = self.pins
return laygo2.object.NativeInstanceTemplate(libname=libname, cellname=cellname, bbox=xy, pins=pins)
[docs]
def get_matched_rects_by_layer(self, layer):
"""
Return a list containing physical objects matched with the layer input in Design object.
Parameters
----------
layer : list
The layer information. Format is [name, purpose].
Returns
-------
list: The list containing the matched Physical objects.
Example
-------
>>> dsn = laygo2.object.Design(name='dsn', libname="testlib")
>>> rect0 = laygo2.object.Rect(xy=[[0, 0], [100, 100]], layer=[‘M1’, ‘drawing’]……)
>>> pin0 = laygo2.object.Pin(xy=[[0, 0], [100, 100]], layer=[‘M1’, ‘pin’]……)
>>> inst0 = laygo2.object.Instance(name=‘I0’, xy=[100, 100]……)
>>> vinst0_pins[‘in’] = laygo2.object.physical.Pin(xy=[[0, 0], [10, 10]], layer=[‘M1’,’drawing’]……)
>>> vinst0_pins[‘out’] = laygo2.object.physical.Pin(xy=[[90, 90], [100, 100]], layer=[‘M1’, drawing’] ……)
>>> vinst0 = laygo2.object.physical.VirtualInstance(name=‘VI0’, ……)
>>> text0 = laygo2.object.physical.Text(xy=[[ 0, 0], [100,100 ]], layer=[‘text’, ‘drawing’]……)
>>> dsn.append(rect0)
>>> dsn.append(pin0)
>>> dsn.append(inst0)
>>> dsn.append(vinst0)
>>> dsn.append(text0)
>>> print( dsn.get_matchedrects_by_layer( [“M1”, “drawing”] )
[<laygo2.object.physical.Rect object>,
<laygo2.object.physical.Pin object>,
<laygo2.object.physical.Pin object>,
<laygo2.object.physical.Rect object>]
"""
rects = self.rects
insts = self.instances
vinsts = self.virtual_instances
obj_check = []
for rname, rect in rects.items():
if np.array_equal(rect.layer, layer):
obj_check.append(rect)
for iname, inst in insts.items():
for pname, pin in inst.pins.items():
if np.array_equal(pin.layer, layer):
obj_check.append(pin)
for iname, vinst in vinsts.items():
for name, inst in vinst.native_elements.items():
if isinstance(inst, laygo2.object.physical.Rect):
if np.array_equal(inst.layer, layer):
_xy = vinst.get_element_position(inst)
ninst = laygo2.object.physical.Rect(
xy=_xy,
layer=layer,
hextension=inst.hextension,
vextension=inst.vextension,
color=inst.color,
)
obj_check.append(ninst) ## ninst is for sort, inst should be frozen for implement to layout
return obj_check
if __name__ == "__main__":
from laygo2.object.physical import *
# Test
lib = Library(name="mylib")
dsn = Design(name="mycell")
lib.append(dsn)
rect0 = Rect(
xy=[[0, 0], [100, 100]],
layer=["M1", "drawing"],
name="R0",
netname="net0",
params={"maxI": 0.005},
)
dsn.append(rect0)
rect1 = Rect(
xy=[[200, 0], [300, 100]],
layer=["M1", "drawing"],
netname="net0",
params={"maxI": 0.005},
)
dsn.append(rect1)
path0 = Path(
xy=[[0, 0], [0, 100]],
width=10,
extension=5,
layer=["M1", "drawing"],
netname="net0",
params={"maxI": 0.005},
)
dsn.append(path0)
pin0 = Pin(
xy=[[0, 0], [100, 100]],
layer=["M1", "pin"],
netname="n0",
master=rect0,
params={"direction": "input"},
)
dsn.append(pin0)
# text0 = Text(xy=[0, 0], layer=['text', 'drawing'], text='test', params=None)
# dsn.append(text0)
inst0_pins = dict()
inst0_pins["in"] = Pin(xy=[[0, 0], [10, 10]], layer=["M1", "drawing"], netname="in")
inst0_pins["out"] = Pin(xy=[[90, 90], [100, 100]], layer=["M1", "drawing"], netname="out")
inst0 = Instance(
name="I0",
xy=[100, 100],
libname="mylib",
cellname="mycell",
shape=[3, 2],
pitch=[100, 100],
unit_size=[100, 100],
pins=inst0_pins,
transform="R0",
)
dsn.append(inst0)
print(lib)
print(dsn)