Fix new replica_bitcell_array refactor with end caps. Remove single port end cap exceptions.

This commit is contained in:
mrg 2020-11-20 16:56:07 -08:00
parent 27a652ac1b
commit f729e9fca7
5 changed files with 77 additions and 94 deletions

View File

@ -318,14 +318,8 @@ class replica_bitcell_array(bitcell_base_array):
self.unused_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer))
self.unused_offset = vector(self.unused_pitch, 0)
# Add extra width on the left and right for the unused WLs
self.height = (self.row_size + self.extra_rows) * self.dummy_row.height
self.width = (self.column_size + self.extra_cols) * self.cell.width + 2 * self.unused_pitch
# This is a bitcell x bitcell offset to scale
self.bitcell_offset = vector(self.cell.width, self.cell.height)
self.strap_offset = vector(0, 0)
self.col_end_offset = vector(self.cell.width, self.cell.height)
self.row_end_offset = vector(self.cell.width, self.cell.height)
@ -336,12 +330,15 @@ class replica_bitcell_array(bitcell_base_array):
self.add_end_caps()
# Array was at (0, 0) but move everything so it is at the lower left
# We move DOWN the number of left RBL even if we didn't add the column to this bitcell array
array_offset = self.bitcell_offset.scale(1 + len(self.left_rbl), 1 + self.rbl[0])
self.translate_all(array_offset.scale(-1, -1))
# Add extra width on the left and right for the unused WLs
self.height = self.dummy_row_insts[1].uy()
self.width = self.dummy_col_insts[1].rx()
self.add_layout_pins()
self.route_unused_wordlines()
@ -375,17 +372,17 @@ class replica_bitcell_array(bitcell_base_array):
# Grow from left to right, toward the array
for bit, port in enumerate(self.left_rbl):
if not self.cell.end_caps:
offset = self.bitcell_offset.scale(-len(self.left_rbl) + bit, -self.rbl[0] - 1) + self.strap_offset.scale(-len(self.left_rbl) + bit, 0) + self.unused_offset
offset = self.bitcell_offset.scale(-len(self.left_rbl) + bit, -self.rbl[0] - 1) + self.unused_offset
else:
offset = self.bitcell_offset.scale(-len(self.left_rbl) + bit, -self.rbl[0] - (self.col_end_offset.y/self.cell.height)) + self.strap_offset.scale(-len(self.left_rbl) + bit, 0) + self.unused_offset
offset = self.bitcell_offset.scale(-len(self.left_rbl) + bit, -self.rbl[0] - (self.col_end_offset.y/self.cell.height)) + self.unused_offset
self.replica_col_insts[bit].place(offset)
# Grow to the right of the bitcell array, array outward
for bit, port in enumerate(self.right_rbl):
if not self.cell.end_caps:
offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.rbl[0] - 1) + self.strap_offset.scale(bit, -self.rbl[0] - 1)
offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.rbl[0] - 1)
else:
offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.rbl[0] - (self.col_end_offset.y/self.cell.height)) + self.strap_offset.scale(bit, -self.rbl[0] - 1)
offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.rbl[0] - (self.col_end_offset.y/self.cell.height))
self.replica_col_insts[self.rbl[0] + bit].place(offset)
@ -408,37 +405,24 @@ class replica_bitcell_array(bitcell_base_array):
# FIXME: These depend on the array size itself
# Far top dummy row (first row above array is NOT flipped)
flip_dummy = self.rbl[1] % 2
if not self.cell.end_caps:
dummy_row_offset = self.bitcell_offset.scale(0, self.rbl[1] + flip_dummy) + self.bitcell_array_inst.ul()
else:
dummy_row_offset = self.bitcell_offset.scale(0, self.rbl[1] + flip_dummy) + self.bitcell_array_inst.ul()
dummy_row_offset = self.bitcell_offset.scale(0, self.rbl[1] + flip_dummy) + self.bitcell_array_inst.ul()
self.dummy_row_insts[1].place(offset=dummy_row_offset,
mirror="MX" if flip_dummy else "R0")
# FIXME: These depend on the array size itself
# Far bottom dummy row (first row below array IS flipped)
flip_dummy = (self.rbl[0] + 1) % 2
if not self.cell.end_caps:
dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - 1 + flip_dummy) + self.unused_offset
else:
dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - (self.col_end_offset.y/self.cell.height) + flip_dummy) + self.unused_offset
dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - 1 + flip_dummy) + self.unused_offset
self.dummy_row_insts[0].place(offset=dummy_row_offset,
mirror="MX" if flip_dummy else "R0")
mirror="MX" if flip_dummy else "R0")
# Far left dummy col
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array
if not self.cell.end_caps:
dummy_col_offset = self.bitcell_offset.scale(-len(self.left_rbl) - 1, -self.rbl[0] - 1) + self.unused_offset
else:
dummy_col_offset = self.bitcell_offset.scale(-(len(self.left_rbl)*(1+self.strap_offset.x/self.cell.width)) - (self.row_end_offset.x/self.cell.width), -len(self.left_rbl) - (self.col_end_offset.y/self.cell.height))
dummy_col_offset = self.bitcell_offset.scale(-len(self.left_rbl) - 1, -self.rbl[0] - 1) + self.unused_offset
self.dummy_col_insts[0].place(offset=dummy_col_offset)
# Far right dummy col
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array
if not self.cell.end_caps:
dummy_col_offset = self.bitcell_offset.scale(len(self.right_rbl), -self.rbl[0] - 1) + self.bitcell_array_inst.lr()
else:
dummy_col_offset = self.bitcell_offset.scale(len(self.right_rbl)*(1+self.strap_offset.x/self.cell.width), -self.rbl[0] - (self.col_end_offset.y/self.cell.height)) + self.bitcell_array_inst.lr()
dummy_col_offset = self.bitcell_offset.scale(len(self.right_rbl), -self.rbl[0] - 1) + self.bitcell_array_inst.lr()
self.dummy_col_insts[1].place(offset=dummy_col_offset)
def add_layout_pins(self):
@ -455,6 +439,7 @@ class replica_bitcell_array(bitcell_base_array):
offset=pin.ll().scale(0, 1),
width=self.width,
height=pin.height())
# Replica wordlines (go by the row instead of replica column because we may have to add a pin
# even though the column is in another local bitcell array)
for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts):
@ -549,8 +534,7 @@ class replica_bitcell_array(bitcell_base_array):
self.add_power_pin("gnd", right_loc, directions=("H", "H"))
# Add a path to connect to the array
self.add_path(pin_layer, [left_loc, left_pin_loc])
self.add_path(pin_layer, [right_loc, right_pin_loc])
self.add_path(pin_layer, [left_loc, right_loc], width=pin.height())
def gen_bl_wire(self):
if OPTS.netlist_only:

