dual port rba lvs clean again with cell library changes

This commit is contained in:
Jesse Cirimelli-Low 2026-04-14 14:48:26 -07:00
parent b6d98c44d5
commit 515591a422
12 changed files with 116 additions and 62 deletions

View File

@ -19,8 +19,8 @@ class bitcell_array(bitcell_base_array):
Creates a rows x cols array of memory cells.
Assumes bit-lines and word lines are connected by abutment.
"""
def __init__(self, rows, cols, column_offset=0, name="", left_rbl=None, right_rbl=None):
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name)
def __init__(self, rows, cols, column_offset=0, row_offset=0, name="", left_rbl=None, right_rbl=None):
super().__init__(rows=rows, cols=cols, column_offset=column_offset, row_offset=row_offset, name=name)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
@ -59,18 +59,21 @@ class bitcell_array(bitcell_base_array):
self.cell = factory.create(module_type=OPTS.bitcell)
def create_instances(self):
r = self.row_offset
c = self.column_offset
self.cell_inst={}
if self.cell.mirror.y:
core_block = [[0 for x in range(2)] for y in range(2)]
core_block[0][0] = geometry.instance("core_0_0", mod=self.cell, is_bitcell=True)
core_block[1][0] = geometry.instance("core_1_0", mod=self.cell, is_bitcell=True, mirror='MX')
core_block[0][1] = geometry.instance("core_0_1", mod=self.cell, is_bitcell=True, mirror='MY')
core_block[1][1] = geometry.instance("core_1_1", mod=self.cell, is_bitcell=True, mirror='XY')
core_block[(0 + r) % 2][(0+c) %2] = geometry.instance(f"core_{(0 + r)%2}_{(0+c)%2}", mod=self.cell, is_bitcell=True, mirror='XY')
core_block[(0 + r) % 2][(1+c) %2] = geometry.instance(f"core_{(0 + r)%2}_{(1+c)%2}", mod=self.cell, is_bitcell=True, mirror='MX')
core_block[(1 + r) % 2][(0+c) %2] = geometry.instance(f"core_{(1 + r)%2}_{(0+c)%2}", mod=self.cell, is_bitcell=True, mirror='MY')
core_block[(1 + r) % 2][(1+c) %2] = geometry.instance(f"core_{(1 + r)%2}_{(1+c)%2}", mod=self.cell, is_bitcell=True, mirror='')
else:
core_block = [[0 for x in range(1)] for y in range(2)]
core_block[0][0] = geometry.instance("core_0_0", mod=self.cell, is_bitcell=True)
core_block[1][0] = geometry.instance("core_1_0", mod=self.cell, is_bitcell=True, mirror='MX')
core_block = [[0 for x in range(1)] for y in range(2)]
core_block[(0 + self.row_offset) % 2][(0+self.column_offset) %2] = geometry.instance("core_0_0", mod=self.cell, is_bitcell=True)
core_block[(1 + self.row_offset) % 2][(0+self.column_offset) %2] = geometry.instance("core_1_0", mod=self.cell, is_bitcell=True, mirror='MX')
print(r, c)
print(core_block)
self.pattern = pattern(self, "bitcell_array", core_block, num_rows=self.row_size, num_cols=self.column_size,name_template="bit_r{0}_c{1}")
self.pattern.connect_array()

View File

@ -16,14 +16,14 @@ class bitcell_base_array(design):
"""
Abstract base class for bitcell-arrays -- bitcell, dummy, replica
"""
def __init__(self, name, rows, cols, column_offset):
def __init__(self, name, rows, cols, column_offset, row_offset):
super().__init__(name)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.column_size = cols
self.row_size = rows
self.column_offset = column_offset
self.row_offset = row_offset
# Bitcell for port names only
self.cell = factory.create(module_type=OPTS.bitcell)
@ -170,6 +170,18 @@ class bitcell_base_array(design):
power_name = 'vdd'
ground_name = 'gnd'
if vdd_found == False or gnd_found == False:
for inst in self.insts:
if 'VDD' in inst.mod.get_pin_names():
vdd_found = True
power_name = 'VDD'
if 'GND' in inst.mod.get_pin_names():
gnd_found = True
ground_name = 'GND'
if vdd_found is False or gnd_found is False:
from openram.tech import cell_properties
try:

View File

@ -20,7 +20,7 @@ class capped_replica_bitcell_array(bitcell_base_array):
sides of a bitcell array.
"""
def __init__(self, rows, cols, rbl=None, left_rbl=None, right_rbl=None, name=""):
super().__init__(name, rows, cols, column_offset=0)
super().__init__(name, rows, cols, column_offset=0, row_offset=0)
debug.info(1, "Creating {0} {1} x {2} rbls: {3} left_rbl: {4} right_rbl: {5}".format(self.name,
rows,
cols,

View File

@ -8,12 +8,13 @@ from openram import OPTS
from .bitcell_base_array import bitcell_base_array
from openram.base import geometry
from .pattern import pattern
from math import ceil
class col_cap_array(bitcell_base_array):
"""
Generate a dummy row/column for the replica array.
"""
def __init__(self, rows, cols, column_offset=0, mirror=0, location="", name="",left_rbl=[],right_rbl=[]):
def __init__(self, rows, cols, column_offset=0, row_offset=0, mirror=0, location="", name="",left_rbl=[],right_rbl=[]):
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name)
self.mirror = mirror
self.location = location
@ -38,28 +39,44 @@ class col_cap_array(bitcell_base_array):
def create_layout(self):
self.place_array("dummy_r{0}_c{1}", self.mirror)
self.place_array()
self.add_layout_pins()
self.height = self.dummy_cell.height
self.width = self.column_size * self.cell.width
#self.height = self.dummy_cell.height
#self.width = self.column_size * self.cell.width
self.add_boundary()
self.DRC_LVS()
def add_modules(self):
""" Add the modules used in this design """
self.dummy_cell = factory.create(module_type="col_cap_{}".format(OPTS.bitcell))
self.colend = factory.create(module_type="col_cap_{}".format(OPTS.bitcell))
# def create_instances(self):
# """ Create the module instances used in this design """
# self.cell_inst = {}
# for col in range(self.column_size):
# for row in range(self.row_size):
# name = "bit_r{0}_c{1}".format(row, col)
# self.cell_inst[row, col]=self.add_inst(name=name,
# mod=self.dummy_cell)
# self.connect_inst(self.get_bitcell_pins(row, col))
def create_instances(self):
""" Create the module instances used in this design """
self.cell_inst = {}
for col in range(self.column_size):
for row in range(self.row_size):
name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row, col]=self.add_inst(name=name,
mod=self.dummy_cell)
self.connect_inst(self.get_bitcell_pins(row, col))
self.cell_inst={}
if self.location == "top":
bit_row = [geometry.instance("00_colend", mod=self.colend, is_bitcell=True, mirror="MY")]\
+ [geometry.instance("01_colend", mod=self.colend, is_bitcell=True)]
elif self.location == "bottom":
bit_row = [geometry.instance("00_colend", mod=self.colend, is_bitcell=True, mirror="XY")]\
+ [geometry.instance("01_colend", mod=self.colend, is_bitcell=True, mirror="MX")]
bit_row = pattern.rotate_list(bit_row, self.column_offset * 2)
bit_block = []
pattern.append_row_to_block(bit_block, bit_row)
self.pattern = pattern(self, "col_cap_array_" + self.location , bit_block, num_rows=self.row_size, num_cols=self.column_size, num_cores_x=ceil(self.column_size/2), num_cores_y=ceil(self.row_size/2), name_template="col_cap_array" + self.location + "_r{0}_c{1}")
self.pattern.connect_array()
def get_bitcell_pins(self, row, col):
"""

View File

@ -15,7 +15,7 @@ class dummy_array(bitcell_base_array):
"""
def __init__(self, rows, cols, column_offset=0, row_offset=0 ,mirror=0, location="", name="", left_rbl=0, right_rbl=0):
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name)
super().__init__(rows=rows, cols=cols, column_offset=column_offset, row_offset=row_offset, name=name)
self.location = location
self.row_offset = row_offset
self.mirror = mirror
@ -55,17 +55,20 @@ class dummy_array(bitcell_base_array):
def create_instances(self):
""" Create the module instances used in this design """
self.cell_inst={}
r = self.row_offset
c = self.column_offset
if self.cell.mirror.y:
core_block = [[0 for x in range(2)] for y in range(2)]
core_block[(0+self.mirror) %2][(0+self.column_offset+self.row_offset) %2] = geometry.instance("core_0_0", mod=self.dummy_cell, is_bitcell=True, mirror='MX')
core_block[(1+self.mirror) %2][(0+self.column_offset+self.row_offset) %2] = geometry.instance("core_1_0", mod=self.dummy_cell, is_bitcell=True)
core_block[(0+self.mirror) %2][(1+self.column_offset+self.row_offset) %2] = geometry.instance("core_0_1", mod=self.dummy_cell, is_bitcell=True, mirror='XY')
core_block[(1+self.mirror) %2][(1+self.column_offset+self.row_offset) %2] = geometry.instance("core_1_1", mod=self.dummy_cell, is_bitcell=True, mirror='MY')
core_block[(0 + r) % 2][(0+c) %2] = geometry.instance(f"core_{(0 + r)%2}_{(0+c)%2}", mod=self.dummy_cell, is_bitcell=True, mirror='XY')
core_block[(0 + r) % 2][(1+c) %2] = geometry.instance(f"core_{(0 + r)%2}_{(1+c)%2}", mod=self.dummy_cell, is_bitcell=True, mirror='MX')
core_block[(1 + r) % 2][(0+c) %2] = geometry.instance(f"core_{(1 + r)%2}_{(0+c)%2}", mod=self.dummy_cell, is_bitcell=True, mirror='MY')
core_block[(1 + r) % 2][(1+c) %2] = geometry.instance(f"core_{(1 + r)%2}_{(1+c)%2}", mod=self.dummy_cell, is_bitcell=True, mirror='')
else:
core_block = [[0 for x in range(1)] for y in range(2)]
core_block[(1+self.mirror) %2][(0+self.column_offset) %2] = geometry.instance("core_0_0", mod=self.dummy_cell, is_bitcell=True, mirror='MX')
core_block[(0+self.mirror) %2][(0+self.column_offset) %2] = geometry.instance("core_1_0", mod=self.dummy_cell, is_bitcell=True)
core_block = [[0 for x in range(1)] for y in range(2)]
core_block[(0 + self.row_offset) % 2][(0+self.column_offset) %2] = geometry.instance("core_0_0", mod=self.dummy_cell, is_bitcell=True)
core_block[(1 + self.row_offset) % 2][(0+self.column_offset) %2] = geometry.instance("core_1_0", mod=self.dummy_cell, is_bitcell=True, mirror='MX')
print(r, c)
print(core_block)
self.pattern = pattern(self, "dummy_array", core_block, num_rows=self.row_size, num_cols=self.column_size, name_template="bit_r{0}_c{1}")
self.pattern.connect_array()

