Replica bitcell array bbox to include unused WL gnd pins.

This commit is contained in:
mrg 2020-09-28 14:49:33 -07:00
parent 9c6d8d7aed
commit 70c90ca7fb
2 changed files with 49 additions and 25 deletions

View File

@ -845,11 +845,11 @@ class bank(design.design):
self.route_port_address_in(port) self.route_port_address_in(port)
if port % 2: if port % 2:
self.route_port_address_right(port) self.route_port_address_out(port, "right")
else: else:
self.route_port_address_left(port) self.route_port_address_out(port, "left")
def route_port_address_left(self, port): def route_port_address_out(self, port, side="left"):
""" Connecting Wordline driver output to Bitcell WL connection """ """ Connecting Wordline driver output to Bitcell WL connection """
driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] + ["rbl_wl"] driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] + ["rbl_wl"]
@ -857,18 +857,32 @@ class bank(design.design):
for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port) + [rbl_wl_name]): for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port) + [rbl_wl_name]):
# The mid guarantees we exit the input cell to the right. # The mid guarantees we exit the input cell to the right.
driver_wl_pin = self.port_address_inst[port].get_pin(driver_name) driver_wl_pin = self.port_address_inst[port].get_pin(driver_name)
driver_wl_pos = driver_wl_pin.rc() if side == "left":
driver_wl_pos = driver_wl_pin.rc()
else:
driver_wl_pos = driver_wl_pin.lc()
bitcell_wl_pin = self.bitcell_array_inst.get_pin(array_name) bitcell_wl_pin = self.bitcell_array_inst.get_pin(array_name)
bitcell_wl_pos = bitcell_wl_pin.lc()
mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * self.port_address_inst[port].rx() + 0.5 * self.bitcell_array_inst.lx(), 0) if side == "left":
mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0.5, 1) bitcell_wl_pos = bitcell_wl_pin.lc()
self.add_path(driver_wl_pin.layer, [driver_wl_pos, mid1, mid2]) port_address_pos = self.port_address_inst[port].rx()
# Via is non-preferred direction because mid1->mid2 is non-preferred direction bitcell_array_pos = self.bitcell_array_inst.lx()
self.add_via_stack_center(from_layer=driver_wl_pin.layer, else:
to_layer=bitcell_wl_pin.layer, bitcell_wl_pos = bitcell_wl_pin.rc()
offset=mid2, port_address_pos = self.port_address_inst[port].lx()
directions="nonpref") bitcell_array_pos = self.bitcell_array_inst.rx()
self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos])
mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * port_address_pos + 0.5 * bitcell_array_pos, 0)
mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0, 1)
if driver_wl_pin.layer != bitcell_wl_pin.layer:
self.add_path(driver_wl_pin.layer, [driver_wl_pos, mid1, mid2])
self.add_via_stack_center(from_layer=driver_wl_pin.layer,
to_layer=bitcell_wl_pin.layer,
offset=mid2)
self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos])
else:
self.add_path(bitcell_wl_pin.layer, [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
def route_port_address_right(self, port): def route_port_address_right(self, port):
""" Connecting Wordline driver output to Bitcell WL connection """ """ Connecting Wordline driver output to Bitcell WL connection """
@ -889,6 +903,7 @@ class bank(design.design):
offset=mid2) offset=mid2)
self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos]) self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos])
def route_column_address_lines(self, port): def route_column_address_lines(self, port):
""" Connecting the select lines of column mux to the address bus """ """ Connecting the select lines of column mux to the address bus """
if not self.col_addr_size>0: if not self.col_addr_size>0:

View File

