From 5c263e0001caf6311477030ab91e0ea877e12728 Mon Sep 17 00:00:00 2001 From: jcirimel Date: Wed, 23 Sep 2020 06:24:52 -0700 Subject: [PATCH] rep col done w/o power pins --- compiler/custom/s8_col_end.py | 7 +- compiler/modules/replica_bitcell_array.py | 48 +++---- compiler/modules/replica_column.py | 164 +++++++++++++--------- compiler/tests/missing_pin.gds | Bin 7970 -> 3328 bytes compiler/tests/sram_1b_16_1rw_sky130.log | Bin 182 -> 96 bytes missing_pin.gds | Bin 7970 -> 3328 bytes sram_1b_16_1rw_sky130.log | 4 + 7 files changed, 135 insertions(+), 88 deletions(-) diff --git a/compiler/custom/s8_col_end.py b/compiler/custom/s8_col_end.py index f35d691a..a6961027 100644 --- a/compiler/custom/s8_col_end.py +++ b/compiler/custom/s8_col_end.py @@ -22,18 +22,23 @@ class s8_col_end(design.design): if version == "colend": self.name = "s8sram16x16_colend" + structure = "s8sram16x16_colend\x00" elif version == "colend_p_cent": self.name = "s8sram16x16_colend_p_cent" + structure = "s8sram16x16_colend_p_cent\x00" elif version == "colenda": self.name = "s8sram16x16_colenda" + structure = "s8sram16x16_colenda\x00" elif version == "colenda_p_cent": self.name = "s8sram16x16_colenda_p_cent" + structure = "s8sram16x16_colenda_p_cent" else: debug.error("Invalid type for col_end", -1) design.design.__init__(self, name=self.name) (self.width, self.height) = utils.get_libcell_size(self.name, GDS["unit"], - layer["mem"]) + layer["mem"], + structure) pin_map = utils.get_libcell_pins(pin_names, self.name, GDS["unit"]) diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 4a097402..5589e18b 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -45,11 +45,12 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): debug.check(sum(rbl) <= len(self.all_ports), "Invalid number of RBLs for port configuration.") + if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - # Two dummy rows plus replica even if we don't add the column - self.extra_rows = 2 + sum(rbl) - # Two dummy cols plus replica if we add the column - self.extra_cols = 2 + self.add_left_rbl + self.add_right_rbl + # Two dummy rows plus replica even if we don't add the column + self.extra_rows = 2 + sum(rbl) + # Two dummy cols plus replica if we add the column + self.extra_cols = 2 + self.add_left_rbl + self.add_right_rbl self.create_netlist() if not OPTS.netlist_only: @@ -115,31 +116,30 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): column_offset=column_offset, replica_bit=replica_bit) self.add_mod(self.replica_columns[bit]) - - # Dummy row - self.dummy_row = factory.create(module_type="dummy_array", - cols=self.column_size, - rows=1, - # dummy column + left replica column - column_offset=1 + self.add_left_rbl, - mirror=0) - self.add_mod(self.dummy_row) - - # If there are bitcell end caps, replace the dummy cells on the edge of the bitcell array with end caps. + # If there are bitcell end caps, replace the dummy cells on the edge of the bitcell array with end caps. try: end_caps_enabled = cell_properties.bitcell.end_caps except AttributeError: end_caps_enabled = False + if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): + # Dummy row + self.dummy_row = factory.create(module_type="dummy_array", + cols=self.column_size, + rows=1, + # dummy column + left replica column + column_offset=1 + self.add_left_rbl, + mirror=0) + self.add_mod(self.dummy_row) - # Dummy Row or Col Cap, depending on bitcell array properties - col_cap_module_type = ("col_cap_array" if end_caps_enabled else "dummy_array") - self.col_cap = factory.create(module_type=col_cap_module_type, - cols=self.column_size, - rows=1, - # dummy column + left replica column(s) - column_offset=1 + self.add_left_rbl, - mirror=0) - self.add_mod(self.col_cap) + # Dummy Row or Col Cap, depending on bitcell array properties + col_cap_module_type = ("col_cap_array" if end_caps_enabled else "dummy_array") + self.col_cap = factory.create(module_type=col_cap_module_type, + cols=self.column_size, + rows=1, + # dummy column + left replica column(s) + column_offset=1 + self.add_left_rbl, + mirror=0) + self.add_mod(self.col_cap) # Dummy Col or Row Cap, depending on bitcell array properties row_cap_module_type = ("row_cap_array" if end_caps_enabled else "dummy_array") diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index f1f6eebb..78ec56fd 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -50,8 +50,6 @@ class replica_column(design.design): self.create_instances() def create_layout(self): - self.height = self.total_size * self.cell.height - self.width = self.cell.width self.place_instances() self.add_layout_pins() @@ -99,6 +97,7 @@ class replica_column(design.design): else: self.replica_cell = factory.create(module_type="s8_bitcell", version = "opt1") self.add_mod(self.replica_cell) + self.cell = self.replica_cell self.replica_cell2 = factory.create(module_type="s8_bitcell", version = "opt1a") self.add_mod(self.replica_cell2) @@ -167,82 +166,121 @@ class replica_column(design.design): custom_replica_column_arrangement(self) def place_instances(self): - from tech import cell_properties - # Flip the mirrors if we have an odd number of replica+dummy rows at the bottom - # so that we will start with mirroring rather than not mirroring - rbl_offset = (self.left_rbl + 1) %2 + if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - # if our bitcells are mirrored on the y axis, check if we are in global - # column that needs to be flipped. - dir_y = False - xoffset = 0 - if cell_properties.bitcell.mirror.y and self.column_offset % 2: - dir_y = True - xoffset = self.replica_cell.width + # Flip the mirrors if we have an odd number of replica+dummy rows at the bottom + # so that we will start with mirroring rather than not mirroring + rbl_offset = (self.left_rbl + 1) %2 - for row in range(self.total_size): - # name = "bit_r{0}_{1}".format(row, "rbl") - dir_x = cell_properties.bitcell.mirror.x and (row + rbl_offset) % 2 + # if our bitcells are mirrored on the y axis, check if we are in global + # column that needs to be flipped. + dir_y = False + xoffset = 0 + if cell_properties.bitcell.mirror.y and self.column_offset % 2: + dir_y = True + xoffset = self.replica_cell.width - offset = vector(xoffset, self.cell.height * (row + (row + rbl_offset) % 2)) + for row in range(self.total_size): + # name = "bit_r{0}_{1}".format(row, "rbl") + dir_x = cell_properties.bitcell.mirror.x and (row + rbl_offset) % 2 - if dir_x and dir_y: - dir_key = "XY" - elif dir_x: - dir_key = "MX" - elif dir_y: - dir_key = "MY" - else: - dir_key = "" + offset = vector(xoffset, self.cell.height * (row + (row + rbl_offset) % 2)) - self.cell_inst[row].place(offset=offset, - mirror=dir_key) + if dir_x and dir_y: + dir_key = "XY" + elif dir_x: + dir_key = "MX" + elif dir_y: + dir_key = "MY" + else: + dir_key = "" + + self.cell_inst[row].place(offset=offset, + mirror=dir_key) + else: + from tech import custom_replica_cell_placement + custom_replica_cell_placement(self) def add_layout_pins(self): """ Add the layout pins """ + if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): + for port in self.all_ports: + bl_pin = self.cell_inst[0].get_pin(self.cell.get_bl_name(port)) + self.add_layout_pin(text="bl_{0}_{1}".format(port, 0), + layer=bl_pin.layer, + offset=bl_pin.ll().scale(1, 0), + width=bl_pin.width(), + height=self.height) + bl_pin = self.cell_inst[0].get_pin(self.cell.get_br_name(port)) + self.add_layout_pin(text="br_{0}_{1}".format(port, 0), + layer=bl_pin.layer, + offset=bl_pin.ll().scale(1, 0), + width=bl_pin.width(), + height=self.height) - for port in self.all_ports: - bl_pin = self.cell_inst[0].get_pin(self.cell.get_bl_name(port)) - self.add_layout_pin(text="bl_{0}_{1}".format(port, 0), - layer=bl_pin.layer, - offset=bl_pin.ll().scale(1, 0), - width=bl_pin.width(), - height=self.height) - bl_pin = self.cell_inst[0].get_pin(self.cell.get_br_name(port)) - self.add_layout_pin(text="br_{0}_{1}".format(port, 0), - layer=bl_pin.layer, - offset=bl_pin.ll().scale(1, 0), - width=bl_pin.width(), - height=self.height) + try: + end_caps_enabled = cell_properties.bitcell.end_caps + except AttributeError: + end_caps_enabled = False + + if end_caps_enabled: + row_range_max = self.total_size - 1 + row_range_min = 1 + else: + row_range_max = self.total_size + row_range_min = 0 + + for port in self.all_ports: + for row in range(row_range_min, row_range_max): + wl_pin = self.cell_inst[row].get_pin(self.cell.get_wl_name(port)) + self.add_layout_pin(text="wl_{0}_{1}".format(port, row), + layer=wl_pin.layer, + offset=wl_pin.ll().scale(0, 1), + width=self.width, + height=wl_pin.height()) + + # Supplies are only connected in the ends + for (index, inst) in self.cell_inst.items(): + for pin_name in ["vdd", "gnd"]: + if inst in [self.cell_inst[0], self.cell_inst[self.total_size - 1]]: + self.copy_power_pins(inst, pin_name) + else: + self.copy_layout_pin(inst, pin_name) + else: + for port in self.all_ports: + bl_pin = self.cell_inst[2].get_pin(self.cell.get_bl_name(port)) + self.add_layout_pin(text="bl_{0}_{1}".format(port, 0), + layer=bl_pin.layer, + offset=bl_pin.ll().scale(1, 0), + width=bl_pin.width(), + height=self.height) + bl_pin = self.cell_inst[2].get_pin(self.cell.get_br_name(port)) + self.add_layout_pin(text="br_{0}_{1}".format(port, 0), + layer=bl_pin.layer, + offset=bl_pin.ll().scale(1, 0), + width=bl_pin.width(), + height=self.height) - try: - end_caps_enabled = cell_properties.bitcell.end_caps - except AttributeError: - end_caps_enabled = False - if end_caps_enabled: row_range_max = self.total_size - 1 row_range_min = 1 - else: - row_range_max = self.total_size - row_range_min = 0 - for port in self.all_ports: - for row in range(row_range_min, row_range_max): - wl_pin = self.cell_inst[row].get_pin(self.cell.get_wl_name(port)) - self.add_layout_pin(text="wl_{0}_{1}".format(port, row), - layer=wl_pin.layer, - offset=wl_pin.ll().scale(0, 1), - width=self.width, - height=wl_pin.height()) + for port in self.all_ports: + for row in range(row_range_min, row_range_max): + wl_pin = self.cell_inst[row].get_pin(self.cell.get_wl_name(port)) + self.add_layout_pin(text="wl_{0}_{1}".format(port, row), + layer=wl_pin.layer, + offset=wl_pin.ll().scale(0, 1), + width=self.width, + height=wl_pin.height()) - # Supplies are only connected in the ends - for (index, inst) in self.cell_inst.items(): - for pin_name in ["vdd", "gnd"]: - if inst in [self.cell_inst[0], self.cell_inst[self.total_size - 1]]: - self.copy_power_pins(inst, pin_name) - else: - self.copy_layout_pin(inst, pin_name) + # # Supplies are only connected in the ends + # for (index, inst) in self.cell_inst.items(): + # for pin_name in ["vdd", "gnd"]: + # if inst in [self.cell_inst[0], self.cell_inst[self.total_size - 1]]: + # self.copy_power_pins(inst, pin_name) + # else: + # self.copy_layout_pin(inst, pin_name) def get_bitline_names(self, port=None): if port == None: diff --git a/compiler/tests/missing_pin.gds b/compiler/tests/missing_pin.gds index 15ea40c50a4284f1df1302b36b90da9b488cc8b3..25df96f6f8225f45a3de16bfacd9df384fba6796 100644 GIT binary patch literal 3328 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 diff --git a/missing_pin.gds b/missing_pin.gds index 15ea40c50a4284f1df1302b36b90da9b488cc8b3..25df96f6f8225f45a3de16bfacd9df384fba6796 100644 GIT binary patch literal 3328 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