From 8909ad71652527418b31bf1a6430709fd3bd15ec Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 11 Sep 2020 15:36:22 -0700 Subject: [PATCH] Update modules to use variable bit offsets. Bitcell arrays can return the bit offsets. Port data and submodules can use offsets for spacing. Default spacing for port data if no offsets given. --- compiler/modules/bank.py | 28 ++++++++++++------- compiler/modules/bitcell_base_array.py | 6 ++++ compiler/modules/global_bitcell_array.py | 10 ++++++- compiler/modules/local_bitcell_array.py | 17 +++++++---- compiler/modules/port_data.py | 14 +++++++++- compiler/modules/precharge_array.py | 23 +++++++++------ compiler/modules/replica_bitcell_array.py | 9 +++++- compiler/modules/sense_amp_array.py | 3 +- .../modules/single_level_column_mux_array.py | 13 ++++++--- compiler/modules/write_driver_array.py | 26 +++++++++-------- compiler/modules/write_mask_and_array.py | 14 +++++++--- 11 files changed, 116 insertions(+), 47 deletions(-) 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):