Source code for laygo2.object.template.core

#!/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.
#
########################################################################################################################

__author__ = "Jaeduk Han"
__maintainer__ = "Jaeduk Han"
__status__ = "Prototype"

from abc import *
import numpy as np
import laygo2.object


[docs] class Template(metaclass=ABCMeta): """ The base class that defines the functions and attributes of the template. """ name = None """str: Template name."""
[docs] def __init__(self, name=None): """ The constructor function. Parameters ---------- name : str or None, optional. The name of this template. """ self.name = name
def __str__(self): """Return a string representation of this template's information. """ return self.summarize()
[docs] def summarize(self): """Return the summary of the template information.""" return ( self.__repr__() + " " "name: " + self.name + ", " + "class: " + self.__class__.__name__ + ", " + "" )
[docs] def height(self, params=None): """int: Return the height of the template.""" return abs(self.bbox(params=params)[0, 1] - self.bbox(params=params)[1, 1])
[docs] def width(self, params=None): """int: Return the width of the template.""" return abs(self.bbox(params=params)[0, 0] - self.bbox(params=params)[1, 0])
[docs] def size(self, params=None): """int: Return the size of the template.""" return np.array([self.width(params=params), self.height(params=params)])
[docs] @abstractmethod def bbox(self, params=None): """numpy.ndarray: (Abstract method) the physical bounding box of the template.""" pass
[docs] @abstractmethod def pins(self, params=None): """dict: (Abstract method) Dictionary storing the pins of the template.""" pass
[docs] @abstractmethod def generate(self, name=None, shape=None, pitch=None, transform="R0", netmap=None, params=None): """instance: (Abstract method) Generate an instance from the template.""" pass
[docs] class NativeInstanceTemplate(Template): """ NativeInstanceTemplate class implements the template that generate Instance. """ libname = None """str: Library name. Example ------- >>> from laygo2.object.physical import Pin >>> from laygo2.object.template import NativeInstanceTemplate >>> p = dict() >>> p['i'] = Pin(xy=[[0, 0], [10, 10]], layer=['M1', 'drawing'], netname='i') >>> p['o'] = Pin(xy=[[90, 90], [100, 100]], layer=['M1', 'drawing'], netname='o') >>> nt = NativeInstanceTemplate(libname='mylib', cellname='mytemp', bbox=[[0, 0], [100, 100]], pins=p) >>> nt.libname 'mylib' .. image:: ../assets/img/object_template_NativeInstanceTemplate_libname.png :height: 250 """ cellname = None """str: Cell name. Example ------- >>> from laygo2.object.physical import Pin >>> from laygo2.object.template import NativeInstanceTemplate >>> p = dict() >>> p['i'] = Pin(xy=[[0, 0], [10, 10]], layer=['M1', 'drawing'], netname='i') >>> p['o'] = Pin(xy=[[90, 90], [100, 100]], layer=['M1', 'drawing'], netname='o') >>> nt = NativeInstanceTemplate(libname='mylib', cellname='mytemp', bbox=[[0, 0], [100, 100]], pins=p) >>> nt.cellname 'mytemp' .. image:: ../assets/img/object_template_NativeInstanceTemplate_cellname.png :height: 250 """ _bbox = np.array([[0, 0], [0, 0]]) _pins = None
[docs] def __init__(self, libname, cellname, bbox=np.array([[0, 0], [0, 0]]), pins=None): """ Constructor function. Parameters ---------- libname : str Library name. cellname : str Cell name. bbox : numpy.ndarray Bounding box of the object. pins : dict Dictionary storing the template's pin objects. Returns ------- NativeInstanceTemplate Example ------- >>> from laygo2.object.physical import Pin >>> from laygo2.object.template import NativeInstanceTemplate >>> p = dict() >>> p['i'] = Pin(xy=[[0, 0], [10, 10]], layer=['M1', 'drawing'], netname='i') >>> p['o'] = Pin(xy=[[90, 90], [100, 100]], layer=['M1', 'drawing'], netname='o') >>> nt = NativeInstanceTemplate(libname='mylib', cellname='mytemp', bbox=[[0, 0], [100, 100]], pins=p) <laygo2.object.template.NativeInstanceTemplate object> >>> print(nt) <laygo2.object.template.NativeInstanceTemplate object at 0x0000013C01..> name: mytemp, class: NativeInstanceTemplate, bbox: [[0, 0], [100, 100]], pins: {'i': <laygo2.object.physical.Pin object at 0x0000013C01CEFDC0>, 'o': <laygo2.object.physical.Pin object at 0x0000013C01C30BE0>}, .. image:: ../assets/img/object_template_NativeInstanceTemplate_init.png :height: 250 """ self.libname = libname self.cellname = cellname self._bbox = None if bbox is None else np.asarray(bbox) self._pins = pins Template.__init__(self, name=cellname)
[docs] def summarize(self): """Return the summary of the object information.""" return ( self.__repr__() + " " "name: " + self.name + ", " + "class: " + self.__class__.__name__ + ", " + "bbox: " + str(self.bbox().tolist()) + ", " + "pins: " + str(self.pins()) + ", " + "" )
# Core template functions
[docs] def bbox(self, params=None): """ Bounding box of the object. Parameters ---------- None Returns ------- numpy.ndarray Example ------- >>> from laygo2.object.physical import Pin >>> from laygo2.object.template import NativeInstanceTemplate >>> p = dict() >>> p['i'] = Pin(xy=[[0, 0], [10, 10]], layer=['M1', 'drawing'], netname='i') >>> p['o'] = Pin(xy=[[90, 90], [100, 100]], layer=['M1', 'drawing'], netname='o') >>> nt = NativeInstanceTemplate(libname='mylib', cellname='mytemp', bbox=[[0, 0], [100, 100]], pins=p) >>> nt.bbox() array([[ 0, 0], [100, 100]]) .. image:: ../assets/img/object_template_NativeInstanceTemplate_bbox.png :height: 250 """ return self._bbox
[docs] def pins(self, params=None): """ Dictionary storing pins of the object. Parameters ---------- None Returns ------- dict : Dictionary storing pin objects. Example ------- >>> from laygo2.object.physical import Pin >>> from laygo2.object.template import NativeInstanceTemplate >>> p = dict() >>> p['i'] = Pin(xy=[[0, 0], [10, 10]], layer=['M1', 'drawing'], netname='i') >>> p['o'] = Pin(xy=[[90, 90], [100, 100]], layer=['M1', 'drawing'], netname='o') >>> nt = NativeInstanceTemplate(libname='mylib', cellname='mytemp', bbox=[[0, 0], [100, 100]], pins=p) >>> nt.pins() >>> {'i': <laygo2.object.physical.Pin object at 0x000002578C762500>, 'o': <laygo2.object.physical.Pin object at 0x00000257FBA87C40>} >>> print(nt.pins()['i']) <laygo2.object.physical.Pin object at 0x000002578C762500> name: None, class: Pin, xy: [[0, 0], [10, 10]], params: None, layer: ['M1' 'drawing'], netname: i, shape: None, master: None .. image:: ../assets/img/object_template_ParameterizedInstanceTemplate_pins.png :height: 250 """ return self._pins
[docs] def generate(self, name=None, shape=None, pitch=None, transform="R0", netmap=None, params=None): """ Generate Instance object. Parameters ---------- name : str Name of the instance to be generated. shape : numpy.ndarray, optional. Shape of the object to be generated. pitch : numpy.ndarray, optional. Element pitch of the array object to be generated. transform : str Transformation attribute of the object to be generated. netmap : dict, optional. Dictionary storing net-pin conversion mappings. params : dict, optional. Dictionary storing the parameters associated with the object. Returns ------- (laygo2.object.physical.Instance) generated Instance object See Also -------- Class Instance Example ------- >>> from laygo2.object.physical import Pin >>> from laygo2.object.template import NativeInstanceTemplate >>> p = dict() >>> p['i'] = Pin(xy=[[0, 0], [10, 10]], layer=['M1', 'drawing'], netname='i') >>> p['o'] = Pin(xy=[[90, 90], [100, 100]], layer=['M1', 'drawing'], netname='o') >>> nt = NativeInstanceTemplate(libname='mylib', cellname='mytemp', bbox=[[0, 0], [100, 100]], pins=p) >>> i0 = nt.generate(name="I0") >>> i1 = nt.generate(name="I1") >>> print(i0) <laygo2.object.physical.Instance object at 0x000002C3F717F850> name: I0, class: Instance, xy: [0, 0], params: None, size: [100, 100], shape: None, pitch: [100, 100], transform: R0, pins: {'i': <laygo2.object.physical.Pin object at 0x000002C3F717F820>, 'o': <laygo2.object.physical.Pin object at 0x000002C3F717FD90>}, >>> print(i1) <laygo2.object.physical.Instance object at 0x000002C3FF91C100> name: I1, class: Instance, xy: [0, 0], params: None, size: [100, 100], shape: None, pitch: [100, 100], transform: R0, pins: {'i': <laygo2.object.physical.Pin object at 0x000002C3FF91C0A0>, 'o': <laygo2.object.physical.Pin object at 0x000002C3FF91C070>}, .. image:: ../assets/img/object_template_ParameterizedInstanceTemplate_generate.png :height: 250 """ inst = laygo2.object.physical.Instance( libname=self.libname, cellname=self.cellname, xy=np.array([0, 0]), shape=shape, pitch=pitch, unit_size=self.size(params), pins=self.pins(params), transform=transform, name=name, params=params, ) # update netnames if netmap is provided. if netmap is not None: inst.update_netname(netmap=netmap) return inst
# I/O functions
[docs] def export_to_dict(self): """ Return a dictionary containing the template information. Parameters ---------- None Returns ------- dict See Also -------- Class Instance Example ------- >>> from laygo2.object.physical import Pin >>> from laygo2.object.template import NativeInstanceTemplate >>> p = dict() >>> p['i'] = Pin(xy=[[0, 0], [10, 10]], layer=['M1', 'drawing'], netname='i') >>> p['o'] = Pin(xy=[[90, 90], [100, 100]], layer=['M1', 'drawing'], netname='o') >>> nt = NativeInstanceTemplate(libname='mylib', cellname='mytemp', bbox=[[0, 0], [100, 100]], pins=p) >>> nt.export_to_dict() {'libname': 'mylib', 'cellname': 'mytemp', 'bbox': [[0, 0], [100, 100]], 'pins': {'i': {'xy': [[0, 0], [10, 10]], 'layer': ['M1', 'drawing'], 'name': None, 'netname': 'i'}, 'o': {'xy': [[90, 90], [100, 100]], 'layer': ['M1', 'drawing'], 'name': None, 'netname': 'o'} } } .. image:: ../assets/img/object_template_NativeInstanceTemplate_export_to_dict.png :height: 250 """ db = dict() db["libname"] = self.libname db["cellname"] = self.cellname db["bbox"] = self.bbox().tolist() db["pins"] = dict() for pn, p in self.pins().items(): db["pins"][pn] = p.export_to_dict() return db
[docs] class ParameterizedInstanceTemplate(Template): """ The ParameterizedInstanceTemplate class implements a template for generating instances with varying size (bounding box) and pin configurations based on input parameters, such as instances mapped to Cadence Virtuoso's pcells or Pycells. """ libname = None """str: The libname of the instance to be generated.""" cellname = None """str: The cellname of the instance to be generated.""" _bbox = None _pins = None
[docs] def __init__(self, libname, cellname, bbox_func=None, pins_func=None): """ Constructor of ParameterizedInstanceTemplate class. Parameters ---------- libname : str The library name. cellname : str The cell name of the template. bbox_func : callable The function that computes the bounding box of the template from its input parameters. pins_func : callable The function that returns a dictionary that contains its pin objects for its input parameters. Returns ------- laygo2.object.template.ParameterizedInstanceTemplate Example ------- >>> import numpy as np >>> from laygo2.object.template import ParameterizedInstanceTemplate >>> from laygo2.object.physical import Pin >>> # bbox computation function. >>> def pcell_bbox_func(params): return np.array([[0, 0], [100 * params["mult"], 100]]) >>> # pin generation function. >>> def pcell_pins_func(params): >>> template_pins = dict() >>> for i in range(params["mult"]): >>> template_pins["in" + str(i)] = Pin( >>> xy=[[i * 100 + 0, 0], [i * 100 + 10, 10]], >>> layer=["M1", "drawing"], >>> netname="in" + str(i), >>> ) >>> template_pins["out" + str(i)] = Pin( >>> xy=[[i * 100 + 90, 90], [i * 100 + 90, 100]], >>> layer=["M1", "drawing"], >>> netname="out" + str(i), >>> ) >>> return template_pins >>> # Create a template >>> pcell_temp = ParameterizedInstanceTemplate( >>> libname="mylib", >>> cellname="mypcelltemplate", >>> bbox_func=pcell_bbox_func, >>> pins_func=pcell_pins_func, >>> ) >>> # Generate an instance for input parameters. >>> pcell_inst_params = {"mult": 4} >>> pcell_inst = pcell_temp.generate( >>> name="mypcellinst", >>> transform="R0", >>> params=pcell_inst_params, >>> ) >>> # display >>> print(pcell_temp) <laygo2.object.template.ParameterizedInstanceTemplate object at 0x000001B1BA91D9C0> name: mypcelltemplate, class: ParameterizedInstanceTemplate, >>> print(pcell_inst) xy: [0, 0], params: {'mult': 4}, size: [400, 100], shape: None, pitch: [400, 100], transform: R0, pins: {'in0': <laygo2.object.physical.Pin object at 0x000001B1BA91FCA0>, 'out0': <laygo2.object.physical.Pin object at 0x000001B1BA91FC70>, 'in1': <laygo2.object.physical.Pin object at 0x000001B1BA91FC10>, 'out1': <laygo2.object.physical.Pin object at 0x000001B1BA91E8C0>, 'in2': <laygo2.object.physical.Pin object at 0x000001B1BA91E890>, 'out2': <laygo2.object.physical.Pin object at 0x000001B1BA91FBE0>, 'in3': <laygo2.object.physical.Pin object at 0x000001B1BA91E7D0>, 'out3': <laygo2.object.physical.Pin object at 0x000001B1BA91E710>}, .. image:: ../assets/img/object_template_ParameterizedInstanceTemplate_init.png :height: 250 """ self.libname = libname self.cellname = cellname self._bbox = bbox_func self._pins = pins_func Template.__init__(self, name=cellname)
# Core template functions
[docs] def bbox(self, params=None): """ Bounding box of the template object. Parameters ---------- params: dict A dictionary that contains input parameters corresponding to the bounding box to be computed. Returns ------- numpy.ndarray: A 2x2 numpy array that contains the bounding box coordinates corresponding to the input parameters. Example ------- >>> import numpy as np >>> from laygo2.object.template import ParameterizedInstanceTemplate >>> from laygo2.object.physical import Pin >>> # bbox computation function. >>> def pcell_bbox_func(params): return np.array([[0, 0], [100 * params["mult"], 100]]) >>> # pin generation function. >>> def pcell_pins_func(params): >>> template_pins = dict() >>> for i in range(params["mult"]): >>> template_pins["in" + str(i)] = Pin( >>> xy=[[i * 100 + 0, 0], [i * 100 + 10, 10]], >>> layer=["M1", "drawing"], >>> netname="in" + str(i), >>> ) >>> template_pins["out" + str(i)] = Pin( >>> xy=[[i * 100 + 90, 90], [i * 100 + 90, 100]], >>> layer=["M1", "drawing"], >>> netname="out" + str(i), >>> ) >>> return template_pins >>> # Create a template >>> pcell_temp = ParameterizedInstanceTemplate( >>> libname="mylib", >>> cellname="mypcelltemplate", >>> bbox_func=pcell_bbox_func, >>> pins_func=pcell_pins_func, >>> ) >>> # Compute bbox for input parameters >>> pcell_inst_params = {"mult": 4} >>> pcell_temp.bbox(params=pcell_inst_params) array([[ 0, 0], [400, 100]]) .. image:: ../assets/img/object_template_ParameterizedInstanceTemplate_bbox.png :height: 250 """ return self._bbox(params=params)
[docs] def pins(self, params=None): """ Return pin dictionary of ParameterizedInstanceTemplate object. Parameters ---------- params: dict A dictionary that contains input parameters corresponding to the pin objects to be produced. Returns ------- dict: A dictionary that contains pin object corresponding to the input parameters. Example ------- >>> import numpy as np >>> from laygo2.object.template import ParameterizedInstanceTemplate >>> from laygo2.object.physical import Pin >>> # bbox computation function. >>> def pcell_bbox_func(params): return np.array([[0, 0], [100 * params["mult"], 100]]) >>> # pin generation function. >>> def pcell_pins_func(params): >>> template_pins = dict() >>> for i in range(params["mult"]): >>> template_pins["in" + str(i)] = Pin( >>> xy=[[i * 100 + 0, 0], [i * 100 + 10, 10]], >>> layer=["M1", "drawing"], >>> netname="in" + str(i), >>> ) >>> template_pins["out" + str(i)] = Pin( >>> xy=[[i * 100 + 90, 90], [i * 100 + 90, 100]], >>> layer=["M1", "drawing"], >>> netname="out" + str(i), >>> ) >>> return template_pins >>> # Create a template >>> pcell_temp = ParameterizedInstanceTemplate( >>> libname="mylib", >>> cellname="mypcelltemplate", >>> bbox_func=pcell_bbox_func, >>> pins_func=pcell_pins_func, >>> ) >>> # Compute bbox for input parameters >>> pcell_inst_params = {"mult": 4} >>> pcell_temp.pins(params=pcell_inst_params) {'in0': <laygo2.object.physical.Pin object at 0x000001B1BA91F7C0>, 'out0': <laygo2.object.physical.Pin object at 0x000001B1BA91E830>, 'in1': <laygo2.object.physical.Pin object at 0x000001B1BA91DAB0>, 'out1': <laygo2.object.physical.Pin object at 0x000001B1BA91E860>, 'in2': <laygo2.object.physical.Pin object at 0x000001B1BA91E560>, 'out2': <laygo2.object.physical.Pin object at 0x000001B1BA91E800>, 'in3': <laygo2.object.physical.Pin object at 0x000001B1BA91E770>, 'out3': <laygo2.object.physical.Pin object at 0x000001B1BA91EA40>} .. image:: ../assets/img/object_template_ParameterizedInstanceTemplate_pins.png :height: 250 """ return self._pins(params=params)
[docs] def generate(self, name=None, shape=None, pitch=None, transform="R0", netmap=None, params=None): """ Generate an Instance object corresponding to the template and its input parameters. Parameters ---------- name : str name of the instance to be generated. shape : numpy.ndarray, optional. shape of the object to be generated. pitch : numpy.ndarray, optional. pitch of the object to be generated. transform : str, optional. transformation attribute of the entity to be generated. netmap : dict, optional. dictionary containing netmap conversion information of pins. params : dict, optional. dictionary having the entity attributes. Returns ------- laygo2.object.physical.Instance: The generated Instance object Example ------- >>> import numpy as np >>> from laygo2.object.template import ParameterizedInstanceTemplate >>> from laygo2.object.physical import Pin >>> # bbox computation function. >>> def pcell_bbox_func(params): return np.array([[0, 0], [100 * params["mult"], 100]]) >>> # pin generation function. >>> def pcell_pins_func(params): >>> template_pins = dict() >>> for i in range(params["mult"]): >>> template_pins["in" + str(i)] = Pin( >>> xy=[[i * 100 + 0, 0], [i * 100 + 10, 10]], >>> layer=["M1", "drawing"], >>> netname="in" + str(i), >>> ) >>> template_pins["out" + str(i)] = Pin( >>> xy=[[i * 100 + 90, 90], [i * 100 + 90, 100]], >>> layer=["M1", "drawing"], >>> netname="out" + str(i), >>> ) >>> return template_pins >>> # Create a template >>> pcell_temp = ParameterizedInstanceTemplate( >>> libname="mylib", >>> cellname="mypcelltemplate", >>> bbox_func=pcell_bbox_func, >>> pins_func=pcell_pins_func, >>> ) >>> # Generate an instance for input parameters. >>> pcell_inst_params = {"mult": 4} >>> pcell_inst = pcell_temp.generate( >>> name="mypcellinst", >>> transform="R0", >>> params=pcell_inst_params, >>> ) >>> # display >>> print(pcell_temp) <laygo2.object.template.ParameterizedInstanceTemplate object at 0x000001B1BA91D9C0> name: mypcelltemplate, class: ParameterizedInstanceTemplate, >>> print(pcell_inst) xy: [0, 0], params: {'mult': 4}, size: [400, 100], shape: None, pitch: [400, 100], transform: R0, pins: {'in0': <laygo2.object.physical.Pin object at 0x000001B1BA91FCA0>, 'out0': <laygo2.object.physical.Pin object at 0x000001B1BA91FC70>, 'in1': <laygo2.object.physical.Pin object at 0x000001B1BA91FC10>, 'out1': <laygo2.object.physical.Pin object at 0x000001B1BA91E8C0>, 'in2': <laygo2.object.physical.Pin object at 0x000001B1BA91E890>, 'out2': <laygo2.object.physical.Pin object at 0x000001B1BA91FBE0>, 'in3': <laygo2.object.physical.Pin object at 0x000001B1BA91E7D0>, 'out3': <laygo2.object.physical.Pin object at 0x000001B1BA91E710>}, .. image:: ../assets/img/object_template_ParameterizedInstanceTemplate_generate.png :height: 250 """ # xy = xy + np.dot(self.xy(params)[0], tf.Mt(transform).T) inst = laygo2.object.physical.Instance( libname=self.libname, cellname=self.cellname, xy=np.array([0, 0]), shape=shape, pitch=pitch, unit_size=self.size(params), pins=self.pins(params), transform=transform, name=name, params=params, ) # update netnames if netmap is provided. if netmap is not None: inst.update_netname(netmap=netmap) return inst
[docs] class UserDefinedTemplate(Template): """ UserDefinedTemplate class implements the template that generates a VirtualInstance object corresponding to the template and input parameters. """ _bbox = None """The internal pointer to the bbox computing function.""" _pins = None """The internal pointer to the pin creation function.""" _generate = None """The internal pointer to the instance generation function."""
[docs] def __init__(self, bbox_func, pins_func, generate_func, name=None): """ Constructor function of UserDefinedTemplate class. Parameters ---------- bbox_func: callable The function that computes the bounding box of the template from its input parameters. pins_func: callable The function that returns a dictionary that contains its pin objects for its input parameters. generate_func: callable The function that returns a generated VirtualInstance object for its input parameters. name : str The name of the template. Returns ------- laygo2.object.template.UserDefinedTemplate Example ------- >>> import numpy as np >>> from laygo2.object.template import UserDefinedTemplate >>> from laygo2.object.physical import Pin, Rect, VirtualInstance >>> # bbox computation function. >>> def user_bbox_func(params): >>> return np.array([[0, 0], [100 * params["mult"], 100]]) >>> # pin generation function. >>> def user_pins_func(params): >>> template_pins = dict() >>> for i in range(params["mult"]): >>> template_pins["in" + str(i)] = Pin( >>> xy=[[i * 100 + 0, 0], [i * 100 + 10, 10]], >>> layer=["M1", "drawing"], >>> netname="in" + str(i), >>> ) >>> template_pins["out" + str(i)] = Pin( >>> xy=[[i * 100 + 90, 90], [i * 100 + 90, 100]], >>> layer=["M1", "drawing"], >>> netname="out" + str(i), >>> ) >>> return template_pins >>> # instance generation function. >>> def user_generate_func( >>> name=None, shape=None, pitch=np.array([0, 0]), transform="R0", >>> params=None): >>> m = params["mult"] >>> shape = np.array([1, 1]) if shape is None else np.asarray(shape) >>> inst_pins = user_pins_func(params) >>> inst_native_elements = dict() >>> for i in range(m): >>> ofst = i * 100 >>> inst_native_elements["R0_" + str(i)] = Rect( >>> xy=[[ofst, 0], [ofst + 10, 10]], layer=["M1", "drawing"] >>> ) >>> inst_native_elements["R1_" + str(i)] = Rect( >>> xy=[[ofst + 90, 90], [ofst + 100, 100]], layer=["M1", "drawing"] >>> ) >>> inst_native_elements["R2"] = Rect( >>> xy=[[0, 0], [m * 100, 100]], layer=["prBoundary", "drawing"] >>> ) >>> inst = VirtualInstance( >>> name=name, >>> libname="mylib", >>> cellname="myvinst", >>> xy=np.array([0, 0]), >>> native_elements=inst_native_elements, >>> shape=shape, >>> pitch=pitch, >>> unit_size=[m * 100, 100], >>> pins=inst_pins, >>> transform=transform, >>> params=params, >>> ) >>> return inst >>> # UserDefinedTemplate construction. >>> user_temp = UserDefinedTemplate( >>> name="myusertemplate", >>> bbox_func=user_bbox_func, >>> pins_func=user_pins_func, >>> generate_func=user_generate_func, >>> ) >>> # VirtualInstance generation. >>> user_inst = user_temp.generate(name="myinst", params={"mult": 5}) >>> # Display >>> print(user_temp) <laygo2.object.template.UserDefinedTemplate object at 0x00000192BF990130> name: myusertemplate, class: UserDefinedTemplate, >>> print(user_inst) <laygo2.object.physical.VirtualInstance object at 0x00000192BF990280> name: myinst, class: VirtualInstance, xy: [0, 0], params: {'mult': 5}, size: [500, 100], shape: [1, 1], pitch: [500, 100], transform: R0, pins: {'in0': <laygo2.object.physical.Pin object at 0x00000192BF9930D0>, 'out0': <laygo2.object.physical.Pin object at 0x00000192BF9931C0>, 'in1': <laygo2.object.physical.Pin object at 0x00000192BF993760>, 'out1': <laygo2.object.physical.Pin object at 0x00000192BF9936A0>, 'in2': <laygo2.object.physical.Pin object at 0x00000192BF993610>, 'out2': <laygo2.object.physical.Pin object at 0x00000192BF9935B0>, 'in3': <laygo2.object.physical.Pin object at 0x00000192BF9932E0>, 'out3': <laygo2.object.physical.Pin object at 0x00000192BF9931F0>, 'in4': <laygo2.object.physical.Pin object at 0x00000192BF993130>, 'out4': <laygo2.object.physical.Pin object at 0x00000192BF9930A0>}, native elements: {'R0_0': <laygo2.object.physical.Rect object at 0x0...>, 'R1_0': <laygo2.object.physical.Rect object at 0x0...>, 'R0_1': <laygo2.object.physical.Rect object at 0x0...>, 'R1_1': <laygo2.object.physical.Rect object at 0x0...>, 'R0_2': <laygo2.object.physical.Rect object at 0x0...>, 'R1_2': <laygo2.object.physical.Rect object at 0x0...>, 'R0_3': <laygo2.object.physical.Rect object at 0x0...>, 'R1_3': <laygo2.object.physical.Rect object at 0x0...>, 'R0_4': <laygo2.object.physical.Rect object at 0x0...>, 'R1_4': <laygo2.object.physical.Rect object at 0x0...>, 'R2': <laygo2.object.physical.Rect object at 0x000...>} >>> print(user_inst.bbox) [[ 0 0] [500 100]] .. image:: ../assets/img/object_template_UserDefinedTemplate_init.png :height: 250 """ self._bbox = bbox_func self._pins = pins_func self._generate = generate_func Template.__init__(self, name=name)
# Core template functions
[docs] def bbox(self, params=None): """ Return bbox of UserDefinedTemplate object. Parameters ---------- params: dict A dictionary that contains input parameters corresponding to the bounding box to be computed. Returns ------- numpy.ndarray: A 2x2 numpy array that contains the bounding box coordinates corresponding to the input parameters. Example ------- >>> import numpy as np >>> from laygo2.object.template import UserDefinedTemplate >>> from laygo2.object.physical import Pin, Rect, VirtualInstance >>> # bbox computation function. >>> def user_bbox_func(params): >>> return np.array([[0, 0], [100 * params["mult"], 100]]) >>> # pin generation function. >>> def user_pins_func(params): >>> template_pins = dict() >>> for i in range(params["mult"]): >>> template_pins["in" + str(i)] = Pin( >>> xy=[[i * 100 + 0, 0], [i * 100 + 10, 10]], >>> layer=["M1", "drawing"], >>> netname="in" + str(i), >>> ) >>> template_pins["out" + str(i)] = Pin( >>> xy=[[i * 100 + 90, 90], [i * 100 + 90, 100]], >>> layer=["M1", "drawing"], >>> netname="out" + str(i), >>> ) >>> return template_pins >>> # instance generation function. >>> def user_generate_func( >>> name=None, shape=None, pitch=np.array([0, 0]), transform="R0", >>> params=None): >>> m = params["mult"] >>> shape = np.array([1, 1]) if shape is None else np.asarray(shape) >>> inst_pins = user_pins_func(params) >>> inst_native_elements = dict() >>> for i in range(m): >>> ofst = i * 100 >>> inst_native_elements["R0_" + str(i)] = Rect( >>> xy=[[ofst, 0], [ofst + 10, 10]], layer=["M1", "drawing"] >>> ) >>> inst_native_elements["R1_" + str(i)] = Rect( >>> xy=[[ofst + 90, 90], [ofst + 100, 100]], layer=["M1", "drawing"] >>> ) >>> inst_native_elements["R2"] = Rect( >>> xy=[[0, 0], [m * 100, 100]], layer=["prBoundary", "drawing"] >>> ) >>> inst = VirtualInstance( >>> name=name, >>> libname="mylib", >>> cellname="myvinst", >>> xy=np.array([0, 0]), >>> native_elements=inst_native_elements, >>> shape=shape, >>> pitch=pitch, >>> unit_size=[m * 100, 100], >>> pins=inst_pins, >>> transform=transform, >>> params=params, >>> ) >>> return inst >>> # UserDefinedTemplate construction. >>> user_temp = UserDefinedTemplate( >>> name="myusertemplate", >>> bbox_func=user_bbox_func, >>> pins_func=user_pins_func, >>> generate_func=user_generate_func, >>> ) >>> user_temp.bbox(params={"mult": 5}) array([[ 0, 0], [500, 100]]) .. image:: ../assets/img/object_template_UserDefinedTemplate_bbox.png :height: 250 """ return self._bbox(params=params)
[docs] def pins(self, params=None): """ Pins of UserDefinedTemplate object. Parameters ---------- params: dict A dictionary that contains input parameters corresponding to the pin objects to be produced. Returns ------- dict: A dictionary that contains pin object corresponding to the input parameters. Example ------- >>> import numpy as np >>> from laygo2.object.template import UserDefinedTemplate >>> from laygo2.object.physical import Pin, Rect, VirtualInstance >>> # bbox computation function. >>> def user_bbox_func(params): >>> return np.array([[0, 0], [100 * params["mult"], 100]]) >>> # pin generation function. >>> def user_pins_func(params): >>> template_pins = dict() >>> for i in range(params["mult"]): >>> template_pins["in" + str(i)] = Pin( >>> xy=[[i * 100 + 0, 0], [i * 100 + 10, 10]], >>> layer=["M1", "drawing"], >>> netname="in" + str(i), >>> ) >>> template_pins["out" + str(i)] = Pin( >>> xy=[[i * 100 + 90, 90], [i * 100 + 90, 100]], >>> layer=["M1", "drawing"], >>> netname="out" + str(i), >>> ) >>> return template_pins >>> # instance generation function. >>> def user_generate_func( >>> name=None, shape=None, pitch=np.array([0, 0]), transform="R0", >>> params=None): >>> m = params["mult"] >>> shape = np.array([1, 1]) if shape is None else np.asarray(shape) >>> inst_pins = user_pins_func(params) >>> inst_native_elements = dict() >>> for i in range(m): >>> ofst = i * 100 >>> inst_native_elements["R0_" + str(i)] = Rect( >>> xy=[[ofst, 0], [ofst + 10, 10]], layer=["M1", "drawing"] >>> ) >>> inst_native_elements["R1_" + str(i)] = Rect( >>> xy=[[ofst + 90, 90], [ofst + 100, 100]], layer=["M1", "drawing"] >>> ) >>> inst_native_elements["R2"] = Rect( >>> xy=[[0, 0], [m * 100, 100]], layer=["prBoundary", "drawing"] >>> ) >>> inst = VirtualInstance( >>> name=name, >>> libname="mylib", >>> cellname="myvinst", >>> xy=np.array([0, 0]), >>> native_elements=inst_native_elements, >>> shape=shape, >>> pitch=pitch, >>> unit_size=[m * 100, 100], >>> pins=inst_pins, >>> transform=transform, >>> params=params, >>> ) >>> return inst >>> # UserDefinedTemplate construction. >>> user_temp = UserDefinedTemplate( >>> name="myusertemplate", >>> bbox_func=user_bbox_func, >>> pins_func=user_pins_func, >>> generate_func=user_generate_func, >>> ) >>> user_temp.pins(params={"mult": 5}) {'in0': <laygo2.object.physical.Pin object at 0x00000192BF990670>, 'out0': <laygo2.object.physical.Pin object at 0x00000192BF990400>, 'in1': <laygo2.object.physical.Pin object at 0x00000192BF993250>, 'out1': <laygo2.object.physical.Pin object at 0x00000192BF9903D0>, 'in2': <laygo2.object.physical.Pin object at 0x00000192BF9901F0>, 'out2': <laygo2.object.physical.Pin object at 0x00000192BF9904F0>, 'in3': <laygo2.object.physical.Pin object at 0x00000192BF993640>, 'out3': <laygo2.object.physical.Pin object at 0x00000192BF990520>, 'in4': <laygo2.object.physical.Pin object at 0x00000192BF9936D0>, 'out4': <laygo2.object.physical.Pin object at 0x00000192BF993790>} .. image:: ../assets/img/object_template_UserDefinedTemplate_pins.png :height: 250 """ return self._pins(params=params)
[docs] def generate(self, name=None, shape=None, pitch=None, transform="R0", netmap=None, params=None): """ Generate a VirtualInstance object by calling generate_func() bound to the template. Parameters ---------- name : str name of the instance to be generated. shape : numpy.ndarray, optional. shape of the object to be generated. pitch : numpy.ndarray, optional. pitch of the object to be generated. transform : str, optional. transformation attribute of the entity to be generated. netmap : dict, optional. dictionary containing netmap conversion information of pins. params : dict, optional. dictionary having the entity attributes. Returns ------- laygo2.object.physical.VirtualInstance: The generated VirtualInstance object. Example ------- >>> import numpy as np >>> from laygo2.object.template import UserDefinedTemplate >>> from laygo2.object.physical import Pin, Rect, VirtualInstance >>> # bbox computation function. >>> def user_bbox_func(params): >>> return np.array([[0, 0], [100 * params["mult"], 100]]) >>> # pin generation function. >>> def user_pins_func(params): >>> template_pins = dict() >>> for i in range(params["mult"]): >>> template_pins["in" + str(i)] = Pin( >>> xy=[[i * 100 + 0, 0], [i * 100 + 10, 10]], >>> layer=["M1", "drawing"], >>> netname="in" + str(i), >>> ) >>> template_pins["out" + str(i)] = Pin( >>> xy=[[i * 100 + 90, 90], [i * 100 + 90, 100]], >>> layer=["M1", "drawing"], >>> netname="out" + str(i), >>> ) >>> return template_pins >>> # instance generation function. >>> def user_generate_func( >>> name=None, shape=None, pitch=np.array([0, 0]), transform="R0", >>> params=None): >>> m = params["mult"] >>> shape = np.array([1, 1]) if shape is None else np.asarray(shape) >>> inst_pins = user_pins_func(params) >>> inst_native_elements = dict() >>> for i in range(m): >>> ofst = i * 100 >>> inst_native_elements["R0_" + str(i)] = Rect( >>> xy=[[ofst, 0], [ofst + 10, 10]], layer=["M1", "drawing"] >>> ) >>> inst_native_elements["R1_" + str(i)] = Rect( >>> xy=[[ofst + 90, 90], [ofst + 100, 100]], layer=["M1", "drawing"] >>> ) >>> inst_native_elements["R2"] = Rect( >>> xy=[[0, 0], [m * 100, 100]], layer=["prBoundary", "drawing"] >>> ) >>> inst = VirtualInstance( >>> name=name, >>> libname="mylib", >>> cellname="myvinst", >>> xy=np.array([0, 0]), >>> native_elements=inst_native_elements, >>> shape=shape, >>> pitch=pitch, >>> unit_size=[m * 100, 100], >>> pins=inst_pins, >>> transform=transform, >>> params=params, >>> ) >>> return inst >>> # UserDefinedTemplate construction. >>> user_temp = UserDefinedTemplate( >>> name="myusertemplate", >>> bbox_func=user_bbox_func, >>> pins_func=user_pins_func, >>> generate_func=user_generate_func, >>> ) >>> # VirtualInstance generation. >>> user_inst = user_temp.generate(name="myinst", params={"mult": 5}) >>> # Display >>> print(user_temp) <laygo2.object.template.UserDefinedTemplate object at 0x00000192BF990130> name: myusertemplate, class: UserDefinedTemplate, >>> print(user_inst) <laygo2.object.physical.VirtualInstance object at 0x00000192BF990280> name: myinst, class: VirtualInstance, xy: [0, 0], params: {'mult': 5}, size: [500, 100], shape: [1, 1], pitch: [500, 100], transform: R0, pins: {'in0': <laygo2.object.physical.Pin object at 0x00000192BF9930D0>, 'out0': <laygo2.object.physical.Pin object at 0x00000192BF9931C0>, 'in1': <laygo2.object.physical.Pin object at 0x00000192BF993760>, 'out1': <laygo2.object.physical.Pin object at 0x00000192BF9936A0>, 'in2': <laygo2.object.physical.Pin object at 0x00000192BF993610>, 'out2': <laygo2.object.physical.Pin object at 0x00000192BF9935B0>, 'in3': <laygo2.object.physical.Pin object at 0x00000192BF9932E0>, 'out3': <laygo2.object.physical.Pin object at 0x00000192BF9931F0>, 'in4': <laygo2.object.physical.Pin object at 0x00000192BF993130>, 'out4': <laygo2.object.physical.Pin object at 0x00000192BF9930A0>}, native elements: {'R0_0': <laygo2.object.physical.Rect object at 0x0...>, 'R1_0': <laygo2.object.physical.Rect object at 0x0...>, 'R0_1': <laygo2.object.physical.Rect object at 0x0...>, 'R1_1': <laygo2.object.physical.Rect object at 0x0...>, 'R0_2': <laygo2.object.physical.Rect object at 0x0...>, 'R1_2': <laygo2.object.physical.Rect object at 0x0...>, 'R0_3': <laygo2.object.physical.Rect object at 0x0...>, 'R1_3': <laygo2.object.physical.Rect object at 0x0...>, 'R0_4': <laygo2.object.physical.Rect object at 0x0...>, 'R1_4': <laygo2.object.physical.Rect object at 0x0...>, 'R2': <laygo2.object.physical.Rect object at 0x000...>} >>> print(user_inst.bbox) [[ 0 0] [500 100]] .. image:: ../assets/img/object_template_UserDefinedTemplate_generate.png :height: 250 """ inst = self._generate( name=name, shape=shape, pitch=pitch, transform=transform, params=params ) # update netnames if netmap is provided. if netmap is not None: inst.update_netname(netmap=netmap) return inst
# Test if __name__ == "__main__": test_native_template = True test_pcell_template = True test_user_template = True import laygo2.object if test_native_template: print("NativeInstanceTemplate test") # define pins nat_temp_pins = dict() nat_temp_pins["in"] = laygo2.object.Pin( xy=[[0, 0], [10, 10]], layer=["M1", "drawing"], netname="in" ) nat_temp_pins["out"] = laygo2.object.Pin( xy=[[90, 90], [100, 100]], layer=["M1", "drawing"], netname="out" ) # create a template nat_temp = NativeInstanceTemplate( libname="mylib", cellname="mynattemplate", bbox=[[0, 0], [100, 100]], pins=nat_temp_pins, ) # generate nat_inst = nat_temp.generate( name="mynatinst", shape=[2, 2], pitch=[100, 100], transform="R0" ) # display print(nat_temp) print(nat_inst) if test_pcell_template: print("ParameterizedInstanceTemplate test") # define the bbox computation function. def pcell_bbox_func(params): return np.array([[0, 0], [100 * params["mult"], 100]]) # define the pin generation function. def pcell_pins_func(params): template_pins = dict() for i in range(params["mult"]): template_pins["in" + str(i)] = laygo2.object.Pin( xy=[[i * 100 + 0, 0], [i * 100 + 10, 10]], layer=["M1", "drawing"], netname="in" + str(i), ) template_pins["out" + str(i)] = laygo2.object.Pin( xy=[[i * 100 + 90, 90], [i * 100 + 90, 100]], layer=["M1", "drawing"], netname="out" + str(i), ) return template_pins # create a template. pcell_temp = ParameterizedInstanceTemplate( libname="mylib", cellname="mypcelltemplate", bbox_func=pcell_bbox_func, pins_func=pcell_pins_func, ) # generate based on the parameter assigned. pcell_inst_params = {"mult": 4} pcell_inst_size = pcell_temp.size(params=pcell_inst_params) pcell_inst = pcell_temp.generate( name="mypcellinst", shape=[2, 2], pitch=pcell_inst_size, transform="R0", params=pcell_inst_params, ) # display print(pcell_temp) print(pcell_inst) if test_user_template: print("UserDefinedTemplate test") # define the bbox computation function. def user_bbox_func(params): return np.array([[0, 0], [100 * params["mult"], 100]]) # define the pin generation function. def user_pins_func(params): template_pins = dict() for i in range(params["mult"]): template_pins["in" + str(i)] = laygo2.object.Pin( xy=[[i * 100 + 0, 0], [i * 100 + 10, 10]], layer=["M1", "drawing"], netname="in" + str(i), ) template_pins["out" + str(i)] = laygo2.object.Pin( xy=[[i * 100 + 90, 90], [i * 100 + 90, 100]], layer=["M1", "drawing"], netname="out" + str(i), ) return template_pins # define the instance generation function. def user_generate_func( name=None, shape=None, pitch=np.array([0, 0]), transform="R0", params=None ): m = params["mult"] shape = np.array([1, 1]) if shape is None else np.asarray(shape) inst_pins = user_pins_func(params) inst_native_elements = dict() for i in range(m): ofst = i * 100 inst_native_elements["R0_" + str(i)] = laygo2.object.Rect( xy=[[ofst, 0], [ofst + 10, 10]], layer=["M1", "drawing"] ) inst_native_elements["R1_" + str(i)] = laygo2.object.Rect( xy=[[ofst + 90, 90], [ofst + 100, 100]], layer=["M1", "drawing"] ) inst_native_elements["R2"] = laygo2.object.Rect( xy=[[0, 0], [m * 100, 100]], layer=["prBoundary", "drawing"] ) inst = laygo2.object.VirtualInstance( name=name, libname="mylib", cellname="myvinst", xy=np.array([0, 0]), native_elements=inst_native_elements, shape=shape, pitch=pitch, unit_size=[m * 100, 100], pins=inst_pins, transform=transform, params=params, ) return inst user_temp = UserDefinedTemplate( name="myusertemplate", bbox_func=user_bbox_func, pins_func=user_pins_func, generate_func=user_generate_func, ) user_inst = user_temp.generate( name="myuserinst", shape=[2, 1], params={"mult": 5} ) print(user_temp) print(user_inst) print(user_inst.bbox)