@ -305,14 +305,21 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
def create_layout(self): def create_layout(self):
# We will need unused wordlines grounded, so we need to know their layer
pin = self.cell.get_pin(self.cell.get_all_wl_names()[0])
pin_layer = pin.layer
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.height = (self.row_size + self.extra_rows) * self.dummy_row.height
self.width = (self.column_size + self.extra_cols) * self.cell.width self.width = (self.column_size + self.extra_cols) * self.cell.width + 2 * self.unused_pitch
# This is a bitcell x bitcell offset to scale # This is a bitcell x bitcell offset to scale
self.bitcell_offset = vector(self.cell.width, self.cell.height) self.bitcell_offset = vector(self.cell.width, self.cell.height)
# Everything is computed with the main array at (0, 0) to start # Everything is computed with the main array at (self.unused_pitch, 0) to start
self.bitcell_array_inst.place(offset=[0, 0]) self.bitcell_array_inst.place(offset=self.unused_offset)
self.add_replica_columns() self.add_replica_columns()
@ -356,7 +363,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
# Grow from left to right, toward the array # Grow from left to right, toward the array
for bit, port in enumerate(self.left_rbl): for bit, port in enumerate(self.left_rbl):
offset = self.bitcell_offset.scale(-len(self.left_rbl) + bit, -self.rbl[0] - 1) offset = self.bitcell_offset.scale(-len(self.left_rbl) + bit, -self.rbl[0] - 1) + self.unused_offset
self.replica_col_insts[port].place(offset) self.replica_col_insts[port].place(offset)
# Grow to the right of the bitcell array, array outward # Grow to the right of the bitcell array, array outward
for bit, port in enumerate(self.right_rbl): for bit, port in enumerate(self.right_rbl):
@ -367,11 +374,13 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
# Add the dummy rows even if we aren't adding the replica column to this bitcell array # Add the dummy rows even if we aren't adding the replica column to this bitcell array
# These grow up, toward the array # These grow up, toward the array
for bit in range(self.rbl[0]): for bit in range(self.rbl[0]):
self.dummy_row_replica_insts[bit].place(offset=self.bitcell_offset.scale(0, -self.rbl[0] + bit + (-self.rbl[0] + bit) % 2), dummy_offset = self.bitcell_offset.scale(0, -self.rbl[0] + bit + (-self.rbl[0] + bit) % 2) + self.unused_offset
self.dummy_row_replica_insts[bit].place(offset=dummy_offset,
mirror="MX" if (-self.rbl[0] + bit) % 2 else "R0") mirror="MX" if (-self.rbl[0] + bit) % 2 else "R0")
# These grow up, away from the array # These grow up, away from the array
for bit in range(self.rbl[1]): for bit in range(self.rbl[1]):
self.dummy_row_replica_insts[self.rbl[0] + bit].place(offset=self.bitcell_offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul(), dummy_offset = self.bitcell_offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul()
self.dummy_row_replica_insts[self.rbl[0] + bit].place(offset=dummy_offset,
mirror="MX" if bit % 2 else "R0") mirror="MX" if bit % 2 else "R0")
def add_end_caps(self): def add_end_caps(self):
@ -386,12 +395,12 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
# FIXME: These depend on the array size itself # FIXME: These depend on the array size itself
# Far bottom dummy row (first row below array IS flipped) # Far bottom dummy row (first row below array IS flipped)
flip_dummy = (self.rbl[0] + 1) % 2 flip_dummy = (self.rbl[0] + 1) % 2
dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - 1 + flip_dummy) 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, 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 # Far left dummy col
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array # Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array
dummy_col_offset = self.bitcell_offset.scale(-len(self.left_rbl) - 1, -self.rbl[0] - 1) 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) self.dummy_col_insts[0].place(offset=dummy_col_offset)
# Far right dummy col # Far right dummy col
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array # Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array
@ -495,13 +504,13 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
def ground_pin(self, inst, name): def ground_pin(self, inst, name):
pin = inst.get_pin(name) pin = inst.get_pin(name)
pin_layer = pin.layer pin_layer = pin.layer
layer_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer))
left_pin_loc = vector(self.dummy_col_insts[0].lx(), pin.cy()) left_pin_loc = vector(self.dummy_col_insts[0].lx(), pin.cy())
right_pin_loc = vector(self.dummy_col_insts[1].rx(), pin.cy()) right_pin_loc = vector(self.dummy_col_insts[1].rx(), pin.cy())
# Place the pins a track outside of the array # Place the pins a track outside of the array
left_loc = left_pin_loc - vector(layer_pitch, 0) left_loc = left_pin_loc - vector(self.unused_pitch, 0)
right_loc = right_pin_loc + vector(layer_pitch, 0) right_loc = right_pin_loc + vector(self.unused_pitch, 0)
self.add_power_pin("gnd", left_loc, directions=("H", "H")) self.add_power_pin("gnd", left_loc, directions=("H", "H"))
self.add_power_pin("gnd", right_loc, directions=("H", "H")) self.add_power_pin("gnd", right_loc, directions=("H", "H"))