View File

@ -147,7 +147,6 @@ class pattern():
def connect_array(self) -> None:
#debug_array = [[None]*12 for _ in range(6)]
row = 0
col = 0
for i in range(self.num_cores_y):
@ -183,7 +182,7 @@ class pattern():
y += inst.height
if "Y" in inst.mirror:
x += inst.width
#print('placing inst {} at {}'.format(inst, offset))
print('placing inst {} at {}'.format(inst, offset))
inst.place((x, y), inst.mirror, inst.rotate)
def place_array(self):
@ -193,7 +192,7 @@ class pattern():
for row in range(self.row_max+1):
x = 0
for col in range(self.col_max+1):
inst = self.parent_design.all_inst[self.row_max - row, col]
inst = self.parent_design.all_inst[row, col]
self.place_inst(inst, (x, y))
x += inst.width
y += inst.height

View File

@ -25,7 +25,7 @@ class replica_bitcell_array(bitcell_base_array):
replica bitcell and dummy bitcell (BL/BR disconnected).
"""
def __init__(self, rows, cols, rbl=None, left_rbl=None, right_rbl=None, name=""):
super().__init__(name=name, rows=rows, cols=cols, column_offset=0)
super().__init__(name=name, rows=rows, cols=cols, column_offset=0, row_offset=0)
debug.info(1, "Creating {0} {1} x {2} rbls: {3} left_rbl: {4} right_rbl: {5}".format(self.name,
rows,
cols,
@ -77,6 +77,7 @@ class replica_bitcell_array(bitcell_base_array):
# Bitcell array
self.bitcell_array = factory.create(module_type="bitcell_array",
column_offset=len(self.left_rbl),
row_offset=len(self.left_rbl),
cols=self.column_size,
rows=self.row_size,
left_rbl=self.left_rbl,
@ -110,20 +111,17 @@ class replica_bitcell_array(bitcell_base_array):
for port in self.all_ports:
if port in self.left_rbl:
row_offset = self.row_size
mirror = row_offset % 2 + 1
elif port in self.right_rbl:
row_offset = 0
mirror = 0
elif port in self.right_rbl:
row_offset = self.row_size + len(self.left_rbl)
else:
continue
row_offset = 0
self.dummy_rows[port] = factory.create(module_type="dummy_array",
cols=self.column_size,
rows=1,
row_offset=row_offset,
column_offset=len(self.left_rbl),
mirror=mirror)
column_offset=len(self.left_rbl))
def add_pins(self):

View File

@ -30,7 +30,7 @@ class replica_column(bitcell_base_array):
self.row_start = rbl[0]
# End of regular word line rows
self.row_end = self.row_start + rows
super().__init__(rows=self.row_size, cols=1, column_offset=column_offset, name=name)
super().__init__(rows=self.row_size, cols=1, column_offset=column_offset, row_offset=0, name=name)
self.rows = rows
self.left_rbl = rbl[0]
@ -95,12 +95,12 @@ class replica_column(bitcell_base_array):
# Replic bit specifies which other bit (in the full range (0,total_size) to make a replica cell.
# All other cells are dummies
if (row == self.replica_bit) or (row >= self.row_start and row < self.row_end):
if current_row % 2 == 1:
if current_row % 2 == 0:
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.replica_cell, is_bitcell=True)
else:
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.replica_cell, is_bitcell=True, mirror='MX')
else:
if current_row % 2 == 1:
if current_row % 2 == 0:
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.dummy_cell, is_bitcell=True)
else:
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.dummy_cell, is_bitcell=True, mirror='MX')

View File

@ -6,16 +6,19 @@
from openram.sram_factory import factory
from openram import OPTS
from .bitcell_base_array import bitcell_base_array
from .pattern import pattern
from openram.base import geometry
from math import ceil
class row_cap_array(bitcell_base_array):
"""
Generate a dummy row/column for the replica array.
"""
def __init__(self, rows, cols, column_offset=0, mirror=0, location="", name=""):
def __init__(self, rows, cols, column_offset=0, row_offset=0, mirror=0, location="", name=""):
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name)
self.mirror = mirror
self.location = location
self.row_offset = row_offset
#self.no_instances = True
self.create_netlist()
if not OPTS.netlist_only:
@ -33,7 +36,7 @@ class row_cap_array(bitcell_base_array):
def create_layout(self):
self.place_array("dummy_r{0}_c{1}", self.mirror)
self.place_array()
self.add_layout_pins()
self.width = max([x.rx() for x in self.insts])
@ -44,19 +47,37 @@ class row_cap_array(bitcell_base_array):
def add_modules(self):
""" Add the modules used in this design """
self.dummy_cell = factory.create(module_type="row_cap_{}".format(OPTS.bitcell))
self.row_cap = factory.create(module_type="row_cap_{}".format(OPTS.bitcell))
self.cell = factory.create(module_type=OPTS.bitcell)
def create_instances(self):
""" Create the module instances used in this design """
self.cell_inst = {}
for col in range(self.column_size):
for row in range(0, self.row_size):
name = "bit_r{0}_c{1}".format(row, col)
self.cell_inst[row, col]=self.add_inst(name=name,
mod=self.dummy_cell)
self.connect_inst(self.get_bitcell_pins(row, col))
self.all_inst={}
self.cell_inst={}
bit_block = []
if self.location == "left":
#top_corner = geometry.instance("row_cap_top_corner", mod=self.top_corner, is_bitcell=False, mirror="MY")
#bottom_corner = geometry.instance("row_cap_bottom_corner", mod=self.bottom_corner, is_bitcell=False, mirror="XY")
rowend = geometry.instance("row_cap_rowend", mod=self.row_cap, is_bitcell=True, mirror="")
rowend_m = geometry.instance("row_cap_rowend_m", mod=self.row_cap, is_bitcell=True, mirror="MX")
elif self.location == "right":
#top_corner = geometry.instance("row_cap_top_corner", mod=self.top_corner, is_bitcell=False)
#bottom_corner = geometry.instance("row_cap_bottom_corner", mod=self.bottom_corner, is_bitcell=False, mirror="MX")
rowend = geometry.instance("row_cap_rowend", mod=self.row_cap, is_bitcell=True, mirror="MY")
rowend_m = geometry.instance("row_cap_rowend_m", mod=self.row_cap, is_bitcell=True, mirror="XY")
#pattern.append_row_to_block(bit_block, [top_corner])
for row in range(0, self.row_size):
if row % 2 == 1:
pattern.append_row_to_block(bit_block, [rowend])
else:
pattern.append_row_to_block(bit_block, [rowend_m])
#pattern.append_row_to_block(bit_block, [bottom_corner])
self.pattern = pattern(self, "row_cap_array_" + self.location, bit_block, num_rows=self.row_size, num_cols=self.column_size, num_cores_x=ceil(self.column_size/2), num_cores_y=ceil(self.row_size/2), name_template="row_cap_array" + self.location + "_r{0}_c{1}")
self.pattern.connect_array_raw()
def get_bitcell_pins(self, row, col):
"""

