OpenRAM/technology/sky130/custom/sky130_bitcell_base_array.py

179 lines
7.6 KiB
Python
Raw Normal View History

2021-08-18 20:21:52 +02:00
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California
# All rights reserved.
#
import debug
from base import geometry
2021-08-18 20:21:52 +02:00
from sram_factory import factory
from modules import bitcell_base_array
2021-08-18 20:21:52 +02:00
from globals import OPTS
from tech import layer
class sky130_bitcell_base_array(bitcell_base_array):
"""
Abstract base class for bitcell-arrays -- bitcell, dummy, replica
"""
def __init__(self, name, rows, cols, column_offset):
super().__init__(name, rows, cols, column_offset)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.cell = factory.create(module_type=OPTS.bitcell, version="opt1")
def place_array(self, name_template, row_offset=0, col_offset=0):
yoffset = 0.0
for row in range(0, len(self.array_layout)):
xoffset = 0.0
for col in range(0, len(self.array_layout[row])):
self.place_inst = self.insts[(col) + (row) * len(self.array_layout[row])]
if row % 2 == 0:
if col == 0:
self.place_inst.place(offset=[xoffset, yoffset + self.cell.height], mirror="MX")
elif col % 4 == 0:
self.place_inst.place(offset=[xoffset, yoffset + self.cell.height], mirror="MX")
elif col % 4 == 3 :
self.place_inst.place(offset=[xoffset, yoffset + self.cell.height], mirror="MX")
elif col % 4 == 2:
self.place_inst.place(offset=[xoffset + self.cell.width, yoffset + self.cell.height], mirror="XY")
else:
self.place_inst.place(offset=[xoffset, yoffset + self.cell.height], mirror="MX")
else:
if col == 0:
self.place_inst.place(offset=[xoffset, yoffset])
elif col % 4 == 0:
self.place_inst.place(offset=[xoffset, yoffset])
elif col % 4 == 3 :
self.place_inst.place(offset=[xoffset, yoffset])
elif col % 4 == 2:
self.place_inst.place(offset=[xoffset + self.cell.width, yoffset], mirror="MY")
# self.place_inst.place(offset=[xoffset, yoffset])
else:
self.place_inst.place(offset=[xoffset, yoffset])
xoffset += self.place_inst.width
yoffset += self.place_inst.height
self.width = max([x.rx() for x in self.insts])
self.height = max([x.uy() for x in self.insts])
2022-03-07 10:20:59 +01:00
def get_bitcell_pins(self, row, col, swap = False):
2021-08-18 20:21:52 +02:00
"""
Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array
"""
bitcell_pins = []
for port in self.all_ports:
bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))])
bitcell_pins.append("gnd") # gnd
bitcell_pins.append("vdd") # vdd
bitcell_pins.append("vdd") # vpb
bitcell_pins.append("gnd") # vnb
bitcell_pins.extend([x for x in self.all_wordline_names if x.endswith("_{0}".format(row))])
return bitcell_pins
2021-12-15 23:19:52 +01:00
def get_strap_pins(self, row, col, name=""):
2021-08-18 20:21:52 +02:00
"""
Creates a list of connections in the strap cell,
indexed by column and row, for instance use in bitcell_array
"""
2021-12-15 23:19:52 +01:00
if name and "_p" in name:
strap_pins = ["gnd"]
else:
strap_pins = ["vdd"]
2021-08-18 20:21:52 +02:00
return strap_pins
2021-12-15 23:19:52 +01:00
def get_col_cap_p_pins(self, row, col):
2021-08-18 20:21:52 +02:00
"""
"""
2021-12-15 23:19:52 +01:00
strap_pins = ["gnd", "vdd", "gnd"]
2021-08-18 20:21:52 +02:00
return strap_pins
2021-12-15 23:19:52 +01:00
def get_col_cap_pins(self, row, col):
2021-08-18 20:21:52 +02:00
"""
"""
strap_pins = []
for port in self.all_ports:
strap_pins.extend([x for x in self.get_bitline_names(port) if "bl" in x and x.endswith("_{0}".format(col))])
strap_pins.extend(["vdd", "gnd"])
for port in self.all_ports:
strap_pins.extend([x for x in self.get_bitline_names(port) if "br" in x and x.endswith("_{0}".format(col))])
if row == 0:
2022-03-07 10:20:59 +01:00
strap_pins.extend(["top_gate"])
else:
2022-03-07 10:20:59 +01:00
strap_pins.extend(["bot_gate"])
2022-06-16 07:34:21 +02:00
strap_pins.extend(["vdd", "gnd"])
2021-08-18 20:21:52 +02:00
return strap_pins
def get_row_cap_pins(self, row, col):
"""
"""
strap_pins = ["gnd", "vdd", "gnd"]
return strap_pins
def get_corner_pins(self):
"""
"""
strap_pins = ["vdd", "gnd", "vdd"]
return strap_pins
def add_supply_pins(self):
""" Add the layout pins """
# Copy a vdd/gnd layout pin from every cell
for row in range(self.row_size):
for col in range(self.column_size):
inst = self.cell_inst[row, col]
for pin_name in ["vdd", "gnd"]:
self.copy_layout_pin(inst, pin_name)
if row == 2: #add only 1 label per col
2022-06-16 07:34:21 +02:00
if 'VPB' or 'vpb' in self.cell_inst[row, col].mod.pins:
2021-08-18 20:21:52 +02:00
pin = inst.get_pin("vpb")
self.objs.append(geometry.rectangle(layer["nwell"],
pin.ll(),
pin.width(),
pin.height()))
self.objs.append(geometry.label("vdd", layer["nwell"], pin.center()))
2022-06-16 07:34:21 +02:00
if 'VNB' or 'vnb'in self.cell_inst[row, col].mod.pins:
2021-08-18 20:21:52 +02:00
try:
from tech import layer_override
if layer_override['VNB']:
pin = inst.get_pin("vnb")
self.objs.append(geometry.label("gnd", layer["pwellp"], pin.center()))
self.objs.append(geometry.rectangle(layer["pwellp"],
pin.ll(),
pin.width(),
pin.height()))
except:
pin = inst.get_pin("vnb")
self.add_label("vdd", pin.layer, pin.center())
2022-03-07 10:20:59 +01:00
def add_bitline_pins(self):
bitline_names = self.cell.get_all_bitline_names()
for col in range(self.column_size):
for port in self.all_ports:
bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port])
text = "bl_{0}_{1}".format(port, col)
2022-05-20 06:45:48 +02:00
#if "Y" in self.cell_inst[0, col].mirror:
# text = text.replace("bl", "br")
2022-03-07 10:20:59 +01:00
self.add_layout_pin(text=text,
layer=bl_pin.layer,
offset=bl_pin.ll().scale(1, 0),
width=bl_pin.width(),
height=self.height)
br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1])
text = "br_{0}_{1}".format(port, col)
2022-05-20 06:45:48 +02:00
#if "Y" in self.cell_inst[0, col].mirror:
# text = text.replace("br", "bl")
2022-03-07 10:20:59 +01:00
self.add_layout_pin(text=text,
layer=br_pin.layer,
offset=br_pin.ll().scale(1, 0),
width=br_pin.width(),
height=self.height)