class Resistor(spira.PCell): width = spira.NumberParameter(default=spira.RDD.R1.MIN_WIDTH, doc='Width of the shunt resistance.') length = spira.NumberParameter(default=spira.RDD.R1.MIN_LENGTH, doc='Length of the shunt resistance.') p1 = spira.Parameter(fdef_name='create_p1') p2 = spira.Parameter(fdef_name='create_p2') def validate_parameters(self): if self.width > self.length: raise ValueError('`Width` cannot be larger than `length`.') return True def create_p1(self): return spira.Port(name='P1', midpoint=(-self.length/2,0), orientation=180, width=self.width, process=spira.RDD.PROCESS.R1) def create_p2(self): return spira.Port(name='P2', midpoint=(self.length/2,2), orientation=0, width=self.width, process=spira.RDD.PROCESS.R1) def create_elements(self, elems): elems += spira.RouteManhattan(ports=[self.p1, self.p2], layer=spira.RDD.PLAYER.R1.METAL) return elems def create_ports(self, ports): ports += [self.p1, self.p2] return ports
class BoschVia(spira.Device): __name_prefix__ = 'Bosch_Standard' radius = spira.NumberParameter(default=RDD.B0.MIN_SIZE) m0_radius = spira.Parameter( fdef_name='create_m0_radius', doc='Radius of the ground layer around the via.') al_radius = spira.Parameter( fdef_name='create_al_radius', doc='Radius of the aluminum layer around the via.') def create_m0_radius(self): return (self.radius + 2 * RDD.Al.B0_MIN_SURROUND) def create_al_radius(self): return (self.radius + 2 * RDD.Al.B0_MIN_SURROUND) def create_elements(self, elems): elems += spira.Circle(box_size=(self.radius, self.radius), layer=RDD.PLAYER.B0.VIA) elems += spira.Circle(box_size=(self.m0_radius, self.m0_radius), layer=RDD.PLAYER.M0.METAL) elems += spira.Circle(box_size=(self.al_radius, self.al_radius), layer=RDD.PLAYER.Al.METAL) return elems def create_ports(self, ports): return ports
class HorizontalConnections(spira.Cell): ref_point = spira.Parameter(fdef_name='create_ref_point') def create_ref_point(self): return spira.Rectangle(p1=(-2.5, -2.5), p2=(2.5, 2.5), layer=spira.Layer(number=1)) def get_ports(self): p1 = spira.Port(name='P1_M1', midpoint=(50, 0), orientation=135, width=10) return [p1] def create_elements(self, elems): elems += self.ref_point pc = ProcessLayer() T = spira.Rotation(0) S = spira.SRef(pc, midpoint=(10, 0), transformation=T) p1 = self.get_ports()[0] S.connect(port=S.ports[0], destination=p1) elems += S return elems def create_ports(self, ports): ports += self.get_ports() return ports
class HorizontalAlignment(spira.Cell): ref_point = spira.Parameter(fdef_name='create_ref_point') def create_ref_point(self): return spira.Rectangle(p1=(-2.5, -2.5), p2=(2.5, 2.5), layer=spira.Layer(number=1)) def get_ports(self): p1 = spira.Port(name='P1_M1', midpoint=(50, 0), orientation=330, width=10) return [p1] def create_elements(self, elems): elems += self.ref_point pc = ProcessLayer() S = spira.SRef(pc, midpoint=(0, 0)) p1 = self.get_ports()[0] S.distance_alignment(port=pc.ports[0], destination=p1, distance=20) elems += S return elems def create_ports(self, ports): ports += self.get_ports() return ports
class RotationReference(spira.Cell): ref_point = spira.Parameter(fdef_name='create_ref_point') t1 = spira.Parameter(fdef_name='create_t1') t2 = spira.Parameter(fdef_name='create_t2') t3 = spira.Parameter(fdef_name='create_t3') def create_ref_point(self): ply = spira.Rectangle(p1=(-2.5, -2.5), p2=(2.5, 2.5), layer=spira.Layer(number=1)) return ply def create_t1(self): cell = spira.Cell() cell += spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=2)) T = spira.Rotation(-30) S = spira.SRef(cell, transformation=T) return S def create_t2(self): cell = spira.Cell() cell += spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=3)) T = spira.GenericTransform(rotation=-60) S = spira.SRef(cell, transformation=T) return S def create_t3(self): cell = spira.Cell() cell += spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=4)) S = spira.SRef(cell) S.rotate(-90) return S def create_elements(self, elems): elems += self.ref_point elems += self.t1 elems += self.t2 elems += self.t3 return elems
class ProcessLayer(spira.Cell): ref_point = spira.Parameter(fdef_name='create_ref_point') t1 = spira.Parameter(fdef_name='create_t1') width = spira.NumberParameter(default=10) length = spira.NumberParameter(default=50) def get_transforms(self): # T = spira.Translation(Coord(10, 0)) + spira.Rotation(rotation=60) T = spira.Translation(Coord(10, 0)) T += spira.Rotation(rotation=20) return T def create_ref_point(self): return spira.Rectangle(p1=(-2.5, -2.5), p2=(2.5, 2.5), layer=spira.Layer(number=1)) def create_t1(self): T = self.get_transforms() ply = spira.Rectangle(p1=(0, 0), p2=(self.width, self.length), layer=spira.Layer(number=2)) ply.transform(transformation=T) return ply def create_elements(self, elems): # elems += self.ref_point elems += self.t1 return elems def create_ports(self, ports): T = self.get_transforms() p1 = spira.Port(name='P1_M1', midpoint=(self.width / 2, 0), orientation=-90, width=self.width) p2 = spira.Port(name='P2_M1', midpoint=(self.width / 2, self.length), orientation=90, width=self.width) ports += p1.transform_copy(T) ports += p2.transform_copy(T) return ports
class TransformPolygon(spira.Cell): ref_point = spira.Parameter(fdef_name='create_ref_point') t1 = spira.Parameter(fdef_name='create_t1') t2 = spira.Parameter(fdef_name='create_t2') t3 = spira.Parameter(fdef_name='create_t3') def create_ref_point(self): return spira.Rectangle(p1=(-2.5, -2.5), p2=(2.5, 2.5), layer=spira.Layer(number=1)) def create_t1(self): T = spira.Rotation(30) + spira.Translation(Coord(10, 0)) ply = spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=2)) ply.transform(transformation=T) return ply def create_t2(self): T = spira.GenericTransform(translation=(20, 0), rotation=60) ply = spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=3), transformation=T) return ply def create_t3(self): ply = spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=4)) ply.translate((30, 0)) ply.rotate(90) # FIXME: Reflection is not working. ply.reflect(True) return ply def create_elements(self, elems): elems += self.ref_point elems += self.t1 elems += self.t2 elems += self.t3 return elems
class YtronCircuit(spira.Circuit): ytron = spira.Parameter(fdef_name='create_ytron') @spira.cache() def get_io_ports(self): p1 = spira.Port(name='P1_M1', midpoint=(-10, 10), orientation=0) p2 = spira.Port(name='P2_M1', midpoint=(5, 10), width=0.5, orientation=270) p3 = spira.Port(name='P3_M1', midpoint=(0, -10), width=1, orientation=90) return [p1, p2, p3] def create_ytron(self): shape = YtronShape(rho=0.5, theta=5) D = YtronDevice(shape=shape) return spira.SRef(alias='ytron', reference=D) def create_elements(self, elems): p1, p2, p3 = self.get_io_ports() elems += self.ytron # R = spira.RouteManhattan( elems += spira.RouteManhattan(ports=[self.ytron.ports['Pl_M1'], p1], width=self.ytron.ref.shape.arm_widths[0], layer=RDD.PLAYER.M1.METAL, corners=self.corners) # print(R[0].layer) # R[0].set(layer=RDD.PLAYER.M2.METAL) # print(R[0].layer) # elems += R elems += spira.RouteStraight(p1=p2, p2=self.ytron.ports['Pr_M1'], layer=RDD.PLAYER.M1.METAL, path_type='sine', width_type='sine') elems += spira.RouteStraight(p1=p3, p2=self.ytron.ports['Psrc_M1'], layer=RDD.PLAYER.M1.METAL, path_type='sine', width_type='sine') return elems def create_ports(self, ports): ports += self.get_io_ports() return ports
class ResistorExtended(Resistor): p3 = spira.Parameter(fdef_name='create_p3') def create_p3(self): return spira.Port(name='P3', midpoint=(self.length,0), orientation=90, width=self.width, process=spira.RDD.PROCESS.R1) def create_elements(self, elems): elems = super().create_elements(elems) elems += spira.RouteManhattan(ports=[self.p2, self.p3], corners='round', layer=spira.RDD.PLAYER.R1.METAL) return elems
class TranslatePolygon(spira.Cell): ref_point = spira.Parameter(fdef_name='create_ref_point') t1 = spira.Parameter(fdef_name='create_t1') t2 = spira.Parameter(fdef_name='create_t2') t3 = spira.Parameter(fdef_name='create_t3') def create_ref_point(self): return spira.Rectangle(p1=(-2.5, -2.5), p2=(2.5, 2.5), layer=spira.Layer(number=1)) def create_t1(self): T = spira.Translation(Coord(-10, 0)) ply = spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=2)) ply.transform(T) return ply def create_t2(self): tf = spira.GenericTransform(translation=Coord(-22, 0)) ply = spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=3), transformation=tf) return ply def create_t3(self): ply = spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=4)) ply.translate((-34, 0)) return ply def create_elements(self, elems): elems += self.ref_point elems += self.t1 elems += self.t2 elems += self.t3 return elems
class ReflectPolygon(spira.Cell): ref_point = spira.Parameter(fdef_name='create_ref_point') t1 = spira.Parameter(fdef_name='create_t1') t2 = spira.Parameter(fdef_name='create_t2') t3 = spira.Parameter(fdef_name='create_t3') def create_ref_point(self): return spira.Rectangle(p1=(-2.5, -2.5), p2=(2.5, 2.5), layer=spira.Layer(number=1)) def create_t1(self): T = spira.Reflection(True) ply = spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=2)) ply.transform(T) return ply def create_t2(self): T = spira.GenericTransform(reflection=True) ply = spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=3), transformation=T) return ply def create_t3(self): ply = spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=4)) ply.reflect(True) return ply def create_elements(self, elems): elems += self.ref_point elems += self.t1 elems += self.t2 elems += self.t3 return elems
class RouteExample(spira.Cell): layer = spira.LayerParameter(default=spira.RDD.PLAYER.M1.METAL, doc='Layer to be used when creating the route object.') p1 = spira.Parameter(fdef_name='create_p1') p2 = spira.Parameter(fdef_name='create_p2') def create_p1(self): return spira.Port(name='P1', midpoint=(0,0), orientation=180, process=self.layer.process) def create_p2(self): return spira.Port(name='P2', midpoint=(20,10), orientation=0, process=self.layer.process) def create_elements(self, elems): elems += spira.RouteManhattan(ports=[self.p1, self.p2], layer=self.layer) return elems def create_ports(self, ports): ports += self.p1 ports += self.p2 return ports
class TsvCircuit(spira.Circuit): """ Test circuit created for TSV fabrication. """ d2 = spira.Parameter(fdef_name='create_d2') def create_d2(self): return spira.Port(name='Al:D2', midpoint=(-1000, -5000), orientation=0, width=20) def create_elements(self, elems): r1 = Row() s1 = spira.SRef(r1) # s2 = spira.SRef(r1, midpoint=(2000, -1000)) s2 = spira.SRef(r1, transformation=spira.Translation((2000, -1000))) elems += s1 elems += s2 print(s1.ports['Al:T2']) print(s2.ports['Al:T2']) d1 = spira.Port(name='Al:D1', midpoint=(1000, 7000), orientation=180, width=20) # d2 = spira.Port(name='Al:D2', midpoint=(-1000, -5000), orientation=0, width=20) elems += spira.RouteManhattan( ports=[s1.ports['Al:T2'], d1, s2.ports['Al:T2']], width=20, layer=RDD.PLAYER.Al.METAL) elems += spira.RouteManhattan(ports=[s1.ports['Al:T1'], self.d2], width=20, layer=RDD.PLAYER.Al.METAL) return elems def create_ports(self, ports): print(self.elements) ports += self.d2 return ports
class PolygonCell(spira.Cell): res = spira.Parameter(fdef_name='create_res') def create_res(self): res = ResistorCell() s = spira.SRef(reference=res) return s def create_elements(self, elems): # elems += spira.SRef(reference=ResistorCell()) elems += self.res elems += spira.Rectangle(alias='M3', p1=(-10, -15), p2=(10, 15), layer=RDD.PLAYER.M3.METAL) return elems def create_ports(self, ports): ports += self.res.ports['E0_M2'].copy(name='P0_M2') ports += self.res.ports['E2_M2'].copy(name='P1_M2') return ports
class Layer(spira.ParameterInitializer): number = spira.Parameter(default=0, restriction=spira.RestrictRange(2, 5))
class Layer(spira.ParameterInitializer): number = spira.Parameter(default=0, preprocess=spira.ProcessorInt())
class VirtualConnect(__VirtualModel__): """ """ derived_edges = spira.DictParameter(fdef_name='create_derived_edges') derived_contacts = spira.Parameter(fdef_name='create_derived_contacts') attached_contacts = spira.Parameter(fdef_name='create_attached_contacts') def create_derived_contacts(self): """ """ mapping = {} for k in RDD.VIAS.keys: mapping[RDD.PLAYER[k]. CLAYER_CONTACT] = RDD.VIAS[k].LAYER_STACK['VIA_LAYER'] mapping[ RDD.PLAYER[k].CLAYER_M1] = RDD.VIAS[k].LAYER_STACK['BOT_LAYER'] mapping[ RDD.PLAYER[k].CLAYER_M2] = RDD.VIAS[k].LAYER_STACK['TOP_LAYER'] return get_derived_elements(elements=deepcopy(self.device).elements, mapping=mapping) def create_derived_edges(self): """ Detect connecting and overlapping layer edges. Returns the derived merged polygons and derived intersection edges. """ purposes = [ RDD.PURPOSE.METAL, RDD.PURPOSE.DEVICE_METAL, RDD.PURPOSE.CIRCUIT_METAL ] EF = filters.EdgeShapeFilter(edge_type=constants.EDGE_TYPE_OUTSIDE, width=0.3, purposes=purposes) edge_elems = EF(self.device).elements mapping = self._derived_edges_mapping() derived_edges = get_derived_elements(elements=edge_elems, mapping=mapping, store_as_edge=True) overlap_edges = {} self._connect_overlap_edges(self.device, derived_edges, overlap_edges) self._connect_boundary_edges(self.device, derived_edges, overlap_edges) return overlap_edges def _derived_edges_mapping(self): """ Map the derived edge layers in the RDD to a physical layer. """ mapping = {} purposes = ['METAL', 'DEVICE_METAL', 'CIRCUIT_METAL'] for pl in RDD.get_physical_layers_by_purpose(purposes=purposes): key = pl.process.symbol if hasattr(RDD.PLAYER[key], 'EDGE_CONNECTED'): derived_layer = RDD.PLAYER[key].EDGE_CONNECTED ps_1 = derived_layer.layer1.process.symbol ps_2 = derived_layer.layer2.process.symbol if ps_1 == ps_2: mapping[derived_layer] = RDD.PLAYER[ key].OUTSIDE_EDGE_DISABLED else: es = "Error in RDD: Edge process \'{}\' not the same as metal process \'{}\'." raise ValueError(es.format(ps_2, ps_1)) else: LOG.warning( 'Edge detection for METAL layer {} ignored.'.format(key)) return mapping def _connect_overlap_edges(self, D, derived_edges, overlap_edges): """ Connect edges to the overlapping polygon. """ for j, e in enumerate(D.derived_overlap_elements): overlap_edges[e] = [] for i, edge in enumerate(derived_edges): if len(edge.shape.intersections(e.shape)) != 0: edge.external_pid = e.id_string() edge.layer.purpose = RDD.PURPOSE.PORT.OUTSIDE_EDGE_ENABLED overlap_edges[e].append(edge) return overlap_edges def _connect_boundary_edges(self, D, derived_edges, overlap_edges): """ Connect the edges that falls on a shape boudnary, since there is no overlapping polygon in this case. """ for i, edge in enumerate(derived_edges): if edge.layer.purpose == RDD.PURPOSE.PORT.OUTSIDE_EDGE_DISABLED: c_edge = deepcopy(edge) edge.external_pid = edge.id_string() edge.layer.purpose = RDD.PURPOSE.PORT.OUTSIDE_EDGE_ENABLED overlap_edges[c_edge] = [edge] def view_virtual_connect(self, show_layers=False, write=False, **kwargs): """ View that contains all derived connections (attached contacts, derived edges). """ elems = spira.ElementList() if show_layers is True: el = self.derived_contacts F = filters.PurposeFilterAllow(purposes=['JJ', 'VIA']) elems += F(el) elems += self.device.elements else: elems += self.derived_contacts for ply_overlap, edges in self.derived_edges.items(): if ply_overlap.is_empty() is False: for e in edges: EF = filters.EdgeToPolygonFilter() elems += EF(e) if not isinstance(ply_overlap, spira.Edge): elems += ply_overlap name = self.device.name + '_VConnect' D = spira.Cell(name=name, elements=elems, ports=self.device.ports, transformation=self.device.transformation) D.gdsii_view() if write is True: D.gdsii_output(file_name=name) def view_derived_contacts(self, show_layers=False, **kwargs): elems = spira.ElementList() # if show_layers is True: # elems += self.device.elements # el = self.derived_contacts # F = filters.PurposeFilterAllow(purposes=['JJ', 'VIA']) # elems += F(el) el = self.derived_contacts elems += el D = spira.Cell(name='_DERIVED_CONTACTS', elements=elems) D.gdsii_view() def view_derived_edges(self, show_layers=False, **kwargs): elems = spira.ElementList() if show_layers is True: elems += self.device.elements for ply_overlap, edges in self.derived_edges.items(): if ply_overlap.is_empty() is False: for e in edges: EF = filters.EdgeToPolygonFilter() elems += EF(e) D = spira.Cell(name='_DERIVED_EDGES', elements=elems) D.gdsii_view()
class TsvLayout(spira.Circuit): """ Basic 2 TSV bosch via layout. """ width = spira.NumberParameter(default=1000) length = spira.NumberParameter(default=2000) # width = spira.NumberParameter( # default=RDD.R5.MIN_SIZE, # restriction=spira.RestrictRange(lower=RDD.R5.MIN_SIZE), # doc='Width of the shunt resistance.') via = spira.CellParameter(default=BoschVia, restriction=spira.RestrictType([BoschVia]), doc='TSV component for connecting M0 to Al.') via_left = spira.Parameter(fdef_name='create_via_left') via_right = spira.Parameter(fdef_name='create_via_right') p1 = spira.Parameter(fdef_name='create_p1') p2 = spira.Parameter(fdef_name='create_p2') p1_out = spira.Parameter(fdef_name='create_p1_out') def validate_parameters(self): if self.length < self.width: raise ValueError('Length cannot be less than width.') return True def create_p1(self): return spira.Port(name='Al:T1', midpoint=(-2000, 0), orientation=0, width=20) def create_p2(self): return spira.Port(name='Al:T2', midpoint=(2000, 0), orientation=180, width=20) def create_p1_out(self): return spira.Port(name='M0:T4', midpoint=(0, 500), orientation=270, width=20) def create_via_left(self): via = self.via() return spira.SRef(via, midpoint=(-1000, 0)) def create_via_right(self): via = self.via() return spira.SRef(via, midpoint=(1000, 0)) def create_elements(self, elems): elems += [self.via_left, self.via_right] d1 = spira.Port(name='Al:D1', midpoint=(-1000, 0), orientation=180, width=20) d11 = spira.Port(name='M0:D3', midpoint=(-1000, 0), orientation=0, width=20) d2 = spira.Port(name='Al:D2', midpoint=(1000, 0), orientation=0, width=20) d12 = spira.Port(name='M0:D4', midpoint=(1000, 0), orientation=180, width=20) d3 = spira.Port(name='M0:D5', midpoint=(0, 0), orientation=90, width=20) # FIXME: Throughs out with a wierd angle. # elems += spira.RouteManhattan( # ports=[self.p1, d1], # width=5, layer=RDD.PLAYER.Al.METAL) elems += spira.RouteStraight(p1=self.p1, p2=d1, layer=RDD.PLAYER.Al.METAL) elems += spira.RouteStraight(p1=d11, p2=d12, layer=RDD.PLAYER.M0.METAL) elems += spira.RouteStraight(p1=self.p2, p2=d2, layer=RDD.PLAYER.Al.METAL) elems += spira.RouteStraight(p1=self.p1_out, p2=d3, layer=RDD.PLAYER.M0.METAL) return elems def create_ports(self, ports): return ports
class Layer(spira.ParameterInitializer): number = spira.Parameter(default=0, restrictions=spira.INTEGER, preprocess=spira.ProcessorInt(), doc='Advanced parameter.')
class TransformReference(spira.Cell): ref_point = spira.Parameter(fdef_name='create_ref_point') t1 = spira.Parameter(fdef_name='create_t1') t2 = spira.Parameter(fdef_name='create_t2') t3 = spira.Parameter(fdef_name='create_t3') def create_ref_point(self): ply = spira.Rectangle(p1=(-2.5, -2.5), p2=(2.5, 2.5), layer=spira.Layer(number=1)) return ply def create_t1(self): cell = spira.Cell() cell += spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=2)) S1 = spira.SRef(cell) S1.rotate(rotation=45) S1.translate(Coord(15, 15)) S = spira.SRef(cell) S.rotate(rotation=45) S.translate(Coord(15, 15)) S.reflect(True) return [S1, S] def create_t2(self): cell = spira.Cell() tf_1 = spira.GenericTransform(translation=(10, 10), rotation=45) tf_2 = spira.GenericTransform(translation=Coord(10, 10), rotation=45, reflection=True) cell += spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=3)) S1 = spira.SRef(cell, transformation=tf_1) S2 = spira.SRef(cell, transformation=tf_2) return [S1, S2] def create_t3(self): cell = spira.Cell() tf_1 = spira.Translation(Coord(12.5, 2.5)) + spira.Rotation(60) tf_2 = spira.Translation(Coord( 12.5, 2.5)) + spira.Rotation(60) + spira.Reflection(True) cell += spira.Rectangle(p1=(0, 0), p2=(10, 50), layer=spira.Layer(number=4)) S1 = spira.SRef(cell, transformation=tf_1) S2 = spira.SRef(cell, transformation=tf_2) return [S1, S2] def create_elements(self, elems): elems += self.ref_point # elems += self.t1 # elems += self.t2 elems += self.t3 return elems
class __VirtualModel__(ParameterInitializer): device = spira.CellParameter( doc='The device from which a virtual model will be constructed.') geometry = spira.Parameter(fdef_name='create_geometry') process_flow = spira.VModelProcessFlowParameter()
class VirtualConnect(__VirtualModel__): # FIXME: Add a string list restriction. connect_type = spira.StringParameter(default='contact_layer') connected_edges = spira.DictParameter(fdef_name='create_connected_edges') connected_elements = spira.Parameter(fdef_name='create_connected_elements') def __make_polygons__(self): elems = spira.ElementList() if self.connect_type == 'contact_layer': mapping = {} for k in RDD.VIAS.keys: mapping[RDD.PLAYER[k]. CLAYER_CONTACT] = RDD.VIAS[k].LAYER_STACK['VIA_LAYER'] mapping[RDD.PLAYER[k]. CLAYER_M1] = RDD.VIAS[k].LAYER_STACK['BOT_LAYER'] mapping[RDD.PLAYER[k]. CLAYER_M2] = RDD.VIAS[k].LAYER_STACK['TOP_LAYER'] # print('\nMapping:') # for k, v in mapping.items(): # print(k, v) # print('') # print(self.device.elements) el = get_derived_elements(elements=self.device.elements, mapping=mapping) for e in el: if e.purpose == 'METAL': pass else: elems += e else: pass # # D = self.device.expand_flat_copy() # D = self.device.expand_flat_no_jjcopy() # elems = spira.ElementList() # for process in RDD.VMODEL.PROCESS_FLOW.active_processes: # for layer in RDD.get_physical_layers_by_process(processes=process): # LF = LayerFilterAllow(layers=[layer]) # el = LF(D.elements.polygons) # elems += spira.PolygonGroup(elements=el, layer=layer).intersect return elems def create_connected_elements(self): """ Adds contact ports to each metal polygon connected by a contact layer and return a list of the updated elements. """ for e1 in self.__make_polygons__(): for e2 in self.device.elements: for m in ['BOT_LAYER', 'TOP_LAYER']: if e2.layer == RDD.VIAS[e1.process].LAYER_STACK[m]: if e2.encloses(e1.center): e2.ports += spira.Port(name=e1.process, midpoint=e1.center, process=e1.layer.process, purpose=e1.layer.purpose, port_type='contact') return self.device.elements def _map_derived_edges(self): mapping = {} for pl in RDD.get_physical_layers_by_purpose(purposes=['METAL']): key = pl.process.symbol if hasattr(RDD.PLAYER[key], 'EDGE_CONNECTED'): derived_layer = RDD.PLAYER[key].EDGE_CONNECTED ps_1 = derived_layer.layer1.process.symbol ps_2 = derived_layer.layer2.process.symbol if ps_1 == ps_2: mapping[derived_layer] = RDD.PLAYER[ key].OUTSIDE_EDGE_DISABLED else: es = "Error in RDD: Edge process \'{}\' not the same as metal process \'{}\'." raise ValueError(es.format(ps_2, ps_1)) else: LOG.warning( 'Edge detection for METAL layer {} ignored.'.format(key)) return mapping def _connect_overlap_edges(self, D, edges, overlap_edges): """ Connect edges to the overlapping polygon. """ for j, e in enumerate(D.overlap_elements): overlap_edges[e] = [] for i, edge in enumerate(edges): if len(edge.shape.intersections(e.shape)) != 0: edge.pid = '{}'.format(e.shape.hash_string) edge.layer.purpose = RDD.PURPOSE.PORT.OUTSIDE_EDGE_ENABLED overlap_edges[e].append(edge) return overlap_edges def _connect_boundary_edges(self, edges, overlap_edges): """ Connect the edges that falls on a shape boudnary, since there is no overlapping polygon in this case.""" if len(edges) > 0: e = spira.Polygon(alias='Dummy', shape=[], layer=RDD.PLAYER.METAL) overlap_edges[e] = [] for i, edge in enumerate(edges): if edge.layer.purpose == RDD.PURPOSE.PORT.OUTSIDE_EDGE_DISABLED: edge.pid = '{}'.format(e.shape.hash_string) edge.layer.purpose = RDD.PURPOSE.PORT.OUTSIDE_EDGE_ENABLED overlap_edges[e].append(edge) def create_connected_edges(self): from spira.yevon.gdsii.elem_list import ElementList from spira.yevon.vmodel.derived import get_derived_elements EF = filters.EdgeFilter(edge_type=constants.EDGE_TYPE_OUTSIDE) el = EF(self.device).elements mapping = self._map_derived_edges() edges = get_derived_elements(el, mapping=mapping, store_as_edge=True) overlap_edges = {} self._connect_overlap_edges(self.device, edges, overlap_edges) self._connect_boundary_edges(edges, overlap_edges) return overlap_edges def gdsii_output_virtual_connect(self, **kwargs): elems = spira.ElementList() # for e in self.__make_polygons__(): # elems += e for ply_overlap, edges in self.connected_edges.items(): if len(ply_overlap.points) > 0: elems += ply_overlap elems += edges for e in self.device.elements: elems += e D = spira.Cell(name='_VIRTUAL_CONNECT', elements=elems) D.gdsii_output()
class Layer(spira.ParameterInitializer): number = spira.Parameter()