From 70c90ca7fb686d0eb4dd29d10f055103f8fcef75 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 28 Sep 2020 14:49:33 -0700 Subject: [PATCH] Replica bitcell array bbox to include unused WL gnd pins. --- compiler/modules/bank.py | 43 +++++++++++++++-------- compiler/modules/replica_bitcell_array.py | 31 ++++++++++------ 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index beb60501..183d646a 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -845,11 +845,11 @@ class bank(design.design): self.route_port_address_in(port) if port % 2: - self.route_port_address_right(port) + self.route_port_address_out(port, "right") 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 """ 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]): # 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_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_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) - mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0.5, 1) - self.add_path(driver_wl_pin.layer, [driver_wl_pos, mid1, mid2]) - # Via is non-preferred direction because mid1->mid2 is non-preferred direction - self.add_via_stack_center(from_layer=driver_wl_pin.layer, - to_layer=bitcell_wl_pin.layer, - offset=mid2, - directions="nonpref") - self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos]) + + if side == "left": + bitcell_wl_pos = bitcell_wl_pin.lc() + port_address_pos = self.port_address_inst[port].rx() + bitcell_array_pos = self.bitcell_array_inst.lx() + else: + bitcell_wl_pos = bitcell_wl_pin.rc() + port_address_pos = self.port_address_inst[port].lx() + bitcell_array_pos = self.bitcell_array_inst.rx() + + 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): """ Connecting Wordline driver output to Bitcell WL connection """ @@ -888,6 +902,7 @@ class bank(design.design): to_layer=bitcell_wl_pin.layer, offset=mid2) self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos]) + def route_column_address_lines(self, port): """ Connecting the select lines of column mux to the address bus """ diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 6c2d54a7..4e1c4df1 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -305,14 +305,21 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): 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.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 self.bitcell_offset = vector(self.cell.width, self.cell.height) - # Everything is computed with the main array at (0, 0) to start - self.bitcell_array_inst.place(offset=[0, 0]) + # Everything is computed with the main array at (self.unused_pitch, 0) to start + self.bitcell_array_inst.place(offset=self.unused_offset) 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 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) # Grow to the right of the bitcell array, array outward 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 # These grow up, toward the array 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") # These grow up, away from the array 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") 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 # Far bottom dummy row (first row below array IS flipped) 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, 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 - 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) # Far right dummy col # 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): pin = inst.get_pin(name) 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()) right_pin_loc = vector(self.dummy_col_insts[1].rx(), pin.cy()) # Place the pins a track outside of the array - left_loc = left_pin_loc - vector(layer_pitch, 0) - right_loc = right_pin_loc + vector(layer_pitch, 0) + left_loc = left_pin_loc - vector(self.unused_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", right_loc, directions=("H", "H"))