2022-12-09 23:25:11 +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-09 23:25:11 +01:00
|
|
|
# of Regents for the Oklahoma Agricultural and Mechanical College
|
|
|
|
|
# (acting for and on behalf of Oklahoma State University)
|
|
|
|
|
# All rights reserved.
|
|
|
|
|
#
|
|
|
|
|
|
2022-12-13 01:35:23 +01:00
|
|
|
from math import ceil
|
|
|
|
|
from openram.base import geometry
|
|
|
|
|
from openram.base import design
|
|
|
|
|
from openram.sram_factory import factory
|
|
|
|
|
from openram.base import vector
|
|
|
|
|
from openram.tech import layer, drc
|
2022-12-09 23:25:11 +01:00
|
|
|
|
|
|
|
|
class rom_precharge_array(design):
|
|
|
|
|
"""
|
|
|
|
|
An array of inverters to create the inverted address lines for the rom decoder
|
|
|
|
|
"""
|
2023-09-13 20:41:15 +02:00
|
|
|
def __init__(self, cols, name="", bitline_layer="m2", strap_spacing=0, strap_layer="m3", tap_direction="row"):
|
2022-12-09 23:25:11 +01:00
|
|
|
self.cols = cols
|
2023-01-23 03:34:11 +01:00
|
|
|
self.strap_layer = strap_layer
|
2023-07-25 23:45:14 +02:00
|
|
|
self.bitline_layer = bitline_layer
|
2023-01-23 03:34:11 +01:00
|
|
|
self.tap_direction = tap_direction
|
2023-09-13 20:41:15 +02:00
|
|
|
self.strap_spacing = strap_spacing
|
2023-03-02 01:44:48 +01:00
|
|
|
if "li" in layer:
|
2023-01-23 03:34:11 +01:00
|
|
|
self.supply_layer = "li"
|
|
|
|
|
else:
|
|
|
|
|
self.supply_layer = "m1"
|
|
|
|
|
|
2022-12-09 23:25:11 +01:00
|
|
|
if strap_spacing != 0:
|
2022-12-13 01:35:23 +01:00
|
|
|
self.num_straps = ceil(self.cols / self.strap_spacing)
|
2023-03-01 06:10:52 +01:00
|
|
|
self.array_col_size = self.cols + self.num_straps
|
2022-12-09 23:25:11 +01:00
|
|
|
else:
|
|
|
|
|
self.num_straps = 0
|
|
|
|
|
self.array_col_size = self.cols
|
|
|
|
|
|
|
|
|
|
super().__init__(name)
|
|
|
|
|
self.create_netlist()
|
|
|
|
|
self.create_layout()
|
|
|
|
|
|
|
|
|
|
def create_netlist(self):
|
|
|
|
|
self.create_modules()
|
|
|
|
|
self.add_pins()
|
|
|
|
|
self.create_instances()
|
|
|
|
|
|
|
|
|
|
def create_layout(self):
|
2023-03-01 06:10:52 +01:00
|
|
|
self.width = self.cols * self.pmos.width
|
2022-12-09 23:25:11 +01:00
|
|
|
self.height = self.pmos.width
|
|
|
|
|
self.place_instances()
|
|
|
|
|
self.create_layout_pins()
|
|
|
|
|
self.route_supply()
|
2023-01-23 03:34:11 +01:00
|
|
|
self.connect_taps()
|
2023-02-28 00:56:24 +01:00
|
|
|
|
2022-12-09 23:25:11 +01:00
|
|
|
self.add_boundary()
|
2023-01-23 03:34:11 +01:00
|
|
|
self.extend_well()
|
2022-12-09 23:25:11 +01:00
|
|
|
|
|
|
|
|
def add_boundary(self):
|
|
|
|
|
ur = self.find_highest_coords()
|
2023-01-23 03:34:11 +01:00
|
|
|
self.add_label(layer="nwell", text="upper right",offset=ur)
|
2022-12-09 23:25:11 +01:00
|
|
|
super().add_boundary(vector(0, 0), ur)
|
2023-03-01 06:10:52 +01:00
|
|
|
self.height = ur.y
|
2023-01-23 03:34:11 +01:00
|
|
|
self.width = ur.x
|
2022-12-09 23:25:11 +01:00
|
|
|
|
|
|
|
|
def create_modules(self):
|
|
|
|
|
|
2023-03-02 01:44:48 +01:00
|
|
|
self.pmos = factory.create(module_type="rom_precharge_cell", module_name="precharge_cell", bitline_layer=self.bitline_layer, supply_layer=self.supply_layer)
|
2022-12-09 23:25:11 +01:00
|
|
|
|
|
|
|
|
# For layout constants
|
|
|
|
|
self.dummy = factory.create(module_type="rom_base_cell")
|
2023-01-23 03:34:11 +01:00
|
|
|
|
2023-03-20 22:35:06 +01:00
|
|
|
self.poly_tap = factory.create(module_type="rom_poly_tap", tx_type="pmos", add_active_tap=(self.tap_direction == "col"))
|
2022-12-09 23:25:11 +01:00
|
|
|
|
|
|
|
|
def add_pins(self):
|
|
|
|
|
for col in range(self.cols):
|
|
|
|
|
self.add_pin("pre_bl{0}_out".format(col), "OUTPUT")
|
|
|
|
|
self.add_pin("gate", "INPUT")
|
2023-01-27 02:33:47 +01:00
|
|
|
self.add_pin("vdd", "POWER")
|
2022-12-09 23:25:11 +01:00
|
|
|
|
|
|
|
|
def create_instances(self):
|
|
|
|
|
self.array_insts = []
|
|
|
|
|
self.pmos_insts = []
|
|
|
|
|
self.tap_insts = []
|
2023-01-17 01:15:03 +01:00
|
|
|
|
2023-01-23 03:34:11 +01:00
|
|
|
self.create_poly_tap(-1)
|
2022-12-09 23:25:11 +01:00
|
|
|
for col in range(self.cols):
|
2023-02-28 00:56:24 +01:00
|
|
|
|
2023-01-23 03:34:11 +01:00
|
|
|
if col % self.strap_spacing == 0:
|
|
|
|
|
self.create_poly_tap(col)
|
|
|
|
|
self.create_precharge_tx(col)
|
2022-12-09 23:25:11 +01:00
|
|
|
|
2023-01-23 03:34:11 +01:00
|
|
|
def create_precharge_tx(self, col):
|
2023-02-01 23:49:59 +01:00
|
|
|
name = "pmos_c{0}".format(col)
|
2023-01-23 03:34:11 +01:00
|
|
|
pmos = self.add_inst(name=name, mod=self.pmos)
|
|
|
|
|
self.array_insts.append(pmos)
|
|
|
|
|
self.pmos_insts.append(pmos)
|
|
|
|
|
bl = "pre_bl{0}_out".format(col)
|
|
|
|
|
self.connect_inst(["vdd", "gate", bl])
|
|
|
|
|
|
|
|
|
|
def create_poly_tap(self, col):
|
|
|
|
|
name = "tap_c{}".format( col)
|
|
|
|
|
new_tap = self.add_inst(name=name, mod=self.poly_tap)
|
|
|
|
|
self.tap_insts.append(new_tap)
|
|
|
|
|
self.connect_inst([])
|
2022-12-09 23:25:11 +01:00
|
|
|
|
|
|
|
|
def place_instances(self):
|
|
|
|
|
|
|
|
|
|
self.array_pos = []
|
2023-03-01 06:10:52 +01:00
|
|
|
strap_num = 0
|
|
|
|
|
cell_y = 0
|
2023-02-04 02:21:35 +01:00
|
|
|
# columns are bit lines
|
2022-12-09 23:25:11 +01:00
|
|
|
cell_x = 0
|
2023-01-17 01:15:03 +01:00
|
|
|
|
2022-12-09 23:25:11 +01:00
|
|
|
for col in range(self.cols):
|
2023-02-28 00:56:24 +01:00
|
|
|
|
2023-01-23 03:34:11 +01:00
|
|
|
if col % self.strap_spacing == 0:
|
2023-07-25 23:45:14 +02:00
|
|
|
self.tap_insts[strap_num].place(vector(cell_x + self.poly_space, cell_y + self.poly_tap.height))
|
2023-01-23 03:34:11 +01:00
|
|
|
strap_num += 1
|
|
|
|
|
|
|
|
|
|
if self.tap_direction == "col":
|
|
|
|
|
cell_x += self.poly_tap.pitch_offset
|
|
|
|
|
|
2022-12-09 23:25:11 +01:00
|
|
|
self.pmos_insts[col].place(vector(cell_x, cell_y))
|
|
|
|
|
cell_x += self.pmos.width
|
2023-02-04 02:21:35 +01:00
|
|
|
|
2023-07-25 23:45:14 +02:00
|
|
|
self.tap_insts[strap_num].place(vector(cell_x + self.poly_space, cell_y + self.poly_tap.height))
|
2022-12-09 23:25:11 +01:00
|
|
|
|
|
|
|
|
def create_layout_pins(self):
|
2023-01-23 03:34:11 +01:00
|
|
|
self.copy_layout_pin(self.tap_insts[0], "poly_tap", "gate")
|
2023-02-04 02:21:35 +01:00
|
|
|
self.copy_layout_pin(self.tap_insts[-1], "poly_tap", "precharge_r")
|
2022-12-09 23:25:11 +01:00
|
|
|
for col in range(self.cols):
|
|
|
|
|
source_pin = self.pmos_insts[col].get_pin("D")
|
|
|
|
|
bl = "pre_bl{0}_out".format(col)
|
2023-03-02 01:44:48 +01:00
|
|
|
self.add_layout_pin_rect_center(bl, self.bitline_layer, source_pin.center())
|
2022-12-09 23:25:11 +01:00
|
|
|
|
|
|
|
|
def route_supply(self):
|
2023-01-27 02:33:47 +01:00
|
|
|
self.route_horizontal_pins("vdd", insts=self.pmos_insts, layer=self.strap_layer)
|
2022-12-09 23:25:11 +01:00
|
|
|
|
2023-01-23 03:34:11 +01:00
|
|
|
def connect_taps(self):
|
|
|
|
|
array_pins = [self.tap_insts[i].get_pin("poly_tap") for i in range(len(self.tap_insts))]
|
2022-12-09 23:25:11 +01:00
|
|
|
|
2023-01-23 03:34:11 +01:00
|
|
|
self.connect_row_pins(layer=self.strap_layer, pins=array_pins, name=None, round=False)
|
2022-12-09 23:25:11 +01:00
|
|
|
|
2023-02-04 02:21:35 +01:00
|
|
|
for tap in self.tap_insts:
|
|
|
|
|
tap_pin = tap.get_pin("poly_tap")
|
|
|
|
|
start = vector(tap_pin.cx(), tap_pin.by())
|
2023-07-25 23:45:14 +02:00
|
|
|
end = vector(start.x, self.pmos_insts[0].get_pin("G").cy())
|
2023-02-04 02:21:35 +01:00
|
|
|
self.add_segment_center(layer="poly", start=start, end=end)
|
2023-03-01 06:10:52 +01:00
|
|
|
offset_start = vector(end.x - self.poly_tap.width + self.poly_extend_active, end.y)
|
2023-02-04 02:21:35 +01:00
|
|
|
offset_end = end + vector(0.5*self.poly_width, 0)
|
|
|
|
|
self.add_segment_center(layer="poly", start=offset_start, end=offset_end)
|
2023-07-25 23:45:14 +02:00
|
|
|
self.add_segment_center(layer="poly", start=self.pmos_insts[-1].get_pin("G").center(), end=offset_end)
|
2023-02-04 02:21:35 +01:00
|
|
|
|
2023-09-13 20:41:15 +02:00
|
|
|
|
|
|
|
|
gate_y = self.pmos_insts[0].get_pin('G').cy()
|
|
|
|
|
start = vector( self.get_pin("gate").lx(), gate_y)
|
|
|
|
|
end = vector( self.get_pin("precharge_r").rx(), gate_y )
|
|
|
|
|
|
|
|
|
|
self.add_segment_center(layer="poly", start=start, end=end)
|
|
|
|
|
|
2023-01-23 03:34:11 +01:00
|
|
|
def extend_well(self):
|
2023-01-27 00:48:38 +01:00
|
|
|
self.well_offset = self.pmos.tap_offset
|
2022-12-09 23:25:11 +01:00
|
|
|
|
2023-09-13 20:41:15 +02:00
|
|
|
well_y = self.get_pin("vdd").by() - self.nwell_enclose_active
|
2023-01-23 03:34:11 +01:00
|
|
|
well_ll = vector(0, well_y)
|
2022-12-09 23:25:11 +01:00
|
|
|
|
2023-02-28 00:56:24 +01:00
|
|
|
self.add_rect("nwell", well_ll, self.width , self.height - well_y)
|