From e95ab6691658c36f1f12cb9fcdf8cab04c8a24cd Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 14 Sep 2020 12:05:45 -0700 Subject: [PATCH] Update to space according to the bitcell array. --- compiler/modules/bank.py | 23 ++++++---- compiler/modules/bitcell_base_array.py | 3 +- compiler/modules/global_bitcell_array.py | 2 +- compiler/modules/local_bitcell_array.py | 3 +- compiler/modules/port_data.py | 28 ++++++------ compiler/modules/precharge_array.py | 5 ++- compiler/modules/replica_bitcell_array.py | 7 +-- compiler/modules/sense_amp_array.py | 44 ++++++++++--------- .../modules/single_level_column_mux_array.py | 4 +- compiler/modules/write_driver_array.py | 24 ++++------ 10 files changed, 74 insertions(+), 69 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index fa03a807..d091896e 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -189,6 +189,8 @@ class bank(design.design): self.main_bitcell_array_top = self.bitcell_array.get_main_array_top() # Just past the dummy column self.main_bitcell_array_left = self.bitcell_array.get_main_array_left() + # Just past the dummy column + self.main_bitcell_array_right = self.bitcell_array.get_main_array_right() # Just past the dummy row and replica row self.main_bitcell_array_bottom = self.bitcell_array.get_main_array_bottom() @@ -200,8 +202,10 @@ class bank(design.design): """ Return an array of the x offsets of all the regular bits """ - return self.bitcell_array.get_column_offsets() - + # Assumes bitcell_array is at 0,0 + offsets = self.bitcell_array.get_column_offsets() + return offsets + def compute_instance_port0_offsets(self): """ Compute the instance offsets for port0 on the left/bottom of the bank. @@ -215,7 +219,7 @@ class bank(design.design): # LOWER RIGHT QUADRANT # Below the bitcell array - self.port_data_offsets[port] = vector(self.main_bitcell_array_left - self.bitcell_array.cell.width, 0) + self.port_data_offsets[port] = vector(0, 0) # UPPER LEFT QUADRANT # To the left of the bitcell array above the predecoders and control logic @@ -259,7 +263,7 @@ class bank(design.design): # UPPER LEFT QUADRANT # Above the bitcell array - self.port_data_offsets[port] = vector(self.main_bitcell_array_left, self.bitcell_array_top) + self.port_data_offsets[port] = vector(0, self.bitcell_array_top) # LOWER RIGHT QUADRANT # To the right of the bitcell array @@ -392,11 +396,12 @@ class bank(design.design): self.add_mod(self.bitcell_array) self.port_data = [] + self.bit_offsets = self.get_column_offsets() for port in self.all_ports: temp_pre = factory.create(module_type="port_data", sram_config=self.sram_config, port=port, - bit_offsets=self.bitcell_array.get_column_offsets()) + bit_offsets=self.bit_offsets) self.port_data.append(temp_pre) self.add_mod(self.port_data[port]) @@ -916,7 +921,7 @@ class bank(design.design): offset = self.column_decoder_inst[port].lr() + vector(pitch, 0) decode_pins = [self.column_decoder_inst[port].get_pin(x) for x in decode_names] - + sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)] column_mux_pins = [self.port_data_inst[port].get_pin(x) for x in sel_names] @@ -1043,10 +1048,12 @@ class bank(design.design): control_signal = self.prefix + "wl_en{}".format(port) if port % 2: pin_pos = self.port_address_inst[port].get_pin("wl_en").uc() - mid_pos = pin_pos + vector(0, 2 * self.m2_gap) # to route down to the top of the bus + control_y_offset = self.bus_pins[port][control_signal].by() + mid_pos = vector(pin_pos.x, control_y_offset + self.m1_pitch) else: pin_pos = self.port_address_inst[port].get_pin("wl_en").bc() - mid_pos = pin_pos - vector(0, 2 * self.m2_gap) # to route down to the top of the bus + control_y_offset = self.bus_pins[port][control_signal].uy() + mid_pos = vector(pin_pos.x, control_y_offset - self.m1_pitch) control_x_offset = self.bus_pins[port][control_signal].cx() control_pos = vector(control_x_offset, mid_pos.y) self.add_wire(self.m1_stack, [pin_pos, mid_pos, control_pos]) diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 0fe03494..992a5c3c 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -211,4 +211,5 @@ class bitcell_base_array(design.design): """ Return an array of the x offsets of all the regular bits """ - return [self.cell_inst[0, col].lx() for col in range(self.column_size)] + offsets = [self.cell_inst[0, col].lx() for col in range(self.column_size)] + return offsets diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index c65de052..ad3421e5 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -260,5 +260,5 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): """ offsets = [] for inst in self.local_insts: - offsets.extend(inst.lx() + inst.mod.get_column_offsets()) + offsets.extend(inst.lx() + x for x in inst.mod.get_column_offsets()) return offsets diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index 792e4f8b..71e274b2 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -260,5 +260,6 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): Return an array of the x offsets of all the regular bits """ # must add the offset of the instance - return [self.bitcell_array_inst.lx() + x for x in self.bitcell_array.get_column_offsets()] + offsets = [self.bitcell_array_inst.lx() + x for x in self.bitcell_array.get_column_offsets()] + return offsets diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 2f5cf541..0571201d 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -37,7 +37,7 @@ class port_data(design.design): self.bit_offsets.append(i * bitcell.width) else: self.bit_offsets = bit_offsets - + if name == "": name = "port_data_{0}".format(self.port) super().__init__(name) @@ -187,9 +187,19 @@ class port_data(design.design): # Precharge will be shifted left if needed # Column offset is set to port so extra column can be on left or right # and mirroring happens correctly + + # Used for names/dimensions only + self.cell = factory.create(module_type="bitcell") + + if self.port == 0: + # Append an offset on the left + precharge_bit_offsets = [self.bit_offsets[0] - self.cell.width] + self.bit_offsets + else: + # Append an offset on the right + precharge_bit_offsets = self.bit_offsets + [self.bit_offsets[-1] + self.cell.width] self.precharge_array = factory.create(module_type="precharge_array", columns=self.num_cols + self.num_spare_cols + 1, - offsets=self.bit_offsets, + offsets=precharge_bit_offsets, bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port], column_offset=self.port - 1) @@ -231,6 +241,7 @@ class port_data(design.design): # RBLs don't get a write mask self.write_mask_and_array = factory.create(module_type="write_mask_and_array", columns=self.num_cols, + offsets=self.bit_offsets, word_size=self.word_size, write_size=self.write_size) self.add_mod(self.write_mask_and_array) @@ -423,21 +434,15 @@ class port_data(design.design): vertical_port_order.append(self.write_driver_array_inst) vertical_port_order.append(self.write_mask_and_array_inst) - # Add one column for the the RBL - if self.port==0: - x_offset = self.bitcell.width - else: - x_offset = 0 - vertical_port_offsets = 5 * [None] - self.width = x_offset + self.width = 0 self.height = 0 for i, p in enumerate(vertical_port_order): if p == None: continue self.height += (p.height + self.m2_gap) self.width = max(self.width, p.width) - vertical_port_offsets[i] = vector(x_offset, self.height) + vertical_port_offsets[i] = vector(0, self.height) # Reversed order self.write_mask_and_offset = vertical_port_offsets[4] @@ -445,9 +450,6 @@ class port_data(design.design): self.sense_amp_offset = vertical_port_offsets[2] self.column_mux_offset = vertical_port_offsets[1] self.precharge_offset = vertical_port_offsets[0] - # Shift the precharge left if port 0 - if self.precharge_offset and self.port == 0: - self.precharge_offset -= vector(x_offset, 0) def place_instances(self): """ Place the instances. """ diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index 10b9bba9..7f101ac9 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -118,7 +118,7 @@ class precharge_array(design.design): # Default to single spaced columns if not self.offsets: self.offsets = [n * self.pc_cell.width for n in range(self.columns)] - + for i, xoffset in enumerate(self.offsets): if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2: mirror = "MY" @@ -129,4 +129,5 @@ class precharge_array(design.design): offset = vector(tempx, 0) self.local_insts[i].place(offset=offset, mirror=mirror) - xoffset = xoffset + self.pc_cell.width + + diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 0702522c..f6b50f0c 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -321,7 +321,8 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # 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 - self.translate_all(self.bitcell_offset.scale(-1 - len(self.left_rbl), -1 - self.rbl[0])) + array_offset = self.bitcell_offset.scale(1 + len(self.left_rbl), 1 + self.rbl[0]) + self.translate_all(array_offset.scale(-1, -1)) self.add_layout_pins() @@ -347,8 +348,8 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): """ Return an array of the x offsets of all the regular bits """ - # This works because the instance of the module is placed at 0,0 - return self.bitcell_array.get_column_offsets() + offsets = [x + self.bitcell_array_inst.lx() for x in self.bitcell_array.get_column_offsets()] + return offsets def add_replica_columns(self): """ Add replica columns on left and right of array """ diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index e088df1d..932306da 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -6,12 +6,11 @@ # All rights reserved. # import design -from tech import drc from vector import vector from sram_factory import factory import debug from globals import OPTS -import logical_effort +from tech import cell_properties class sense_amp_array(design.design): @@ -29,6 +28,7 @@ class sense_amp_array(design.design): self.word_size = word_size self.words_per_row = words_per_row + self.columns = word_size * words_per_row self.offsets = offsets if not num_spare_cols: self.num_spare_cols = 0 @@ -69,16 +69,15 @@ class sense_amp_array(design.design): self.create_sense_amp_array() def create_layout(self): - self.height = self.amp.height - - if self.bitcell.width > self.amp.width: - self.width = self.bitcell.width * (self.word_size * self.words_per_row + self.num_spare_cols) - else: - self.width = self.amp.width * (self.word_size * self.words_per_row + self.num_spare_cols) self.place_sense_amp_array() + + self.height = self.amp.height + self.width = self.local_insts[-1].rx() + self.add_layout_pins() self.route_rails() + self.add_boundary() self.DRC_LVS() @@ -112,29 +111,32 @@ class sense_amp_array(design.design): self.en_name, "vdd", "gnd"]) def place_sense_amp_array(self): - from tech import cell_properties + if self.bitcell.width > self.amp.width: + self.amp_spacing = self.bitcell.width + else: + self.amp_spacing = self.amp.width + + if not self.offsets: + self.offsets = [] + for i in range(self.num_cols + self.num_spare_cols): + self.offsets.append(i * self.bitcell.width) - for i in range(0, self.row_size, self.words_per_row): - index = int(i / self.words_per_row) - xoffset = i * self.bitcell.width - - if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2: + for i, xoffset in enumerate(self.offsets[0:self.columns:self.words_per_row]): + if cell_properties.bitcell.mirror.y and (i * self.words_per_row + self.column_offset) % 2: mirror = "MY" - xoffset = xoffset + self.amp.width + xoffset = xoffset + self.amp_spacing else: mirror = "" amp_position = vector(xoffset, 0) - self.local_insts[index].place(offset=amp_position, mirror=mirror) + self.local_insts[i].place(offset=amp_position, mirror=mirror) # place spare sense amps (will share the same enable as regular sense amps) - for i in range(0, self.num_spare_cols): + for i, xoffset in enumerate(self.offsets[self.columns:]): index = self.word_size + i - xoffset = ((self.word_size * self.words_per_row) + i) * self.bitcell.width - - if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2: + if cell_properties.bitcell.mirror.y and (index + self.column_offset) % 2: mirror = "MY" - xoffset = xoffset + self.amp.width + xoffset = xoffset + self.amp_width else: mirror = "" diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index ea1dae36..1be0b378 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -117,14 +117,12 @@ class single_level_column_mux_array(design.design): "gnd"]) def place_array(self): - # Default to single spaced columns if not self.offsets: self.offsets = [n * self.mux.width for n in range(self.columns)] # For every column, add a pass gate for col_num, xoffset in enumerate(self.offsets[0:self.columns]): - xoffset = col_num * self.mux.width if cell_properties.bitcell.mirror.y and (col_num + self.column_offset) % 2: mirror = "MY" xoffset = xoffset + self.mux.width @@ -168,7 +166,7 @@ class single_level_column_mux_array(design.design): self.add_layout_pin(text="sel_{}".format(j), layer=self.sel_layer, offset=offset, - width=self.mux.width * self.columns) + width=self.mux_inst[-1].rx()) def add_vertical_poly_rail(self): """ Connect the poly to the address rails """ diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index b8d6a13d..3de81888 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -68,17 +68,10 @@ class write_driver_array(design.design): def create_layout(self): - if self.bitcell.width > self.driver.width: - self.width = (self.columns + self.num_spare_cols) * self.bitcell.width - self.width_regular_cols = self.columns * self.bitcell.width - self.single_col_width = self.bitcell.width - else: - self.width = (self.columns + self.num_spare_cols) * self.driver.width - self.width_regular_cols = self.columns * self.driver.width - self.single_col_width = self.driver.width - self.height = self.driver.height - self.place_write_array() + self.width = self.driver_insts[-1].rx() + self.width_regular_cols = self.driver_insts[-self.num_spare_cols].rx() + self.height = self.driver.height self.add_layout_pins() self.add_boundary() self.DRC_LVS() @@ -109,14 +102,14 @@ class write_driver_array(design.design): self.bitcell = factory.create(module_type="bitcell") def create_write_array(self): - self.driver_insts = {} + self.driver_insts = [] w = 0 windex=0 for i in range(0, self.columns, self.words_per_row): name = "write_driver{}".format(i) index = int(i / self.words_per_row) - self.driver_insts[index]=self.add_inst(name=name, - mod=self.driver) + self.driver_insts.append(self.add_inst(name=name, + mod=self.driver)) if self.write_size: self.connect_inst([self.data_name + "_{0}".format(index), @@ -148,8 +141,8 @@ class write_driver_array(design.design): else: offset = 1 name = "write_driver{}".format(self.columns + i) - self.driver_insts[index]=self.add_inst(name=name, - mod=self.driver) + self.driver_insts.append(self.add_inst(name=name, + mod=self.driver)) self.connect_inst([self.data_name + "_{0}".format(index), self.get_bl_name() + "_{0}".format(index), @@ -178,7 +171,6 @@ class write_driver_array(design.design): self.driver_insts[i].place(offset=base, mirror=mirror) # place spare write drivers (if spare columns are specified) - for i, xoffset in enumerate(self.offsets[self.columns:]): index = self.word_size + i