2022-12-13 01:35:23 +01:00
|
|
|
# See LICENSE for licensing information.
|
|
|
|
|
#
|
2023-02-28 00:56:24 +01:00
|
|
|
# Copyright (c) 2016-2023 Regents of the University of California and The Board
|
2022-12-13 01:35:23 +01:00
|
|
|
# of Regents for the Oklahoma Agricultural and Mechanical College
|
|
|
|
|
# (acting for and on behalf of Oklahoma State University)
|
|
|
|
|
# All rights reserved.
|
|
|
|
|
#
|
|
|
|
|
from openram.base import design
|
|
|
|
|
from openram.base import vector
|
|
|
|
|
from openram import OPTS
|
|
|
|
|
from openram.sram_factory import factory
|
2023-01-17 01:15:03 +01:00
|
|
|
from openram.tech import drc
|
2022-09-02 05:06:48 +02:00
|
|
|
|
|
|
|
|
class rom_poly_tap(design):
|
|
|
|
|
|
2023-03-20 22:35:06 +01:00
|
|
|
def __init__(self, name="", cell_name=None, tx_type="nmos", strap_layer="m2", add_active_tap=False, place_poly=None):
|
2023-01-23 03:34:11 +01:00
|
|
|
super().__init__(name, cell_name)
|
2022-09-02 05:06:48 +02:00
|
|
|
self.strap_layer=strap_layer
|
2022-12-09 23:25:11 +01:00
|
|
|
self.tx_type = tx_type
|
2023-03-20 22:35:06 +01:00
|
|
|
self.add_tap = add_active_tap
|
|
|
|
|
if place_poly is None:
|
|
|
|
|
self.place_poly = add_active_tap
|
|
|
|
|
else:
|
|
|
|
|
self.place_poly = place_poly
|
2023-01-23 03:34:11 +01:00
|
|
|
self.pitch_offset = 0
|
2022-09-02 05:06:48 +02:00
|
|
|
self.create_netlist()
|
|
|
|
|
self.create_layout()
|
|
|
|
|
|
|
|
|
|
def create_netlist(self):
|
|
|
|
|
#for layout constants
|
2023-02-04 02:21:35 +01:00
|
|
|
self.dummy = factory.create(module_type="rom_base_cell")
|
|
|
|
|
|
2022-12-09 23:25:11 +01:00
|
|
|
self.pmos = factory.create(module_type="ptx", tx_type="pmos")
|
2022-09-02 05:06:48 +02:00
|
|
|
|
|
|
|
|
def create_layout(self):
|
|
|
|
|
|
|
|
|
|
self.place_via()
|
2023-02-04 02:21:35 +01:00
|
|
|
self.add_boundary()
|
2023-03-20 22:35:06 +01:00
|
|
|
if self.add_tap or self.place_poly:
|
2023-01-23 03:34:11 +01:00
|
|
|
self.place_active_tap()
|
|
|
|
|
self.extend_poly()
|
|
|
|
|
|
2022-09-02 05:06:48 +02:00
|
|
|
def add_boundary(self):
|
2023-03-01 06:10:52 +01:00
|
|
|
contact_width = self.poly_contact.width
|
2022-09-02 05:06:48 +02:00
|
|
|
self.height = self.dummy.height
|
2023-03-01 06:10:52 +01:00
|
|
|
self.width = contact_width + self.pitch_offset
|
2022-12-30 09:35:15 +01:00
|
|
|
|
2022-09-02 05:06:48 +02:00
|
|
|
super().add_boundary()
|
|
|
|
|
|
|
|
|
|
def place_via(self):
|
2023-02-28 00:56:24 +01:00
|
|
|
|
2022-12-09 23:25:11 +01:00
|
|
|
contact_width = self.poly_contact.width
|
2022-12-30 09:35:15 +01:00
|
|
|
|
2023-01-23 03:34:11 +01:00
|
|
|
contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact
|
|
|
|
|
|
2023-03-01 23:21:29 +01:00
|
|
|
self.contact_x_offset = 0
|
2023-02-28 00:56:24 +01:00
|
|
|
|
2022-12-09 23:25:11 +01:00
|
|
|
|
2023-01-23 03:34:11 +01:00
|
|
|
contact_x = contact_width * 0.5 + self.contact_x_offset
|
2022-12-09 23:25:11 +01:00
|
|
|
self.contact_offset = vector(contact_x, contact_y)
|
2022-12-30 09:35:15 +01:00
|
|
|
|
2022-09-02 05:06:48 +02:00
|
|
|
self.via = self.add_via_stack_center(from_layer="poly",
|
|
|
|
|
to_layer=self.strap_layer,
|
2022-12-09 23:25:11 +01:00
|
|
|
offset=self.contact_offset)
|
2023-01-23 03:34:11 +01:00
|
|
|
self.add_layout_pin_rect_center("poly_tap", self.strap_layer, self.contact_offset)
|
2022-12-30 09:35:15 +01:00
|
|
|
|
2022-12-09 23:25:11 +01:00
|
|
|
def extend_poly(self):
|
2023-02-04 02:21:35 +01:00
|
|
|
y_offset = 0
|
|
|
|
|
if self.tx_type == "pmos":
|
|
|
|
|
y_offset = -self.height
|
|
|
|
|
start = self.via.center() + vector(0, y_offset)
|
|
|
|
|
|
|
|
|
|
self.add_segment_center("poly", start, vector(self.via.cx() + self.pitch_offset, self.via.cy() + y_offset))
|
|
|
|
|
self.add_segment_center("poly", start, vector(0, self.via.cy() + y_offset))
|
2022-12-30 09:35:15 +01:00
|
|
|
|
2023-01-23 03:34:11 +01:00
|
|
|
def place_active_tap(self):
|
|
|
|
|
gap = self.poly_extend_active - 0.5 * ( self.active_contact.height - self.poly_contact.width )
|
|
|
|
|
offset = self.active_space - gap
|
|
|
|
|
tap_x = self.via.cx() + offset
|
2023-03-01 06:10:52 +01:00
|
|
|
tap_y = self.via.cy() + self.dummy.width * 0.5
|
2023-01-23 03:34:11 +01:00
|
|
|
contact_pos = vector(tap_x, tap_y)
|
2022-12-30 09:35:15 +01:00
|
|
|
|
2023-01-23 03:34:11 +01:00
|
|
|
# edge of the next nmos
|
|
|
|
|
active_edge = self.dummy.width - self.dummy.cell_inst.height - self.poly_extend_active
|
2023-02-28 00:56:24 +01:00
|
|
|
|
2023-01-23 03:34:11 +01:00
|
|
|
# edge of the active contact
|
|
|
|
|
tap_edge = tap_x + 0.5 * self.active_contact.height
|
|
|
|
|
self.pitch_offset += (self.active_space * 2) - (tap_edge - active_edge) + self.contact_x_offset
|
2022-12-09 23:25:11 +01:00
|
|
|
|
2023-03-20 22:35:06 +01:00
|
|
|
if self.tx_type == "nmos" and self.add_tap:
|
2023-01-23 03:34:11 +01:00
|
|
|
self.add_via_center(layers=self.active_stack,
|
|
|
|
|
offset=contact_pos,
|
|
|
|
|
implant_type="p",
|
|
|
|
|
well_type="p",
|
|
|
|
|
directions="nonpref")
|
2023-03-20 22:35:06 +01:00
|
|
|
self.add_layout_pin_rect_center("active_tap", self.active_stack[2], contact_pos)
|