View File

@ -14,37 +14,38 @@ from tech import layer_properties as layer_props
class replica_column(bitcell_base_array):
"""
Generate a replica bitline column for the replica array.
Rows is the total number of rows i the main array.
Rows is the total number of rows in the main array.
rbl is a tuple with the number of left and right replica bitlines.
Replica bit specifies which replica column this is (to determine where to put the
replica cell relative to the bottom (including the dummy bit at 0).
"""
def __init__(self, name, rows, rbl, replica_bit, column_offset=0):
super().__init__(rows=sum(rbl) + rows + 2, cols=1, column_offset=column_offset, name=name)
# Used for pin names and properties
self.cell = factory.create(module_type=OPTS.bitcell)
# Row size is the number of rows with word lines
self.row_size = sum(rbl) + rows
# Start of regular word line rows
self.row_start = rbl[0] + 1
# End of regular word line rows
self.row_end = self.row_start + rows
if not self.cell.end_caps:
self.row_size += 2
super().__init__(rows=self.row_size, cols=1, column_offset=column_offset, name=name)
self.rows = rows
self.left_rbl = rbl[0]
self.right_rbl = rbl[1]
self.replica_bit = replica_bit
# left, right, regular rows plus top/bottom dummy cells
self.total_size = self.left_rbl + rows + self.right_rbl
# Used for pin names and properties
self.cell = factory.create(module_type=OPTS.bitcell)
# For end caps
try:
if not self.cell.end_caps:
self.total_size += 2
except AttributeError:
self.total_size += 2
# Total size includes the replica rows and column cap rows
self.total_size = self.left_rbl + rows + self.right_rbl + 2
self.column_offset = column_offset
debug.check(replica_bit != 0 and replica_bit != rows,
"Replica bit cannot be the dummy row.")
debug.check(replica_bit <= self.left_rbl or replica_bit >= self.total_size - self.right_rbl - 1,
debug.check(replica_bit != 0 and replica_bit != self.total_size - 1,
"Replica bit cannot be the dummy/cap row.")
debug.check(replica_bit < self.row_start or replica_bit >= self.row_end,
"Replica bit cannot be in the regular array.")
if layer_props.replica_column.even_rows:
debug.check(rows % 2 == 0 and (self.left_rbl + 1) % 2 == 0,
@ -61,18 +62,20 @@ class replica_column(bitcell_base_array):
self.create_instances()
def create_layout(self):
self.height = self.total_size * self.cell.height
self.width = self.cell.width
self.place_instances()
self.height = self.cell_inst[-1].uy()
self.width = self.cell_inst[0].rx()
self.add_layout_pins()
self.add_boundary()
self.DRC_LVS()
def add_pins(self):
self.create_all_bitline_names()
self.create_all_wordline_names(self.total_size)
self.create_all_wordline_names(self.row_size)
self.add_pin_list(self.all_bitline_names, "OUTPUT")
self.add_pin_list(self.all_wordline_names, "INPUT")
@ -93,32 +96,32 @@ class replica_column(bitcell_base_array):
self.add_mod(self.edge_cell)
def create_instances(self):
self.cell_inst = {}
self.cell_inst = []
for row in range(self.total_size):
name="rbc_{0}".format(row)
# Top/bottom cell are always dummy cells.
# Regular array cells are replica cells (>left_rbl and <rows-right_rbl)
# Replic bit specifies which other bit (in the full range (0,rows) to make a replica cell.
if (row > self.left_rbl and row < self.total_size - self.right_rbl - 1):
self.cell_inst[row]=self.add_inst(name=name,
mod=self.replica_cell)
self.connect_inst(self.get_bitcell_pins(row, 0))
elif row==self.replica_bit:
self.cell_inst[row]=self.add_inst(name=name,
mod=self.replica_cell)
self.connect_inst(self.get_bitcell_pins(row, 0))
elif (row == 0 or row == self.total_size - 1):
self.cell_inst[row]=self.add_inst(name=name,
mod=self.edge_cell)
real_row = row
if self.cell.end_caps:
real_row -= 1
# Regular array cells are replica cells
# Replic bit specifies which other bit (in the full range (0,total_size) to make a replica cell.
if (row == 0 or row == self.total_size - 1):
self.cell_inst.append(self.add_inst(name=name,
mod=self.edge_cell))
if self.cell.end_caps:
self.connect_inst(self.get_bitcell_pins_col_cap(row, 0))
self.connect_inst(self.get_bitcell_pins_col_cap(real_row, 0))
else:
self.connect_inst(self.get_bitcell_pins(row, 0))
self.connect_inst(self.get_bitcell_pins(real_row, 0))
elif (row==self.replica_bit) or (row >= self.row_start and row < self.row_end):
self.cell_inst.append(self.add_inst(name=name,
mod=self.replica_cell))
self.connect_inst(self.get_bitcell_pins(real_row, 0))
else:
self.cell_inst[row]=self.add_inst(name=name,
mod=self.dummy_cell)
self.connect_inst(self.get_bitcell_pins(row, 0))
# Top/bottom cell are always dummy/cap cells.
self.cell_inst.append(self.add_inst(name=name,
mod=self.dummy_cell))
self.connect_inst(self.get_bitcell_pins(real_row, 0))
def place_instances(self):
# Flip the mirrors if we have an odd number of replica+dummy rows at the bottom
@ -184,7 +187,7 @@ class replica_column(bitcell_base_array):
height=wl_pin.height())
# Supplies are only connected in the ends
for (index, inst) in self.cell_inst.items():
for (index, inst) in enumerate(self.cell_inst):
for pin_name in ["vdd", "gnd"]:
if inst in [self.cell_inst[0], self.cell_inst[self.total_size - 1]]:
self.copy_power_pins(inst, pin_name)

View File

@ -25,14 +25,14 @@ class replica_bitcell_array_1rw_1r_test(openram_test):
OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(2, "Testing 4x4 non-replica array for cell_1rw_1r")
debug.info(2, "Testing 4x4 non-replica array for dp cell")
a = factory.create(module_type="replica_bitcell_array",
cols=4,
rows=4,
rbl=[1, 1])
self.local_check(a)
debug.info(2, "Testing 4x4 left replica array for cell_1rw_1r")
debug.info(2, "Testing 4x4 left replica array for dp cell")
a = factory.create(module_type="replica_bitcell_array",
cols=4,
rows=4,
@ -40,7 +40,7 @@ class replica_bitcell_array_1rw_1r_test(openram_test):
left_rbl=[0])
self.local_check(a)
debug.info(2, "Testing 4x4 array left and right replica for cell_1rw_1r")
debug.info(2, "Testing 4x4 array left and right replica for dp cell")
a = factory.create(module_type="replica_bitcell_array",
cols=4,
rows=4,
@ -52,7 +52,7 @@ class replica_bitcell_array_1rw_1r_test(openram_test):
# Sky 130 has restrictions on the symmetries
if OPTS.tech_name != "sky130":
debug.info(2, "Testing 4x4 array right only replica for cell_1rw_1r")
debug.info(2, "Testing 4x4 array right only replica for dp cell")
a = factory.create(module_type="replica_bitcell_array",
cols=4,
rows=4,

View File

@ -25,18 +25,22 @@ class replica_column_test(openram_test):
OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(2, "Testing replica column for 6t_cell")
debug.info(2, "Testing one left replica column for dual port")
a = factory.create(module_type="replica_column", rows=4, rbl=[1, 0], replica_bit=1)
self.local_check(a)
debug.info(2, "Testing replica column for 6t_cell")
debug.info(2, "Testing one right replica column for dual port")
a = factory.create(module_type="replica_column", rows=4, rbl=[0, 1], replica_bit=5)
self.local_check(a)
debug.info(2, "Testing two (left, right) replica columns for dual port")
a = factory.create(module_type="replica_column", rows=4, rbl=[1, 1], replica_bit=1)
self.local_check(a)
debug.info(2, "Testing two (left, right) replica columns for dual port")
a = factory.create(module_type="replica_column", rows=4, rbl=[1, 1], replica_bit=6)
self.local_check(a)
debug.info(2, "Testing replica column for 6t_cell")
a = factory.create(module_type="replica_column", rows=4, rbl=[2, 0], replica_bit=2)
self.local_check(a)
globals.end_openram()
# run the test from the command line

View File

@ -20,18 +20,10 @@ class replica_column_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Testing replica column for cell_6t")
debug.info(2, "Testing replica column for single port")
a = factory.create(module_type="replica_column", rows=4, rbl=[1, 0], replica_bit=1)
self.local_check(a)
debug.info(2, "Testing replica column for cell_1rw_1r")
a = factory.create(module_type="replica_column", rows=4, rbl=[1, 1], replica_bit=6)
self.local_check(a)
debug.info(2, "Testing replica column for cell_1rw_1r")
a = factory.create(module_type="replica_column", rows=4, rbl=[2, 0], replica_bit=2)
self.local_check(a)
globals.end_openram()
# run the test from the command line