From 3648401e674f5e0a894f20110b6a8132f1474026 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 8 Oct 2020 16:58:19 -0700 Subject: [PATCH 1/6] Remove another boundary subcell --- compiler/custom/s8_row_end.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/compiler/custom/s8_row_end.py b/compiler/custom/s8_row_end.py index d02ca709..e413ef40 100644 --- a/compiler/custom/s8_row_end.py +++ b/compiler/custom/s8_row_end.py @@ -9,16 +9,14 @@ import debug import design import utils -from globals import OPTS -from tech import parameter, drc, layer, GDS +from tech import layer, GDS + class s8_row_end(design.design): - def __init__(self, version, name=""): super().__init__(name) pin_names = ["wl", "vpwr"] - type_list = ["OUTPUT", "POWER"] if version == "rowend": self.name = "s8sram16x16_rowend" @@ -28,11 +26,9 @@ class s8_row_end(design.design): debug.error("Invalid type for row_end", -1) design.design.__init__(self, name=self.name) (self.width, self.height) = utils.get_libcell_size(self.name, - GDS["unit"], - layer["mem"], - "s8sram16x16_rowend_ce\x00") + GDS["unit"], + layer["mem"]) self.pin_map = utils.get_libcell_pins(pin_names, self.name, GDS["unit"]) - self.add_pin("wl", "OUTPUT") self.add_pin("vpwr", "POWER") From c3d6be27bef0869060b548eb96cfdeb15bec2a89 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 8 Oct 2020 16:58:38 -0700 Subject: [PATCH 2/6] Fix argument name bug for remove wordlines --- compiler/modules/bitcell_base_array.py | 4 ++-- compiler/modules/replica_column.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 71225c2c..244a9928 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -56,8 +56,8 @@ class bitcell_base_array(design.design): # def get_all_wordline_names(self, prefix=""): # return [prefix + x for x in self.all_wordline_names] - def create_all_wordline_names(self, num_remove_wordline=0): - for row in range(self.row_size - num_remove_wordline): + def create_all_wordline_names(self, remove_num_wordlines=0): + for row in range(self.row_size - remove_num_wordlines): for port in self.all_ports: if not cell_properties.compare_ports(cell_properties.bitcell.split_wl): self.wordline_names[port].append("wl_{0}_{1}".format(port, row)) diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index 58939ad1..82ba1340 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -67,7 +67,7 @@ class replica_column(bitcell_base_array): try: if cell_properties.bitcell.end_caps: # remove 2 wordlines to account for top/bot - self.create_all_wordline_names(num_remove_wordlines=2) + self.create_all_wordline_names(remove_num_wordlines=2) else: self.create_all_wordline_names() except AttributeError: From 05667d784f64fc32860ae32fed90c28427e651c4 Mon Sep 17 00:00:00 2001 From: jcirimel Date: Tue, 13 Oct 2020 04:48:10 -0700 Subject: [PATCH 3/6] move sky130 specific stuff to tech module lib --- compiler/custom/s8_bitcell.py | 103 -------- compiler/custom/s8_col_cap_array.py | 137 ----------- compiler/custom/s8_col_end.py | 37 --- compiler/custom/s8_corner.py | 34 --- compiler/custom/s8_dummy_bitcell.py | 52 ---- compiler/custom/s8_internal.py | 32 --- compiler/custom/s8_replica_bitcell.py | 81 ------ compiler/custom/s8_row_cap_array.py | 162 ------------ compiler/custom/s8_row_end.py | 34 --- compiler/modules/bitcell_array.py | 30 +-- compiler/modules/bitcell_base_array.py | 87 +++---- compiler/modules/dummy_array.py | 45 +--- compiler/modules/replica_bitcell_array.py | 284 ++++++++-------------- compiler/modules/replica_column.py | 274 ++++++++------------- 14 files changed, 256 insertions(+), 1136 deletions(-) delete mode 100644 compiler/custom/s8_bitcell.py delete mode 100644 compiler/custom/s8_col_cap_array.py delete mode 100644 compiler/custom/s8_col_end.py delete mode 100644 compiler/custom/s8_corner.py delete mode 100644 compiler/custom/s8_dummy_bitcell.py delete mode 100644 compiler/custom/s8_internal.py delete mode 100644 compiler/custom/s8_replica_bitcell.py delete mode 100644 compiler/custom/s8_row_cap_array.py delete mode 100644 compiler/custom/s8_row_end.py diff --git a/compiler/custom/s8_bitcell.py b/compiler/custom/s8_bitcell.py deleted file mode 100644 index 4746ca57..00000000 --- a/compiler/custom/s8_bitcell.py +++ /dev/null @@ -1,103 +0,0 @@ -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2019 Regents of the University of California and The Board -# of Regents for the Oklahoma Agricultural and Mechanical College -# (acting for and on behalf of Oklahoma State University) -# All rights reserved. -# -import debug -import utils -from tech import GDS, layer -from tech import cell_properties as props -import bitcell_base - - -class s8_bitcell(bitcell_base.bitcell_base): - """ - A single bit cell (6T, 8T, etc.) This module implements the - single memory cell used in the design. It is a hand-made cell, so - the layout and netlist should be available in the technology - library. - """ - - # If we have a split WL bitcell, if not be backwards - # compatible in the tech file - - if props.compare_ports(props.bitcell.split_wl): - pin_names = ["bl0", "bl1", "wl0", "wl1", "vpwr", "vgnd"] - type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"] - else: - pin_names = [props.bitcell.cell_s8_6t.pin.bl, - props.bitcell.cell_s8_6t.pin.br, - props.bitcell.cell_s8_6t.pin.wl, - "vpwr", - "vgnd"] - type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] - storage_nets = ['Q', 'Q_bar'] - - def __init__(self, version, name=""): - # Ignore the name argument - - if version == "opt1": - self.name = "s8sram_cell_opt1" - elif version == "opt1a": - self.name = "s8sram_cell_opt1a" - - bitcell_base.bitcell_base.__init__(self, self.name) - debug.info(2, "Create bitcell") - - self.pin_map = utils.get_libcell_pins(self.pin_names, self.name, GDS["unit"]) - - self.add_pin_types(self.type_list) - self.nets_match = self.do_nets_exist(self.storage_nets) - - (self.width, self.height) = utils.get_libcell_size(self.name, - GDS["unit"], - layer["mem"]) - - def get_all_wl_names(self): - """ Creates a list of all wordline pin names """ - if props.compare_ports(props.bitcell.split_wl): - row_pins = ["wl0", "wl1"] - else: - row_pins = [props.bitcell.cell_s8_6t.pin.wl] - return row_pins - - def get_all_bitline_names(self): - """ Creates a list of all bitline pin names (both bl and br) """ - pin = props.bitcell.cell_s8_6t.pin - column_pins = [pin.bl, pin.br] - return column_pins - - def get_all_bl_names(self): - """ Creates a list of all bl pins names """ - return [props.bitcell.cell_s8_6t.pin.bl] - - def get_all_br_names(self): - """ Creates a list of all br pins names """ - return [props.bitcell.cell_s8_6t.pin.br] - - def get_bl_name(self, port=0): - """Get bl name""" - debug.check(port == 0, "One port for bitcell only.") - return props.bitcell.cell_s8_6t.pin.bl - - def get_br_name(self, port=0): - """Get bl name""" - debug.check(port == 0, "One port for bitcell only.") - return props.bitcell.cell_s8_6t.pin.br - - def get_wl_name(self, port=0): - """Get wl name""" - if props.compare_ports(props.bitcell.split_wl): - return "wl{}".format(port) - else: - debug.check(port == 0, "One port for bitcell only.") - return props.bitcell.cell_s8_6t.pin.wl - - def build_graph(self, graph, inst_name, port_nets): - """ - Adds edges based on inputs/outputs. - Overrides base class function. - """ - self.add_graph_edges(graph, port_nets) diff --git a/compiler/custom/s8_col_cap_array.py b/compiler/custom/s8_col_cap_array.py deleted file mode 100644 index 3fb00a20..00000000 --- a/compiler/custom/s8_col_cap_array.py +++ /dev/null @@ -1,137 +0,0 @@ -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2019 Regents of the University of California -# All rights reserved. -# -import design -from sram_factory import factory -from globals import OPTS -from tech import cell_properties - - -class s8_col_cap_array(design.design): - """ - Generate a dummy row/column for the replica array. - """ - def __init__(self, rows, cols, location, column_offset=0, mirror=0, name=""): - super().__init__(name) - self.rows = rows - self.cols = cols - self.location = location - self.column_offset = column_offset - self.mirror = mirror - self.no_instances = True - self.all_wordline_names = [] - self.create_netlist() - if not OPTS.netlist_only: - self.create_layout() - - def create_netlist(self): - """ Create and connect the netlist """ - self.add_modules() - self.add_pins() - self.create_instances() - - def create_layout(self): - - self.place_array("col_cap_r{0}_c{1}", self.mirror) - self.add_layout_pins() - self.add_boundary() - self.DRC_LVS() - - def add_modules(self): - """ Add the modules used in this design """ - if self.location == "top": - self.colend1 = factory.create(module_type="s8_col_end", version = "colend") - self.add_mod(self.colend1) - self.colend2 = factory.create(module_type="s8_col_end", version = "colend_p_cent") - self.add_mod(self.colend2) - elif self.location == "bottom": - self.colend1 = factory.create(module_type="s8_col_end", version = "colenda") - self.add_mod(self.colend1) - self.colend2 = factory.create(module_type="s8_col_end", version = "colenda_p_cent") - self.add_mod(self.colend2) - - self.cell = factory.create(module_type="s8_bitcell", version = "opt1") - - def create_instances(self): - """ Create the module instances used in this design """ - self.cell_inst = {} - self.array_layout = [] - alternate_bitcell = 0 - for col in range((self.cols * 2 )-1): - row_layout = [] - name="rca_{0}".format(col) - # Top/bottom cell are always dummy cells. - # Regular array cells are replica cells (>left_rbl and left_rbl and 0): - - if alternate_bitcell == 0: - row_layout.append(self.rowend1) - self.cell_inst[row]=self.add_inst(name=name, mod=self.rowend1) - self.connect_inst(["wl_0_{}".format(row-1), "vpwr"]) - alternate_bitcell = 1 - - else: - row_layout.append(self.rowend2) - self.cell_inst[row]=self.add_inst(name=name,mod=self.rowend2) - self.connect_inst(["wl_0_{}".format(row-1), "vpwr"]) - alternate_bitcell = 0 - - elif (row == 0): - row_layout.append(self.bottom_corner) - self.cell_inst[row]=self.add_inst(name=name, mod=self.bottom_corner) - self.connect_inst([]) - - elif (row == self.rows - 1): - row_layout.append(self.top_corner) - self.cell_inst[row]=self.add_inst(name=name, mod=self.top_corner) - self.connect_inst([]) - - - self.array_layout.append(row_layout) - - - def get_bitcell_pins(self, row, col): - """ - Creates a list of connections in the bitcell, - indexed by column and row, for instance use in bitcell_array - """ - - pin_name = cell_properties.bitcell.cell_1rw1r.pin - bitcell_pins = ["{0}_{1}".format(pin_name.wl0, row), - "{0}_{1}".format(pin_name.wl1, row), - "gnd"] - - return bitcell_pins - - def place_array(self, name_template, row_offset=0): - self.width = 0 - self.height = 0 - - for inst in self.insts: - self.height += inst.height - if inst.width > self.width: - self.width = inst.width - yoffset = 0.0 - for row in range(0, len(self.array_layout)): - xoffset = 0.0 - - for col in range(0, len(self.array_layout[row])): - inst = self.insts[col + row*len(self.array_layout[row])] - inst.place(offset=[xoffset, yoffset]) - xoffset += inst.width - yoffset += inst.height - - - - def add_pins(self): - for row in range(self.rows - 2): - for port in self.all_ports: - self.add_pin("wl_{}_{}".format(port, row), "OUTPUT") - self.add_pin("vpwr", "POWER") - self.add_pin("vgnd", "GROUND") - - def add_layout_pins(self): - """ Add the layout pins """ - if self.column_offset == 0: - row_list = self.cell.get_all_wl_names() - - for row in range(1, self.rows-1): - if row > 0 and row < self.rows: - for cell_row in row_list: - wl_pin = self.cell_inst[row].get_pin(cell_row) - self.add_layout_pin(text=cell_row + "_0_{0}".format(row), - layer=wl_pin.layer, - offset=wl_pin.ll().scale(0, 1), - width=self.width, - height=wl_pin.height()) - - # Add vdd/gnd via stacks - for row in range(1, self.rows): - inst = self.cell_inst[row] - for pin_name in ["vpwr", "vgnd"]: - for pin in inst.get_pins(pin_name): - self.add_power_pin(name=pin.name, - loc=pin.center(), - start_layer=pin.layer) - diff --git a/compiler/custom/s8_row_end.py b/compiler/custom/s8_row_end.py deleted file mode 100644 index e413ef40..00000000 --- a/compiler/custom/s8_row_end.py +++ /dev/null @@ -1,34 +0,0 @@ -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2019 Regents of the University of California and The Board -# of Regents for the Oklahoma Agricultural and Mechanical College -# (acting for and on behalf of Oklahoma State University) -# All rights reserved. -# - -import debug -import design -import utils -from tech import layer, GDS - - -class s8_row_end(design.design): - - def __init__(self, version, name=""): - super().__init__(name) - pin_names = ["wl", "vpwr"] - - if version == "rowend": - self.name = "s8sram16x16_rowend" - elif version == "rowenda": - self.name = "s8sram16x16_rowenda" - else: - debug.error("Invalid type for row_end", -1) - design.design.__init__(self, name=self.name) - (self.width, self.height) = utils.get_libcell_size(self.name, - GDS["unit"], - layer["mem"]) - self.pin_map = utils.get_libcell_pins(pin_names, self.name, GDS["unit"]) - - self.add_pin("wl", "OUTPUT") - self.add_pin("vpwr", "POWER") diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 0a334621..6bd290a2 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -7,7 +7,6 @@ # import debug from bitcell_base_array import bitcell_base_array -from s8_corner import s8_corner from tech import drc, spice from tech import cell_properties as props from globals import OPTS @@ -54,31 +53,18 @@ class bitcell_array(bitcell_base_array): def add_modules(self): """ Add the modules used in this design """ - if not props.compare_ports(props.bitcell_array.use_custom_cell_arrangement): - self.cell = factory.create(module_type="bitcell") - self.add_mod(self.cell) - - else: - self.cell = factory.create(module_type="s8_bitcell", version = "opt1") - self.add_mod(self.cell) - self.add_mod(factory.create(module_type="s8_bitcell", version = "opt1a")) - - self.add_mod(factory.create(module_type="s8_internal", version = "wlstrap")) - self.add_mod(factory.create(module_type="s8_internal", version = "wlstrap_p")) + self.cell = factory.create(module_type="bitcell") + self.add_mod(self.cell) def create_instances(self): """ Create the module instances used in this design """ self.cell_inst = {} - if not props.compare_ports(props.bitcell_array.use_custom_cell_arrangement): - for col in range(self.column_size): - for row in range(self.row_size): - name = "bit_r{0}_c{1}".format(row, col) - self.cell_inst[row, col]=self.add_inst(name=name, - mod=self.cell) - self.connect_inst(self.get_bitcell_pins(row, col)) - else: - from tech import custom_cell_arrangement - custom_cell_arrangement(self) + for col in range(self.column_size): + for row in range(self.row_size): + name = "bit_r{0}_c{1}".format(row, col) + self.cell_inst[row, col]=self.add_inst(name=name, + mod=self.cell) + self.connect_inst(self.get_bitcell_pins(row, col)) def analytical_power(self, corner, load): """Power of Bitcell array and bitline in nW.""" diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 244a9928..90eb7910 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -25,13 +25,8 @@ class bitcell_base_array(design.design): self.column_offset = column_offset # Bitcell for port names only - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - self.cell = factory.create(module_type="bitcell") - else: - self.cell = factory.create(module_type="s8_bitcell", version="opt1") - self.cell2 = factory.create(module_type="s8_bitcell", version="opt1a") - self.strap = factory.create(module_type="s8_internal", version="wlstrap") - self.strap2 = factory.create(module_type="s8_internal", version="wlstrap_p") + self.cell = factory.create(module_type="bitcell") + self.wordline_names = [[] for port in self.all_ports] self.all_wordline_names = [] @@ -72,12 +67,9 @@ class bitcell_base_array(design.design): self.add_pin(bl_name, "INOUT") for wl_name in self.get_wordline_names(): self.add_pin(wl_name, "INPUT") - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - self.add_pin("vdd", "POWER") - self.add_pin("gnd", "GROUND") - else: - self.add_pin("vpwr", "POWER") - self.add_pin("vgnd", "GROUND") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + def get_bitcell_pins(self, row, col): """ Creates a list of connections in the bitcell, @@ -173,24 +165,13 @@ class bitcell_base_array(design.design): width=self.width, height=wl_pin.height()) - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): + # Copy a vdd/gnd layout pin from every cell + for row in range(self.row_size): + for col in range(self.column_size): + inst = self.cell_inst[row, col] + for pin_name in ["vdd", "gnd"]: + self.copy_layout_pin(inst, pin_name) - # Copy a vdd/gnd layout pin from every cell - for row in range(self.row_size): - for col in range(self.column_size): - inst = self.cell_inst[row, col] - for pin_name in ["vdd", "gnd"]: - self.copy_layout_pin(inst, pin_name) - else: - - - # Copy a vdd/gnd layout pin from every cell - for row in range(self.row_size): - for col in range(self.column_size): - inst = self.cell_inst[row, col] - for pin_name in ["vpwr", "vgnd"]: - - self.copy_layout_pin(inst, pin_name) def _adjust_x_offset(self, xoffset, col, col_offset): tempx = xoffset dir_y = False @@ -210,35 +191,31 @@ class bitcell_base_array(design.design): return (tempy, dir_x) def place_array(self, name_template, row_offset=0): - # We increase it by a well enclosure so the precharges don't overlap our wells - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - self.height = self.row_size * self.cell.height - self.width = self.column_size * self.cell.width + # We increase it by a well enclosure so the precharges don't overlap our wells + self.height = self.row_size * self.cell.height + self.width = self.column_size * self.cell.width - xoffset = 0.0 - for col in range(self.column_size): - yoffset = 0.0 - tempx, dir_y = self._adjust_x_offset(xoffset, col, self.column_offset) + xoffset = 0.0 + for col in range(self.column_size): + yoffset = 0.0 + tempx, dir_y = self._adjust_x_offset(xoffset, col, self.column_offset) - for row in range(self.row_size): - tempy, dir_x = self._adjust_y_offset(yoffset, row, row_offset) + for row in range(self.row_size): + tempy, dir_x = self._adjust_y_offset(yoffset, row, row_offset) - if dir_x and dir_y: - dir_key = "XY" - elif dir_x: - dir_key = "MX" - elif dir_y: - dir_key = "MY" - else: - 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, col].place(offset=[tempx, tempy], - mirror=dir_key) - yoffset += self.cell.height - xoffset += self.cell.width - else: - from tech import custom_cell_placement - custom_cell_placement(self) + self.cell_inst[row, col].place(offset=[tempx, tempy], + mirror=dir_key) + yoffset += self.cell.height + xoffset += self.cell.width def get_column_offsets(self): """ diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py index 3a7a2ec0..399073d0 100644 --- a/compiler/modules/dummy_array.py +++ b/compiler/modules/dummy_array.py @@ -45,31 +45,19 @@ class dummy_array(bitcell_base_array): def add_modules(self): """ Add the modules used in this design """ - if not props.compare_ports(props.bitcell_array.use_custom_cell_arrangement): - self.dummy_cell = factory.create(module_type="dummy_{}".format(OPTS.bitcell)) - self.cell = factory.create(module_type="bitcell") - else: - self.dummy_cell = factory.create(module_type="s8_bitcell", version = "opt1") - self.dummy_cell2 = factory.create(module_type="s8_bitcell", version = "opt1a") - self.add_mod(factory.create(module_type="s8_internal", version = "wlstrap")) - self.add_mod(factory.create(module_type="s8_internal", version = "wlstrap_p")) - self.cell = factory.create(module_type="s8_bitcell", version = "opt1") - self.add_mod(self.dummy_cell2) + self.dummy_cell = factory.create(module_type="dummy_{}".format(OPTS.bitcell)) + self.cell = factory.create(module_type="bitcell") self.add_mod(self.dummy_cell) def create_instances(self): """ Create the module instances used in this design """ self.cell_inst = {} - if not props.compare_ports(props.bitcell_array.use_custom_cell_arrangement): - for col in range(self.column_size): - for row in range(self.row_size): - name = "bit_r{0}_c{1}".format(row, col) - self.cell_inst[row, col]=self.add_inst(name=name, - mod=self.dummy_cell) - self.connect_inst(self.get_bitcell_pins(row, col)) - else: - from tech import custom_cell_arrangement - custom_cell_arrangement(self) + for col in range(self.column_size): + for row in range(self.row_size): + name = "bit_r{0}_c{1}".format(row, col) + self.cell_inst[row, col]=self.add_inst(name=name, + mod=self.dummy_cell) + self.connect_inst(self.get_bitcell_pins(row, col)) def add_pins(self): # bitline pins are not added because they are floating @@ -119,18 +107,11 @@ class dummy_array(bitcell_base_array): height=wl_pin.height()) # Copy a vdd/gnd layout pin from every cell - if not props.compare_ports(props.bitcell_array.use_custom_cell_arrangement): - for row in range(self.row_size): - for col in range(self.column_size): - inst = self.cell_inst[row, col] - for pin_name in ["vdd", "gnd"]: - self.copy_layout_pin(inst, pin_name) - else: - for row in range(self.row_size): - for col in range(self.column_size): - inst = self.cell_inst[row, col] - for pin_name in ["vpwr", "vgnd"]: - self.copy_layout_pin(inst, pin_name) + for row in range(self.row_size): + for col in range(self.column_size): + inst = self.cell_inst[row, col] + for pin_name in ["vdd", "gnd"]: + self.copy_layout_pin(inst, pin_name) def input_load(self): diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 3a4a9011..e468788b 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -147,78 +147,37 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): column_offset=1 + len(self.left_rbl), mirror=0) self.add_mod(self.dummy_row) - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - # 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 - column_offset=1 + len(self.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") - - self.row_cap_left = factory.create(module_type=row_cap_module_type, - cols=1, - column_offset=0, - rows=self.row_size + self.extra_rows, - mirror=(self.rbl[0] + 1) % 2) - self.add_mod(self.row_cap_left) - - self.row_cap_right = factory.create(module_type=row_cap_module_type, - cols=1, - # dummy column - # + left replica column(s) - # + bitcell columns - # + right replica column(s) - column_offset = 1 + len(self.left_rbl) + self.column_size + self.rbl[0], - rows=self.row_size + self.extra_rows, - mirror=(self.rbl[0] + 1) %2) - self.add_mod(self.row_cap_right) - else: - # Dummy Row or Col Cap, depending on bitcell array properties - col_cap_module_type = ("s8_col_cap_array" if end_caps_enabled else "dummy_array") - self.col_cap_top = factory.create(module_type=col_cap_module_type, + # 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) + # dummy column + left replica column column_offset=1 + len(self.left_rbl), - mirror=0, - location="top") - self.add_mod(self.col_cap_top) + mirror=0) + self.add_mod(self.col_cap) - self.col_cap_bottom = factory.create(module_type=col_cap_module_type, - cols=self.column_size, - rows=1, - # dummy column + left replica column(s) - column_offset=1 + len(self.left_rbl), - mirror=0, - location="bottom") - self.add_mod(self.col_cap_bottom) - # Dummy Col or Row Cap, depending on bitcell array properties - row_cap_module_type = ("s8_row_cap_array" if end_caps_enabled else "dummy_array") + # Dummy Col or Row Cap, depending on bitcell array properties + row_cap_module_type = ("row_cap_array" if end_caps_enabled else "dummy_array") - self.row_cap_left = factory.create(module_type=row_cap_module_type, - cols=1, - column_offset=0, - rows=self.row_size + self.extra_rows, - mirror=0) - self.add_mod(self.row_cap_left) + self.row_cap_left = factory.create(module_type=row_cap_module_type, + cols=1, + column_offset=0, + rows=self.row_size + self.extra_rows, + mirror=(self.rbl[0] + 1) % 2) + self.add_mod(self.row_cap_left) - self.row_cap_right = factory.create(module_type=row_cap_module_type, - cols=1, - # dummy column - # + left replica column(s) - # + bitcell columns - # + right replica column(s) - column_offset = 1 + len(self.left_rbl) + self.column_size + self.rbl[0], - rows=self.row_size + self.extra_rows, - mirror=0) - self.add_mod(self.row_cap_right) + self.row_cap_right = factory.create(module_type=row_cap_module_type, + cols=1, + # dummy column + # + left replica column(s) + # + bitcell columns + # + right replica column(s) + column_offset = 1 + len(self.left_rbl) + self.column_size + self.rbl[0], + rows=self.row_size + self.extra_rows, + mirror=(self.rbl[0] + 1) %2) + self.add_mod(self.row_cap_right) def add_pins(self): @@ -279,15 +238,13 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # All wordlines including dummy and RBL self.replica_array_wordline_names = [] - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap.get_wordline_names())) + self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap.get_wordline_names())) for bit in range(self.rbl[0]): self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[bit]]) self.replica_array_wordline_names.extend(self.all_wordline_names) for bit in range(self.rbl[1]): self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[self.rbl[0] + bit]]) - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap.get_wordline_names())) + self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap.get_wordline_names())) for port in range(self.rbl[0]): self.add_pin(self.rbl_wordline_names[port][port], "INPUT") @@ -297,56 +254,51 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def create_instances(self): """ Create the module instances used in this design """ - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): + self.supplies = ["vdd", "gnd"] - self.supplies = ["vdd", "gnd"] + # Used for names/dimensions only + self.cell = factory.create(module_type="bitcell") - # Used for names/dimensions only - self.cell = factory.create(module_type="bitcell") + # Main array + self.bitcell_array_inst=self.add_inst(name="bitcell_array", + mod=self.bitcell_array) + self.connect_inst(self.all_bitline_names + self.all_wordline_names + self.supplies) - # Main array - self.bitcell_array_inst=self.add_inst(name="bitcell_array", - mod=self.bitcell_array) - self.connect_inst(self.all_bitline_names + self.all_wordline_names + self.supplies) + # Replica columns + self.replica_col_insts = [] + for port in self.all_ports: + if port in self.rbls: + self.replica_col_insts.append(self.add_inst(name="replica_col_{}".format(port), + mod=self.replica_columns[port])) + self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + self.supplies) + else: + self.replica_col_insts.append(None) + + # Dummy rows under the bitcell array (connected with with the replica cell wl) + self.dummy_row_replica_insts = [] + # Note, this is the number of left and right even if we aren't adding the columns to this bitcell array! + for port in self.all_ports: + self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port), + mod=self.dummy_row)) + self.connect_inst([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[port]] + self.supplies) - # Replica columns - self.replica_col_insts = [] - for port in self.all_ports: - if port in self.rbls: - self.replica_col_insts.append(self.add_inst(name="replica_col_{}".format(port), - mod=self.replica_columns[port])) - self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + self.supplies) - else: - self.replica_col_insts.append(None) - - # Dummy rows under the bitcell array (connected with with the replica cell wl) - self.dummy_row_replica_insts = [] - # Note, this is the number of left and right even if we aren't adding the columns to this bitcell array! - for port in self.all_ports: - self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port), - mod=self.dummy_row)) - self.connect_inst([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[port]] + self.supplies) + # Top/bottom dummy rows or col caps + self.dummy_row_insts = [] + self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot", + mod=self.col_cap)) + self.connect_inst(["gnd"] * len(self.col_cap.get_wordline_names()) + self.supplies) + self.dummy_row_insts.append(self.add_inst(name="dummy_row_top", + mod=self.col_cap)) + self.connect_inst(["gnd"] * len(self.col_cap.get_wordline_names()) + self.supplies) - # Top/bottom dummy rows or col caps - self.dummy_row_insts = [] - self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot", - mod=self.col_cap)) - self.connect_inst(["gnd"] * len(self.col_cap.get_wordline_names()) + self.supplies) - self.dummy_row_insts.append(self.add_inst(name="dummy_row_top", - mod=self.col_cap)) - self.connect_inst(["gnd"] * len(self.col_cap.get_wordline_names()) + self.supplies) - - # Left/right Dummy columns - self.dummy_col_insts = [] - self.dummy_col_insts.append(self.add_inst(name="dummy_col_left", - mod=self.row_cap_left)) - self.connect_inst(self.replica_array_wordline_names + self.supplies) - self.dummy_col_insts.append(self.add_inst(name="dummy_col_right", - mod=self.row_cap_right)) - self.connect_inst(self.replica_array_wordline_names + self.supplies) - else: - from tech import custom_replica_bitcell_array_arrangement - custom_replica_bitcell_array_arrangement(self) + # Left/right Dummy columns + self.dummy_col_insts = [] + self.dummy_col_insts.append(self.add_inst(name="dummy_col_left", + mod=self.row_cap_left)) + self.connect_inst(self.replica_array_wordline_names + self.supplies) + self.dummy_col_insts.append(self.add_inst(name="dummy_col_right", + mod=self.row_cap_right)) + self.connect_inst(self.replica_array_wordline_names + self.supplies) def create_layout(self): @@ -357,26 +309,15 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.unused_offset = vector(self.unused_pitch, 0) # Add extra width on the left and right for the unused WLs - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - self.height = (self.row_size + self.extra_rows) * self.dummy_row.height - self.width = (self.column_size + self.extra_cols) * self.cell.width + 2 * self.unused_pitch - else: - self.width = self.row_cap_left.width + self.row_cap_right.width + self.col_cap_top.width - for rbl in range(self.rbl[0] + self.rbl[1]): - self.width += self.replica_col_insts[rbl].width - self.height = self.row_cap_left.height + self.height = (self.row_size + self.extra_rows) * self.dummy_row.height + 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) - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - self.strap_offset = vector(0, 0) - self.col_end_offset = vector(self.cell.width, self.cell.height) - self.row_end_offset = vector(self.cell.width, self.cell.height) - else: - self.strap_offset = vector(self.replica_col_insts[0].mod.strap1.width, self.replica_col_insts[0].mod.strap1.height) - self.col_end_offset = vector(self.dummy_row_insts[0].mod.colend1.width, self.dummy_row_insts[0].mod.colend1.height) - self.row_end_offset = vector(self.dummy_col_insts[0].mod.rowend1.width, self.dummy_col_insts[0].mod.rowend1.height) + self.strap_offset = vector(0, 0) + self.col_end_offset = vector(self.cell.width, self.cell.height) + self.row_end_offset = vector(self.cell.width, self.cell.height) # Everything is computed with the main array at (self.unused_pitch, 0) to start self.bitcell_array_inst.place(offset=self.unused_offset) @@ -503,50 +444,28 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): #All wordlines #Main array wl and bl/br - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - for pin_name in self.all_wordline_names: - pin_list = self.bitcell_array_inst.get_pins(pin_name) - for pin in pin_list: - self.add_layout_pin(text=pin_name, - layer=pin.layer, - offset=pin.ll().scale(0, 1), - width=self.width, - height=pin.height()) - # Replica wordlines (go by the row instead of replica column because we may have to add a pin - # even though the column is in another local bitcell array) - for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): - for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()): - if wl_name in self.gnd_wordline_names: - continue - pin = inst.get_pin(pin_name) - self.add_layout_pin(text=wl_name, - layer=pin.layer, - offset=pin.ll().scale(0, 1), - width=self.width, - height=pin.height()) - else: - for pin_name in self.all_wordline_names: - pin_list = self.dummy_col_insts[0].get_pins(pin_name) - for pin in pin_list: - self.add_layout_pin(text=pin_name, - layer=pin.layer, - offset=pin.ll().scale(0, 1), - width=self.width, - height=pin.height()) - # Replica wordlines (go by the row instead of replica column because we may have to add a pin - # even though the column is in another local bitcell array) - for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): - for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()): - if wl_name in self.gnd_wordline_names: - continue - pin = inst.get_pin(pin_name) - self.add_layout_pin(text=wl_name, - layer=pin.layer, - offset=pin.ll().scale(0, 1), - width=self.width, - height=pin.height()) - + for pin_name in self.all_wordline_names: + pin_list = self.bitcell_array_inst.get_pins(pin_name) + for pin in pin_list: + self.add_layout_pin(text=pin_name, + layer=pin.layer, + offset=pin.ll().scale(0, 1), + width=self.width, + height=pin.height()) + # Replica wordlines (go by the row instead of replica column because we may have to add a pin + # even though the column is in another local bitcell array) + for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): + for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()): + if wl_name in self.gnd_wordline_names: + continue + pin = inst.get_pin(pin_name) + self.add_layout_pin(text=wl_name, + layer=pin.layer, + offset=pin.ll().scale(0, 1), + width=self.width, + height=pin.height()) + for pin_name in self.all_bitline_names: pin_list = self.bitcell_array_inst.get_pins(pin_name) for pin in pin_list: @@ -603,17 +522,16 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def route_unused_wordlines(self): """ Connect the unused RBL and dummy wordlines to gnd """ - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - # This grounds all the dummy row word lines - for inst in self.dummy_row_insts: - for wl_name in self.col_cap.get_wordline_names(): - self.ground_pin(inst, wl_name) + # This grounds all the dummy row word lines + for inst in self.dummy_row_insts: + for wl_name in self.col_cap.get_wordline_names(): + self.ground_pin(inst, wl_name) - # Ground the unused replica wordlines - for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): - for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()): - if wl_name in self.gnd_wordline_names: - self.ground_pin(inst, pin_name) + # Ground the unused replica wordlines + for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): + for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()): + if wl_name in self.gnd_wordline_names: + self.ground_pin(inst, pin_name) def ground_pin(self, inst, name): pin = inst.get_pin(name) diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index 82ba1340..3d6b524b 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -28,10 +28,8 @@ class replica_column(bitcell_base_array): self.right_rbl = rbl[1] self.replica_bit = replica_bit # left, right, regular rows plus top/bottom dummy cells - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - self.total_size = self.left_rbl + rows + self.right_rbl + 2 - else: - self.total_size = self.left_rbl + rows + self.right_rbl + 2 + self.total_size = self.left_rbl + rows + self.right_rbl + 2 + self.column_offset = column_offset debug.check(replica_bit != 0 and replica_bit != rows, @@ -80,197 +78,129 @@ class replica_column(bitcell_base_array): self.add_pin("gnd", "GROUND") def add_modules(self): - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - self.replica_cell = factory.create(module_type="replica_{}".format(OPTS.bitcell)) - self.add_mod(self.replica_cell) - self.dummy_cell = factory.create(module_type="dummy_{}".format(OPTS.bitcell)) - self.add_mod(self.dummy_cell) - try: - edge_module_type = ("col_cap" if cell_properties.bitcell.end_caps else "dummy") - except AttributeError: - edge_module_type = "dummy" - self.edge_cell = factory.create(module_type=edge_module_type + "_" + OPTS.bitcell) - self.add_mod(self.edge_cell) - # Used for pin names only - self.cell = factory.create(module_type="bitcell") - 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) + self.replica_cell = factory.create(module_type="replica_{}".format(OPTS.bitcell)) + self.add_mod(self.replica_cell) + self.dummy_cell = factory.create(module_type="dummy_{}".format(OPTS.bitcell)) + self.add_mod(self.dummy_cell) + try: + edge_module_type = ("col_cap" if cell_properties.bitcell.end_caps else "dummy") + except AttributeError: + edge_module_type = "dummy" + self.edge_cell = factory.create(module_type=edge_module_type + "_" + OPTS.bitcell) + self.add_mod(self.edge_cell) + # Used for pin names only + self.cell = factory.create(module_type="bitcell") - self.dummy_cell = factory.create(module_type="s8_bitcell", version = "opt1") - self.dummy_cell2 = factory.create(module_type="s8_bitcell", version = "opt1") - - self.strap1 = factory.create(module_type="s8_internal", version = "wlstrap") - self.add_mod(self.strap1) - self.strap2 = factory.create(module_type="s8_internal", version = "wlstrap_p") - self.add_mod(self.strap2) - - self.colend = factory.create(module_type="s8_col_end", version = "colenda") - self.edge_cell = self.colend - self.add_mod(self.colend) - self.colenda = factory.create(module_type="s8_col_end", version = "colenda") - self.add_mod(self.colenda) - self.colend_p_cent = factory.create(module_type="s8_col_end", version = "colend_p_cent") - self.add_mod(self.colend_p_cent) - self.colenda_p_cent = factory.create(module_type="s8_col_end", version = "colenda_p_cent") - self.add_mod(self.colenda_p_cent) def create_instances(self): self.cell_inst = {} - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - try: - end_caps_enabled = cell_properties.bitcell.end_caps - except AttributeError: - end_caps_enabled = False - - for row in range(self.total_size): - name="rbc_{0}".format(row) - # Top/bottom cell are always dummy cells. - # Regular array cells are replica cells (>left_rbl and self.left_rbl and row < self.total_size - self.right_rbl - 1): - self.cell_inst[row]=self.add_inst(name=name, - mod=self.replica_cell) - self.connect_inst(self.get_bitcell_pins(row, 0)) - elif row==self.replica_bit: - self.cell_inst[row]=self.add_inst(name=name, - mod=self.replica_cell) - self.connect_inst(self.get_bitcell_pins(row, 0)) - elif (row == 0 or row == self.total_size - 1): - self.cell_inst[row]=self.add_inst(name=name, - mod=self.edge_cell) - if end_caps_enabled: - self.connect_inst(self.get_bitcell_pins_col_cap(row, 0)) - else: - self.connect_inst(self.get_bitcell_pins(row, 0)) + try: + end_caps_enabled = cell_properties.bitcell.end_caps + except AttributeError: + end_caps_enabled = False + + for row in range(self.total_size): + name="rbc_{0}".format(row) + # Top/bottom cell are always dummy cells. + # Regular array cells are replica cells (>left_rbl and self.left_rbl and row < self.total_size - self.right_rbl - 1): + self.cell_inst[row]=self.add_inst(name=name, + mod=self.replica_cell) + self.connect_inst(self.get_bitcell_pins(row, 0)) + elif row==self.replica_bit: + self.cell_inst[row]=self.add_inst(name=name, + mod=self.replica_cell) + self.connect_inst(self.get_bitcell_pins(row, 0)) + elif (row == 0 or row == self.total_size - 1): + self.cell_inst[row]=self.add_inst(name=name, + mod=self.edge_cell) + if end_caps_enabled: + self.connect_inst(self.get_bitcell_pins_col_cap(row, 0)) else: - self.cell_inst[row]=self.add_inst(name=name, - mod=self.dummy_cell) self.connect_inst(self.get_bitcell_pins(row, 0)) - else: - from tech import custom_replica_column_arrangement - custom_replica_column_arrangement(self) + else: + self.cell_inst[row]=self.add_inst(name=name, + mod=self.dummy_cell) + self.connect_inst(self.get_bitcell_pins(row, 0)) def place_instances(self): - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): + # 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 - # 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 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 - # 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 + 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 - 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 + offset = vector(xoffset, self.cell.height * (row + (row + rbl_offset) % 2)) - offset = vector(xoffset, self.cell.height * (row + (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 = "" - 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) - 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) - - 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) + 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 ["vpwr", "vgnd"]: - 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) + 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) + def get_bitline_names(self, port=None): if port == None: return self.all_bitline_names From 68d74737f7dff953675abf83e65f7c8635d44177 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 13 Oct 2020 07:41:21 -0700 Subject: [PATCH 4/6] Different bitcell and array supply pins --- compiler/modules/bitcell_base_array.py | 33 +++++++++++--------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 90eb7910..06fcafb5 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -9,7 +9,6 @@ import debug import design from tech import cell_properties from sram_factory import factory -from globals import OPTS class bitcell_base_array(design.design): @@ -27,7 +26,6 @@ class bitcell_base_array(design.design): # Bitcell for port names only self.cell = factory.create(module_type="bitcell") - self.wordline_names = [[] for port in self.all_ports] self.all_wordline_names = [] self.bitline_names = [[] for port in self.all_ports] @@ -37,9 +35,11 @@ class bitcell_base_array(design.design): self.rbl_wordline_names = [[] for port in self.all_ports] self.all_rbl_wordline_names = [] - def get_all_bitline_names(self, prefix=""): - return [prefix + x for x in self.all_bitline_names] - + # The supply pin namesn + self.bitcell_supplies = ["vdd", "gnd"] + # If the technology needs renaming of the supplies + self.supplies = self.bitcell_supplies + def create_all_bitline_names(self): for col in range(self.column_size): for port in self.all_ports: @@ -54,11 +54,7 @@ class bitcell_base_array(design.design): def create_all_wordline_names(self, remove_num_wordlines=0): for row in range(self.row_size - remove_num_wordlines): for port in self.all_ports: - if not cell_properties.compare_ports(cell_properties.bitcell.split_wl): - self.wordline_names[port].append("wl_{0}_{1}".format(port, row)) - else: - self.wordline_names[port].append("wl0_{0}_{1}".format(port, row)) - self.wordline_names[port].append("wl1_{0}_{1}".format(port, row)) + self.wordline_names[port].append("wl_{0}_{1}".format(port, row)) self.all_wordline_names = [x for sl in zip(*self.wordline_names) for x in sl] @@ -67,10 +63,9 @@ class bitcell_base_array(design.design): self.add_pin(bl_name, "INOUT") for wl_name in self.get_wordline_names(): self.add_pin(wl_name, "INPUT") - self.add_pin("vdd", "POWER") - self.add_pin("gnd", "GROUND") + self.add_pin(self.supplies[0], "POWER") + self.add_pin(self.supplies[1], "GROUND") - def get_bitcell_pins(self, row, col): """ Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """ @@ -78,8 +73,8 @@ class bitcell_base_array(design.design): for port in self.all_ports: bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))]) bitcell_pins.extend([x for x in self.all_wordline_names if x.endswith("_{0}".format(row))]) - bitcell_pins.append("vdd") - bitcell_pins.append("gnd") + bitcell_pins.append(self.bitcell_supplies[0]) + bitcell_pins.append(self.bitcell_supplies[1]) return bitcell_pins @@ -169,8 +164,8 @@ class bitcell_base_array(design.design): for row in range(self.row_size): for col in range(self.column_size): inst = self.cell_inst[row, col] - for pin_name in ["vdd", "gnd"]: - self.copy_layout_pin(inst, pin_name) + for (pin_name, new_name) in zip(self.bitcell_supplies, self.supplies): + self.copy_layout_pin(inst, pin_name, new_name) def _adjust_x_offset(self, xoffset, col, col_offset): tempx = xoffset @@ -191,7 +186,7 @@ class bitcell_base_array(design.design): return (tempy, dir_x) def place_array(self, name_template, row_offset=0): - # We increase it by a well enclosure so the precharges don't overlap our wells + # We increase it by a well enclosure so the precharges don't overlap our wells self.height = self.row_size * self.cell.height self.width = self.column_size * self.cell.width @@ -213,7 +208,7 @@ class bitcell_base_array(design.design): dir_key = "" self.cell_inst[row, col].place(offset=[tempx, tempy], - mirror=dir_key) + mirror=dir_key) yoffset += self.cell.height xoffset += self.cell.width From 6a1f12b62db320a65bd0ed9bc1030f1d0463aac4 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 13 Oct 2020 11:07:31 -0700 Subject: [PATCH 5/6] Refactored to utilize OOP --- compiler/modules/bitcell_array.py | 1 - compiler/modules/bitcell_base_array.py | 9 +++-- compiler/modules/col_cap_array.py | 25 +++++++++---- compiler/modules/dummy_array.py | 13 ++++--- compiler/modules/replica_bitcell_array.py | 44 ++++++++++++++--------- compiler/modules/row_cap_array.py | 4 +++ 6 files changed, 59 insertions(+), 37 deletions(-) diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 6bd290a2..65470726 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -8,7 +8,6 @@ import debug from bitcell_base_array import bitcell_base_array from tech import drc, spice -from tech import cell_properties as props from globals import OPTS from sram_factory import factory diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 06fcafb5..477100fe 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -48,9 +48,6 @@ class bitcell_base_array(design.design): # Make a flat list too self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] - # def get_all_wordline_names(self, prefix=""): - # return [prefix + x for x in self.all_wordline_names] - def create_all_wordline_names(self, remove_num_wordlines=0): for row in range(self.row_size - remove_num_wordlines): for port in self.all_ports: @@ -67,8 +64,10 @@ class bitcell_base_array(design.design): self.add_pin(self.supplies[1], "GROUND") def get_bitcell_pins(self, row, col): - """ Creates a list of connections in the bitcell, - indexed by column and row, for instance use in bitcell_array """ + """ + Creates a list of connections in the bitcell, + indexed by column and row, for instance use in bitcell_array + """ bitcell_pins = [] for port in self.all_ports: bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))]) diff --git a/compiler/modules/col_cap_array.py b/compiler/modules/col_cap_array.py index a2bf8379..392f573c 100644 --- a/compiler/modules/col_cap_array.py +++ b/compiler/modules/col_cap_array.py @@ -13,9 +13,10 @@ class col_cap_array(bitcell_base_array): """ Generate a dummy row/column for the replica array. """ - def __init__(self, rows, cols, column_offset=0, mirror=0, name=""): + def __init__(self, rows, cols, column_offset=0, mirror=0, location="", name=""): super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name) self.mirror = mirror + self.location = location self.no_instances = True self.create_netlist() @@ -24,6 +25,10 @@ class col_cap_array(bitcell_base_array): def create_netlist(self): """ Create and connect the netlist """ + # This will create a default set of bitline/wordline names + self.create_all_wordline_names() + self.create_all_bitline_names() + self.add_modules() self.add_pins() self.create_instances() @@ -58,12 +63,18 @@ class col_cap_array(bitcell_base_array): indexed by column and row, for instance use in bitcell_array """ - pin_name = cell_properties.bitcell.cell_1rw1r.pin - bitcell_pins = ["{0}_{1}".format(pin_name.bl0, col), - "{0}_{1}".format(pin_name.br0, col), - "{0}_{1}".format(pin_name.bl1, col), - "{0}_{1}".format(pin_name.br1, col), - "vdd"] + if len(self.ports) == 1: + pin_name = cell_properties.bitcell.cell_6t.pin + bitcell_pins = ["{0}_{1}".format(pin_name.bl0, col), + "{0}_{1}".format(pin_name.br0, col), + "vdd"] + else: + pin_name = cell_properties.bitcell.cell_1rw1r.pin + bitcell_pins = ["{0}_{1}".format(pin_name.bl0, col), + "{0}_{1}".format(pin_name.br0, col), + "{0}_{1}".format(pin_name.bl1, col), + "{0}_{1}".format(pin_name.br1, col), + "vdd"] return bitcell_pins diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py index 399073d0..7024a6fc 100644 --- a/compiler/modules/dummy_array.py +++ b/compiler/modules/dummy_array.py @@ -5,7 +5,6 @@ # from bitcell_base_array import bitcell_base_array from sram_factory import factory -from tech import GDS,layer,drc,parameter,cell_properties from tech import cell_properties as props from globals import OPTS @@ -14,20 +13,20 @@ class dummy_array(bitcell_base_array): """ Generate a dummy row/column for the replica array. """ - def __init__(self, rows, cols, column_offset=0, mirror=0, name=""): + def __init__(self, rows, cols, column_offset=0, mirror=0, location="", name=""): super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name) self.mirror = mirror - # This will create a default set of bitline/wordline names - self.create_all_bitline_names() - self.create_all_wordline_names() - self.create_netlist() if not OPTS.netlist_only: self.create_layout() def create_netlist(self): """ Create and connect the netlist """ + # This will create a default set of bitline/wordline names + self.create_all_bitline_names() + self.create_all_wordline_names() + self.add_modules() self.add_pins() self.create_instances() @@ -56,7 +55,7 @@ class dummy_array(bitcell_base_array): for row in range(self.row_size): name = "bit_r{0}_c{1}".format(row, col) self.cell_inst[row, col]=self.add_inst(name=name, - mod=self.dummy_cell) + mod=self.dummy_cell) self.connect_inst(self.get_bitcell_pins(row, col)) def add_pins(self): diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index e468788b..0814728f 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -5,14 +5,14 @@ # import debug -import bitcell_base_array +from bitcell_base_array import bitcell_base_array from tech import drc, spice, cell_properties from vector import vector from globals import OPTS from sram_factory import factory -class replica_bitcell_array(bitcell_base_array.bitcell_base_array): +class replica_bitcell_array(bitcell_base_array): """ Creates a bitcell arrow of cols x rows and then adds the replica and dummy columns and rows. Replica columns are on the left and @@ -150,13 +150,23 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # 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 - column_offset=1 + len(self.left_rbl), - mirror=0) - self.add_mod(self.col_cap) + self.col_cap_top = factory.create(module_type=col_cap_module_type, + cols=self.column_size, + rows=1, + # dummy column + left replica column(s) + column_offset=1 + len(self.left_rbl), + mirror=0, + location="top") + self.add_mod(self.col_cap_top) + + self.col_cap_bottom = factory.create(module_type=col_cap_module_type, + cols=self.column_size, + rows=1, + # dummy column + left replica column(s) + column_offset=1 + len(self.left_rbl), + mirror=0, + location="bottom") + self.add_mod(self.col_cap_bottom) # Dummy Col or Row Cap, depending on bitcell array properties row_cap_module_type = ("row_cap_array" if end_caps_enabled else "dummy_array") @@ -238,13 +248,13 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # All wordlines including dummy and RBL self.replica_array_wordline_names = [] - self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap.get_wordline_names())) + self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap_top.get_wordline_names())) for bit in range(self.rbl[0]): self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[bit]]) self.replica_array_wordline_names.extend(self.all_wordline_names) for bit in range(self.rbl[1]): self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[self.rbl[0] + bit]]) - self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap.get_wordline_names())) + self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap_top.get_wordline_names())) for port in range(self.rbl[0]): self.add_pin(self.rbl_wordline_names[port][port], "INPUT") @@ -285,11 +295,11 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Top/bottom dummy rows or col caps self.dummy_row_insts = [] self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot", - mod=self.col_cap)) - self.connect_inst(["gnd"] * len(self.col_cap.get_wordline_names()) + self.supplies) + mod=self.col_cap_bottom)) + self.connect_inst(["gnd"] * len(self.col_cap_bottom.get_wordline_names()) + self.supplies) self.dummy_row_insts.append(self.add_inst(name="dummy_row_top", - mod=self.col_cap)) - self.connect_inst(["gnd"] * len(self.col_cap.get_wordline_names()) + self.supplies) + mod=self.col_cap_top)) + self.connect_inst(["gnd"] * len(self.col_cap_top.get_wordline_names()) + self.supplies) # Left/right Dummy columns self.dummy_col_insts = [] @@ -491,7 +501,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # replica column should only have a vdd/gnd in the dummy cell on top/bottom supply_insts = self.dummy_col_insts + self.dummy_row_insts - for pin_name in self.supplies: + for pin_name in self.supplies: for inst in supply_insts: pin_list = inst.get_pins(pin_name) for pin in pin_list: @@ -524,7 +534,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): """ Connect the unused RBL and dummy wordlines to gnd """ # This grounds all the dummy row word lines for inst in self.dummy_row_insts: - for wl_name in self.col_cap.get_wordline_names(): + for wl_name in self.col_cap_top.get_wordline_names(): self.ground_pin(inst, wl_name) # Ground the unused replica wordlines diff --git a/compiler/modules/row_cap_array.py b/compiler/modules/row_cap_array.py index 58b33c89..f327aecf 100644 --- a/compiler/modules/row_cap_array.py +++ b/compiler/modules/row_cap_array.py @@ -23,6 +23,10 @@ class row_cap_array(bitcell_base_array): def create_netlist(self): """ Create and connect the netlist """ + # This will create a default set of bitline/wordline names + self.create_all_wordline_names() + self.create_all_bitline_names() + self.add_modules() self.add_pins() self.create_instances() From 35c91168f7ee0e98cd40b00144f3f010eea0ffce Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 16 Oct 2020 13:52:36 -0700 Subject: [PATCH 6/6] Add load/slew scale option to config files --- compiler/characterizer/lib.py | 19 +++++++------------ .../example_config_freepdk45.py | 5 ++++- compiler/globals.py | 18 +++++++++++++++++- compiler/options.py | 2 ++ 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index 525f2180..92f8b167 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -44,20 +44,15 @@ class lib: def prepare_tables(self): """ Determine the load/slews if they aren't specified in the config file. """ # These are the parameters to determine the table sizes - #self.load_scales = np.array([0.1, 0.25, 0.5, 1, 2, 4, 8]) - self.load_scales = np.array([0.25, 1, 4]) - #self.load_scales = np.array([0.25, 1]) + self.load_scales = np.array(OPTS.load_scales) self.load = tech.spice["dff_in_cap"] - self.loads = self.load_scales*self.load - debug.info(1,"Loads: {0}".format(self.loads)) + self.loads = self.load_scales * self.load + debug.info(1, "Loads: {0}".format(self.loads)) - #self.slew_scales = np.array([0.1, 0.25, 0.5, 1, 2, 4, 8]) - self.slew_scales = np.array([0.25, 1, 8]) - #self.slew_scales = np.array([0.25, 1]) - self.slew = tech.spice["rise_time"] - self.slews = self.slew_scales*self.slew - debug.info(1,"Slews: {0}".format(self.slews)) - + self.slew_scales = np.array(OPTS.slew_scales) + self.slew = tech.spice["rise_time"] + self.slews = self.slew_scales * self.slew + debug.info(1, "Slews: {0}".format(self.slews)) def create_corners(self): """ Create corners for characterization. """ diff --git a/compiler/example_configs/example_config_freepdk45.py b/compiler/example_configs/example_config_freepdk45.py index f0d71d6d..9c536bc6 100644 --- a/compiler/example_configs/example_config_freepdk45.py +++ b/compiler/example_configs/example_config_freepdk45.py @@ -7,8 +7,11 @@ process_corners = ["TT"] supply_voltages = [1.0] temperatures = [25] -route_supplies = True +route_supplies = False check_lvsdrc = True +# nominal_corners_only = True +load_scales = [0.5, 1, 4] +slew_scales = [0.5, 1] output_path = "temp" output_name = "sram_{0}_{1}_{2}".format(word_size, diff --git a/compiler/globals.py b/compiler/globals.py index e1bb8661..ef4816c7 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -459,17 +459,33 @@ def set_default_corner(): OPTS.process_corners = ["TT"] else: OPTS.process_corners = tech.spice["fet_models"].keys() + if (OPTS.supply_voltages == ""): if OPTS.nominal_corner_only: OPTS.supply_voltages = [tech.spice["supply_voltages"][1]] else: OPTS.supply_voltages = tech.spice["supply_voltages"] + if (OPTS.temperatures == ""): if OPTS.nominal_corner_only: OPTS.temperatures = [tech.spice["temperatures"][1]] else: OPTS.temperatures = tech.spice["temperatures"] - + + # Load scales are fanout multiples of the DFF input cap + if (OPTS.load_scales == ""): + if OPTS.nominal_corner_only: + OPTS.load_scales = [4] + else: + OPTS.load_scales = [0.25, 1, 4] + + # Load scales are fanout multiples of the default spice input slew + if (OPTS.slew_scales == ""): + if OPTS.nominal_corner_only: + OPTS.slew_scales = [1] + else: + OPTS.slew_scales = [0.25, 1, 4] + def import_tech(): """ Dynamically adds the tech directory to the path and imports it. """ diff --git a/compiler/options.py b/compiler/options.py index 2221f85f..0f94be2b 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -42,6 +42,8 @@ class options(optparse.Values): supply_voltages = "" temperatures = "" process_corners = "" + load_scales = "" + slew_scales = "" # Size parameters must be specified by user in config file. # num_words = 0