diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 1a16eed1..fa03a807 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -191,11 +191,17 @@ class bank(design.design): self.main_bitcell_array_left = self.bitcell_array.get_main_array_left() # Just past the dummy row and replica row self.main_bitcell_array_bottom = self.bitcell_array.get_main_array_bottom() - + self.compute_instance_port0_offsets() if len(self.all_ports)==2: self.compute_instance_port1_offsets() - + + def get_column_offsets(self): + """ + Return an array of the x offsets of all the regular bits + """ + return self.bitcell_array.get_column_offsets() + def compute_instance_port0_offsets(self): """ Compute the instance offsets for port0 on the left/bottom of the bank. @@ -355,14 +361,6 @@ class bank(design.design): def add_modules(self): """ Add all the modules using the class loader """ - - self.port_data = [] - for port in self.all_ports: - temp_pre = factory.create(module_type="port_data", - sram_config=self.sram_config, - port=port) - self.port_data.append(temp_pre) - self.add_mod(self.port_data[port]) self.port_address = factory.create(module_type="port_address", cols=self.num_cols + self.num_spare_cols, @@ -392,6 +390,15 @@ class bank(design.design): cols=self.num_cols + self.num_spare_cols, rows=self.num_rows) self.add_mod(self.bitcell_array) + + self.port_data = [] + 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()) + self.port_data.append(temp_pre) + self.add_mod(self.port_data[port]) if(self.num_banks > 1): self.bank_select = factory.create(module_type="bank_select") @@ -432,6 +439,7 @@ class bank(design.design): for port in self.all_ports: self.port_data_inst[port]=self.add_inst(name="port_data{}".format(port), mod=self.port_data[port]) + temp = [] temp.extend(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)]) temp.extend(self.bitcell_array.get_bitline_names(port)) diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 91363560..0fe03494 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -206,3 +206,9 @@ class bitcell_base_array(design.design): mirror=dir_key) yoffset += self.cell.height xoffset += self.cell.width + + def get_column_offsets(self): + """ + 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)] diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index 219f30ac..c65de052 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -253,4 +253,12 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): def get_main_array_right(self): return self.local_insts[-1].offset.x + self.local_mods[-1].get_main_array_right() - + + def get_column_offsets(self): + """ + Return an array of the x offsets of all the regular bits + """ + offsets = [] + for inst in self.local_insts: + offsets.extend(inst.lx() + inst.mod.get_column_offsets()) + return offsets diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index a2c32e81..792e4f8b 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -244,14 +244,21 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): self.add_path(out_pin.layer, [out_loc, mid_loc, in_loc]) def get_main_array_top(self): - return self.bitcell_array_inst.offset.y + self.bitcell_array.get_main_array_top() + return self.bitcell_array_inst.by() + self.bitcell_array.get_main_array_top() def get_main_array_bottom(self): - return self.bitcell_array_inst.offset.y + self.bitcell_array.get_main_array_bottom() + return self.bitcell_array_inst.by() + self.bitcell_array.get_main_array_bottom() def get_main_array_left(self): - return self.bitcell_array_inst.offset.x + self.bitcell_array.get_main_array_left() + return self.bitcell_array_inst.lx() + self.bitcell_array.get_main_array_left() def get_main_array_right(self): - return self.bitcell_array_inst.offset.x + self.bitcell_array.get_main_array_right() - + return self.bitcell_array_inst.lx() + self.bitcell_array.get_main_array_right() + + def get_column_offsets(self): + """ + 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()] + diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index a8e4bdb2..2f5cf541 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -18,7 +18,7 @@ class port_data(design.design): Port 0 always has the RBL on the left while port 1 is on the right. """ - def __init__(self, sram_config, port, name=""): + def __init__(self, sram_config, port, bit_offsets=None, name=""): sram_config.set_local_config(self) self.port = port @@ -30,6 +30,14 @@ class port_data(design.design): if self.num_spare_cols is None: self.num_spare_cols = 0 + if not bit_offsets: + bitcell = factory.create(module_type="bitcell") + self.bit_offsets = [] + for i in range(self.num_cols + self.num_spare_cols): + 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) @@ -181,6 +189,7 @@ class port_data(design.design): # and mirroring happens correctly self.precharge_array = factory.create(module_type="precharge_array", columns=self.num_cols + self.num_spare_cols + 1, + offsets=self.bit_offsets, bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port], column_offset=self.port - 1) @@ -190,6 +199,7 @@ class port_data(design.design): # RBLs don't get a sense amp self.sense_amp_array = factory.create(module_type="sense_amp_array", word_size=self.word_size, + offsets=self.bit_offsets, words_per_row=self.words_per_row, num_spare_cols=self.num_spare_cols) self.add_mod(self.sense_amp_array) @@ -201,6 +211,7 @@ class port_data(design.design): self.column_mux_array = factory.create(module_type="column_mux_array", columns=self.num_cols, word_size=self.word_size, + offsets=self.bit_offsets, bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port]) self.add_mod(self.column_mux_array) @@ -212,6 +223,7 @@ class port_data(design.design): self.write_driver_array = factory.create(module_type="write_driver_array", columns=self.num_cols, word_size=self.word_size, + offsets=self.bit_offsets, write_size=self.write_size, num_spare_cols=self.num_spare_cols) self.add_mod(self.write_driver_array) diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index 00fe9885..10b9bba9 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -10,7 +10,7 @@ import debug from vector import vector from sram_factory import factory from globals import OPTS -from tech import layer +from tech import cell_properties class precharge_array(design.design): @@ -19,12 +19,13 @@ class precharge_array(design.design): of bit line columns, height is the height of the bit-cell array. """ - def __init__(self, name, columns, size=1, bitcell_bl="bl", bitcell_br="br", column_offset=0): + def __init__(self, name, columns, offsets=None, size=1, bitcell_bl="bl", bitcell_br="br", column_offset=0): super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("cols: {0} size: {1} bl: {2} br: {3}".format(columns, size, bitcell_bl, bitcell_br)) self.columns = columns + self.offsets = offsets self.size = size self.bitcell_bl = bitcell_bl self.bitcell_br = bitcell_br @@ -62,10 +63,11 @@ class precharge_array(design.design): self.create_insts() def create_layout(self): - self.width = self.columns * self.pc_cell.width + self.place_insts() + + self.width = self.offsets[-1] + self.pc_cell.width self.height = self.pc_cell.height - self.place_insts() self.add_layout_pins() self.add_boundary() self.DRC_LVS() @@ -112,15 +114,18 @@ class precharge_array(design.design): def place_insts(self): """ Places precharge array by horizontally tiling the precharge cell""" - from tech import cell_properties - xoffset = 0 - for i in range(self.columns): - tempx = xoffset + + # 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" - tempx = tempx + self.pc_cell.width + tempx = xoffset + self.pc_cell.width else: mirror = "" + tempx = xoffset offset = vector(tempx, 0) self.local_insts[i].place(offset=offset, mirror=mirror) diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 404819c3..0702522c 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -342,7 +342,14 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def get_main_array_right(self): return self.bitcell_array_inst.rx() - + + def get_column_offsets(self): + """ + 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() + 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 6d0b85d2..e088df1d 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -20,7 +20,7 @@ class sense_amp_array(design.design): Dynamically generated sense amp array for all bitlines. """ - def __init__(self, name, word_size, words_per_row, num_spare_cols=None, column_offset=0): + def __init__(self, name, word_size, words_per_row, offsets=None, num_spare_cols=None, column_offset=0): super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) @@ -29,6 +29,7 @@ class sense_amp_array(design.design): self.word_size = word_size self.words_per_row = words_per_row + self.offsets = offsets if not num_spare_cols: self.num_spare_cols = 0 else: diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 267b2a6a..8a75ebea 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -11,7 +11,7 @@ from tech import layer, preferred_directions from vector import vector from sram_factory import factory from globals import OPTS -import logical_effort +from tech import cell_properties class single_level_column_mux_array(design.design): @@ -20,13 +20,14 @@ class single_level_column_mux_array(design.design): Array of column mux to read the bitlines through the 6T. """ - def __init__(self, name, columns, word_size, bitcell_bl="bl", bitcell_br="br", column_offset=0): + def __init__(self, name, columns, word_size, offsets=None, bitcell_bl="bl", bitcell_br="br", column_offset=0): super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("cols: {0} word_size: {1} bl: {2} br: {3}".format(columns, word_size, bitcell_bl, bitcell_br)) self.columns = columns self.word_size = word_size + self.offsets = offsets self.words_per_row = int(self.columns / self.word_size) self.bitcell_bl = bitcell_bl self.bitcell_br = bitcell_br @@ -116,9 +117,13 @@ class single_level_column_mux_array(design.design): "gnd"]) def place_array(self): - from tech import cell_properties + + # 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 in range(self.columns): + for col_num, xoffset in enumerate(self.offsets): xoffset = col_num * self.mux.width if cell_properties.bitcell.mirror.y and (col_num + self.column_offset) % 2: mirror = "MY" diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index b7bcd6b3..b8d6a13d 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -11,6 +11,7 @@ from tech import drc from sram_factory import factory from vector import vector from globals import OPTS +from tech import cell_properties class write_driver_array(design.design): @@ -19,7 +20,7 @@ class write_driver_array(design.design): Dynamically generated write driver array of all bitlines. """ - def __init__(self, name, columns, word_size, num_spare_cols=None, write_size=None, column_offset=0): + def __init__(self, name, columns, word_size, offsets=None, num_spare_cols=None, write_size=None, column_offset=0): super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) @@ -29,6 +30,7 @@ class write_driver_array(design.design): self.columns = columns self.word_size = word_size self.write_size = write_size + self.offsets = offsets self.column_offset = column_offset self.words_per_row = int(columns / word_size) if not num_spare_cols: @@ -155,30 +157,32 @@ class write_driver_array(design.design): self.en_name + "_{0}".format(i + offset), "vdd", "gnd"]) def place_write_array(self): - from tech import cell_properties if self.bitcell.width > self.driver.width: self.driver_spacing = self.bitcell.width else: self.driver_spacing = self.driver.width - for i in range(0, self.columns, self.words_per_row): - index = int(i / self.words_per_row) - xoffset = i * self.driver_spacing - if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2: + if not self.offsets: + self.offsets = [] + for i in range(self.columns + self.num_spare_cols): + self.offsets.append(i * self.driver_spacing) + + 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.driver.width else: mirror = "" base = vector(xoffset, 0) - self.driver_insts[index].place(offset=base, mirror=mirror) + self.driver_insts[i].place(offset=base, mirror=mirror) # place spare write drivers (if spare columns are specified) - for i in range(self.num_spare_cols): + + for i, xoffset in enumerate(self.offsets[self.columns:]): index = self.word_size + i - xoffset = (self.columns + i) * self.driver_spacing - - 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.driver.width else: diff --git a/compiler/modules/write_mask_and_array.py b/compiler/modules/write_mask_and_array.py index 04563209..e2048d3d 100644 --- a/compiler/modules/write_mask_and_array.py +++ b/compiler/modules/write_mask_and_array.py @@ -18,7 +18,7 @@ class write_mask_and_array(design.design): The write mask AND array goes between the write driver array and the sense amp array. """ - def __init__(self, name, columns, word_size, write_size, column_offset=0): + def __init__(self, name, columns, word_size, write_size, offsets=None, column_offset=0): super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("columns: {0}".format(columns)) @@ -28,6 +28,7 @@ class write_mask_and_array(design.design): self.columns = columns self.word_size = word_size self.write_size = write_size + self.offsets = offsets self.column_offset = column_offset self.words_per_row = int(columns / word_size) self.num_wmasks = int(word_size / write_size) @@ -90,12 +91,17 @@ class write_mask_and_array(design.design): debug.check(self.wmask_en_len >= self.and2.width, "Write mask AND is wider than the corresponding write drivers {0} vs {1}.".format(self.and2.width, self.wmask_en_len)) - - self.width = self.bitcell.width * self.columns + if not self.offsets: + self.offsets = [] + for i in range(self.columns): + self.offsets.append(i * self.driver_spacing) + + self.width = self.offsets[-1] + self.driver_spacing self.height = self.and2.height + write_bits = self.columns / self.num_wmasks for i in range(self.num_wmasks): - base = vector(i * self.wmask_en_len, 0) + base = vector(self.offsets[int(i * write_bits)], 0) self.and2_insts[i].place(base) def add_layout_pins(self):