Switched to GF180D for extra metal layers, Fixed drc parameters so contacts are valid. ptx.py modified to achieve proper layer placement with gf180. ROM array and precharge DRC clean.

This commit is contained in:
Sage Walker
2023-10-31 23:24:21 -07:00
committed by SWalker
parent 0040efb86f
commit d6cb15c82d
11 changed files with 129 additions and 51 deletions
+15 -8
View File
@@ -129,12 +129,15 @@ class ptx(design):
# be decided in the layout later.
area_sd = 2.5 * self.poly_width * self.tx_width
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
# self.channel_length = drc("minlength_channel") if OPTS.tech_name != "gf180mcu" else drc("minlength_channel_" + self.tx_type)
self.channel_length = drc("minlength_channel")
if cell_props.ptx.model_is_subckt:
# sky130
main_str = "X{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
self.channel_length)
# Perimeters are in microns
# Area is in u since it is microns square
area_str = "pd={0:.2f} ps={0:.2f} as={1:.2f}u ad={1:.2f}u".format(perimeter_sd,
@@ -143,7 +146,7 @@ class ptx(design):
main_str = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
self.channel_length)
area_str = "pd={0:.2f}u ps={0:.2f}u as={1:.2f}p ad={1:.2f}p".format(perimeter_sd,
area_sd)
self.spice_device = main_str + area_str
@@ -160,17 +163,17 @@ class ptx(design):
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult=1".format("nshort" if self.tx_type == "nmos" else "pshort",
self.mults,
self.tx_width,
drc("minwidth_poly"))
self.channel_length)
elif cell_props.ptx.model_is_subckt:
self.lvs_device = "X{{0}} {{1}} {0} m={1} w={2}u l={3}u".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
self.channel_length)
else:
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
self.channel_length)
def setup_layout_constants(self):
"""
@@ -196,6 +199,9 @@ class ptx(design):
directions=("V", "V"),
dimensions=(1, self.num_contacts))
if OPTS.tech_name == "gf180mcu":
self.poly_width = self.channel_length
# This is the extra poly spacing due to the poly contact to poly contact pitch
# of contacted gates
extra_poly_contact_width = self.poly_contact.width - self.poly_width
@@ -216,11 +222,12 @@ class ptx(design):
self.active_width = 2 * self.end_to_contact + self.active_contact.width \
+ 2 * self.active_contact_to_gate + self.poly_width + (self.mults - 1) * self.poly_pitch
# Active height is just the transistor width
self.active_height = self.tx_width
# Active height is either the transistor width or the wide enough to enclose the active contact
self.active_height = max(self.tx_width, self.active_contact.width + 2 * self.active_enclose_contact)
# Poly height must include poly extension over active
self.poly_height = self.tx_width + 2 * self.poly_extend_active
self.poly_height = self.active_height + 2 * self.poly_extend_active
self.active_offset = vector([self.well_enclose_active] * 2)
+2 -2
View File
@@ -10,7 +10,7 @@
import math
from .bitcell_base_array import bitcell_base_array
from openram.base import vector
from openram import OPTS, debug
from openram import debug
from openram.sram_factory import factory
from openram.tech import drc, layer
@@ -156,7 +156,7 @@ class rom_base_array(bitcell_base_array):
name = "bit_r{0}_c{1}".format(row, col)
# when col = 0, bl_h is connected to precharge, otherwise connect to previous bl connection
# when col = col_size - 1 connected column_sizeto gnd otherwise create new bl connection
# when col = col_size - 1 connected to gnd otherwise create new bl connection
# debug.info(1, "Create cell: r{0}, c{1}".format(row, col))
if row == self.row_size:
+4
View File
@@ -80,6 +80,8 @@ class rom_base_cell(design):
self.cell_inst = self.add_inst( name=self.name + "_nmos",
mod=self.nmos,
)
print("bitmos", self.cell_inst.height, self.cell_inst.width)
if self.bit_value == 0:
self.connect_inst(["bl", "wl", "bl", "gnd"])
else:
@@ -103,6 +105,8 @@ class rom_base_cell(design):
self.copy_layout_pin(self.cell_inst, "S", "S")
self.copy_layout_pin(self.cell_inst, "D", "D")
self.copy_layout_pin(self.cell_inst, "G", "G")
self.source_pos = self.cell_inst.get_pin("S").center()
def place_poly(self):
+1 -1
View File
@@ -36,7 +36,7 @@ class rom_poly_tap(design):
self.place_via()
self.add_boundary()
self.extend_poly()
# self.extend_poly()
if self.add_tap or self.place_poly:
self.place_active_tap()
+6 -12
View File
@@ -17,9 +17,10 @@ class rom_precharge_array(design):
"""
An array of inverters to create the inverted address lines for the rom decoder
"""
def __init__(self, cols, name="", bitline_layer=None, strap_spacing=None, strap_layer="m2", tap_direction="row"):
def __init__(self, cols, name="", bitline_layer="m2", strap_spacing=None, strap_layer="m3", tap_direction="row"):
self.cols = cols
self.strap_layer = strap_layer
self.bitline_layer = bitline_layer
self.tap_direction = tap_direction
if "li" in layer:
@@ -27,14 +28,6 @@ class rom_precharge_array(design):
else:
self.supply_layer = "m1"
if bitline_layer is not None:
self.bitline_layer = bitline_layer
else:
self.bitline_layer = self.supply_layer
if name=="":
name = "rom_inv_array_{0}".format(cols)
if strap_spacing != None:
self.strap_spacing = strap_spacing
@@ -128,7 +121,7 @@ class rom_precharge_array(design):
for col in range(self.cols):
if col % self.strap_spacing == 0:
self.tap_insts[strap_num].place(vector(cell_x, cell_y + self.poly_tap.height))
self.tap_insts[strap_num].place(vector(cell_x + self.poly_space, cell_y + self.poly_tap.height))
strap_num += 1
if self.tap_direction == "col":
@@ -137,7 +130,7 @@ class rom_precharge_array(design):
self.pmos_insts[col].place(vector(cell_x, cell_y))
cell_x += self.pmos.width
self.tap_insts[strap_num].place(vector(cell_x, cell_y + self.poly_tap.height))
self.tap_insts[strap_num].place(vector(cell_x + self.poly_space, cell_y + self.poly_tap.height))
def create_layout_pins(self):
self.copy_layout_pin(self.tap_insts[0], "poly_tap", "gate")
@@ -158,11 +151,12 @@ class rom_precharge_array(design):
for tap in self.tap_insts:
tap_pin = tap.get_pin("poly_tap")
start = vector(tap_pin.cx(), tap_pin.by())
end = vector(start.x, tap.mod.get_pin("poly_tap").cy())
end = vector(start.x, self.pmos_insts[0].get_pin("G").cy())
self.add_segment_center(layer="poly", start=start, end=end)
offset_start = vector(end.x - self.poly_tap.width + self.poly_extend_active, end.y)
offset_end = end + vector(0.5*self.poly_width, 0)
self.add_segment_center(layer="poly", start=offset_start, end=offset_end)
self.add_segment_center(layer="poly", start=self.pmos_insts[-1].get_pin("G").center(), end=offset_end)
def extend_well(self):
self.well_offset = self.pmos.tap_offset
+7 -4
View File
@@ -24,6 +24,8 @@ class rom_precharge_cell(rom_base_cell):
self.place_tap()
self.extend_well()
print("precharge", self.height, self.width)
def add_modules(self):
if OPTS.tech_name == "sky130":
@@ -42,6 +44,7 @@ class rom_precharge_cell(rom_base_cell):
self.cell_inst = self.add_inst( name="precharge_pmos",
mod=self.pmos,
)
print("premos", self.cell_inst.height, self.cell_inst.width)
self.connect_inst(["bitline", "gate", "vdd", "vdd"])
def add_pins(self):
@@ -55,10 +58,10 @@ class rom_precharge_cell(rom_base_cell):
self.poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.height + 2 * self.poly_extend_active)
def extend_well(self):
well_y = self.get_pin("vdd").cy() - 0.5 * self.nwell_width
print(self.nwell_enclose_active)
well_y = self.get_pin("vdd").cy() - 0.5 * self.tap.height - self.nwell_enclose_active
well_ll = vector(0, well_y)
height = self.get_pin("D").cy() + 0.5 * self.nwell_width - well_y
height = self.get_pin("D").cy() + self.nwell_enclose_active - well_y
self.add_rect("nwell", well_ll, self.width , height)
def place_tap(self):
@@ -67,7 +70,7 @@ class rom_precharge_cell(rom_base_cell):
self.tap_offset = abs(tap_y)
pos = vector(source.cx(), tap_y )
self.add_via_center(layers=self.active_stack,
self.tap = self.add_via_center(layers=self.active_stack,
offset=pos,
implant_type="n",
well_type="n",