View File

@ -26,3 +26,4 @@ num_sim_threads = 1
#analytical_delay = False
import os
exec(open(os.path.join(os.path.dirname(__file__), 'sky130_sram_common.py')).read())
#tech_file = "tech_custom_cell"

View File

@ -19,8 +19,8 @@ class sky130_bitcell_array(bitcell_array, sky130_bitcell_base_array):
Creates a rows x cols array of memory cells.
Assumes bit-lines and word lines are connected by abutment.
"""
def __init__(self, rows, cols, column_offset=0, name="",left_rbl=None, right_rbl=None):
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name)
def __init__(self, rows, cols, column_offset=0, row_offset=0, name="",left_rbl=None, right_rbl=None):
super().__init__(rows=rows, cols=cols, column_offset=column_offset, row_offset=row_offset, name=name)
self.left_rbl = left_rbl
self.right_rbl = right_rbl

View File

@ -15,5 +15,5 @@ sys.path.append("{}/{}".format(dir_path,'tech_configs'))
if not hasattr(OPTS, 'tech_file'):
OPTS.tech_file = 'tech_cypress_cell'
#TODO: FIX THIS TERRIBLE HACK JUST FOR TESTING
#TODO: FIX THIS TERRIBLE HACK JUST FOR TESTING EXECUTING
exec('from {} import *'.format(OPTS.tech_file))