From 3a0939c40299a1a65a78b4147a8c91979d571de7 Mon Sep 17 00:00:00 2001 From: Andres AG Date: Tue, 23 Jun 2020 11:50:02 +0100 Subject: [PATCH 01/40] Update minimum required Magic version --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 82fe75ed..d6b948ef 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ The OpenRAM compiler has very few dependencies: If you want to perform DRC and LVS, you will need either: + Calibre (for [FreePDK45]) -+ [Magic] 8.2.79 or higher (for [SCMOS]) ++ [Magic] 8.3.27 or higher (for [SCMOS]) + [Netgen] 1.5 (for [SCMOS]) You must set two environment variables: @@ -81,6 +81,8 @@ We have included the most recent SCN4M_SUBM design rules from [Qflow]. ## Docker Image +**WARNING! Some OpenRAM dependency tools installed in the Docker image are out-of-date.** + We have a pre-configured Ubuntu [Docker](https://www.docker.com/) image available that has all tools installed for the [SCMOS] process. It is available at [docker hub](https://hub.docker.com/r/vlsida/openram-ubuntu). From ed9d32c7bc105db2a438d36d4b2d852152a79e3b Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 13 Jul 2020 16:26:25 -0700 Subject: [PATCH 02/40] OpenRAM 1.1.6 --- compiler/globals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/globals.py b/compiler/globals.py index a192ebc9..dd4ac177 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -19,7 +19,7 @@ import re import copy import importlib -VERSION = "1.1.5" +VERSION = "1.1.6" NAME = "OpenRAM v{}".format(VERSION) USAGE = "openram.py [options] \nUse -h for help.\n" From ee3da912321b87369e3aa742cc6ba607d17ce759 Mon Sep 17 00:00:00 2001 From: Bob Vanhoof Date: Wed, 15 Jul 2020 11:50:21 +0200 Subject: [PATCH 03/40] calibrepex: file copy fix --- compiler/sram/sram.py | 1 + compiler/verify/calibre.py | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/compiler/sram/sram.py b/compiler/sram/sram.py index 1ec7d636..b2ab1124 100644 --- a/compiler/sram/sram.py +++ b/compiler/sram/sram.py @@ -101,6 +101,7 @@ class sram(): start_time = datetime.datetime.now() # Output the extracted design if requested sp_file = OPTS.output_path + "temp_pex.sp" + spname = OPTS.output_path + self.s.name + ".sp" verify.run_pex(self.s.name, gdsname, spname, output=sp_file) print_time("Extraction", datetime.datetime.now(), start_time) else: diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 443c91ca..6d1786c9 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -135,11 +135,11 @@ def write_calibre_lvs_script(cell_name, final_verification): def write_calibre_pex_script(cell_name, extract, output, final_verification): """ Write a pex script that can either just extract the netlist or the netlist+parasitics """ if output == None: - output = name + ".pex.netlist" + output = cell_name + ".pex.netlist" # check if lvs report has been done # if not run drc and lvs - if not os.path.isfile(cell_name + ".lvs.report"): + if not os.path.isfile(OPTS.openram_temp + cell_name + ".lvs.report"): gds_name = OPTS.openram_temp +"/"+ cell_name + ".gds" sp_name = OPTS.openram_temp +"/"+ cell_name + ".sp" run_drc(cell_name, gds_name) @@ -155,7 +155,7 @@ def write_calibre_pex_script(cell_name, extract, output, final_verification): 'pexSourcePath': cell_name + ".sp", 'pexSourcePrimary': cell_name, 'pexReportFile': cell_name + ".pex.report", - 'pexPexNetlistFile': cell_name + ".pex.netlist", + 'pexPexNetlistFile': output, 'pexPexReportFile': cell_name + ".pex.report", 'pexMaskDBFile': cell_name + ".maskdb", 'cmnFDIDEFLayoutPath': cell_name + ".def", @@ -195,8 +195,8 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False): filter_gds(cell_name, OPTS.openram_temp + "temp.gds", OPTS.openram_temp + cell_name + ".gds") else: # Copy file to local dir if it isn't already - if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): - shutil.copy(gds_name, OPTS.openram_temp) + if not os.path.isfile(gds_name): + shutil.copy(OPTS.output_path+os.path.basename(gds_name),gds_name) drc_runset = write_calibre_drc_script(cell_name, extract, final_verification) @@ -241,10 +241,14 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): lvs_runset = write_calibre_lvs_script(cell_name, final_verification) # Copy file to local dir if it isn't already - if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): - shutil.copy(gds_name, OPTS.openram_temp) - if os.path.dirname(sp_name)!=OPTS.openram_temp.rstrip('/'): - shutil.copy(sp_name, OPTS.openram_temp) +# if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): +# shutil.copy(gds_name, OPTS.openram_temp) +# if os.path.dirname(sp_name)!=OPTS.openram_temp.rstrip('/'): +# shutil.copy(sp_name, OPTS.openram_temp) + if not os.path.isfile(gds_name): + shutil.copy(OPTS.output_path+os.path.basename(gds_name), gds_name) + if not os.path.isfile(sp_name): + shutil.copy(OPTS.output_path+os.path.basename(sp_name), sp_name) (outfile, errfile, resultsfile) = run_script(cell_name, "lvs") @@ -327,6 +331,11 @@ def run_pex(cell_name, gds_name, sp_name, output=None, final_verification=False) write_calibre_pex_script(cell_name,True,output,final_verification) + if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)): + shutil.copy(gds_name, OPTS.openram_temp + os.path.basename(gds_name)) + if not os.path.isfile(OPTS.openram_temp + os.path.basename(sp_name)): + shutil.copy(sp_name, OPTS.openram_temp + os.path.basename(sp_name)) + (outfile, errfile, resultsfile) = run_script(cell_name, "pex") From b7c43ae674bb1876e6136e3d4bc55b6886860fb6 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 23 Jul 2020 14:17:13 -0700 Subject: [PATCH 04/40] Fix 1w/1r example --- compiler/example_configs/example_config_1w_1r_scn4m_subm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/example_configs/example_config_1w_1r_scn4m_subm.py b/compiler/example_configs/example_config_1w_1r_scn4m_subm.py index 55ac4016..7698f1a3 100644 --- a/compiler/example_configs/example_config_1w_1r_scn4m_subm.py +++ b/compiler/example_configs/example_config_1w_1r_scn4m_subm.py @@ -1,9 +1,9 @@ word_size = 2 num_words = 16 -num_rw_ports = 1 +num_rw_ports = 0 num_r_ports = 1 -num_w_ports = 0 +num_w_ports = 1 tech_name = "scn4m_subm" nominal_corners_only = False From e1967dc548d82a79161918e26dcd0d195e8d4a61 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 23 Jul 2020 14:43:14 -0700 Subject: [PATCH 05/40] Draft local and global arrays. Ensure rows before cols in usage. --- compiler/modules/bitcell_array.py | 8 +- compiler/modules/bitcell_base_array.py | 4 +- compiler/modules/col_cap_array.py | 4 +- compiler/modules/dummy_array.py | 6 +- compiler/modules/global_bitcell_array.py | 66 +++++++++ compiler/modules/local_bitcell_array.py | 66 +++++++++ compiler/modules/replica_bitcell_array.py | 2 +- compiler/modules/replica_column.py | 14 +- compiler/modules/row_cap_array.py | 4 +- compiler/modules/wordline_buffer_array.py | 137 ++++++++++++++++++ compiler/modules/wordline_driver_array.py | 1 + .../tests/08_wordline_buffer_array_test.py | 37 +++++ 12 files changed, 328 insertions(+), 21 deletions(-) create mode 100644 compiler/modules/global_bitcell_array.py create mode 100644 compiler/modules/local_bitcell_array.py create mode 100644 compiler/modules/wordline_buffer_array.py create mode 100755 compiler/tests/08_wordline_buffer_array_test.py diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 97b681e9..ce72b137 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -17,8 +17,8 @@ class bitcell_array(bitcell_base_array): and word line is connected by abutment. Connects the word lines and bit lines. """ - def __init__(self, cols, rows, name, column_offset=0): - super().__init__(cols, rows, name, column_offset) + def __init__(self, rows, cols, column_offset=0, name=""): + super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name) self.create_netlist() if not OPTS.netlist_only: @@ -57,8 +57,8 @@ class bitcell_array(bitcell_base_array): 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(col, row)) - + 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 7d241b4d..793cfc34 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -14,7 +14,7 @@ class bitcell_base_array(design.design): """ Abstract base class for bitcell-arrays -- bitcell, dummy """ - def __init__(self, cols, rows, name, column_offset): + def __init__(self, name, rows, cols, column_offset): design.design.__init__(self, name) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) self.add_comment("rows: {0} cols: {1}".format(rows, cols)) @@ -61,7 +61,7 @@ class bitcell_base_array(design.design): self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") - def get_bitcell_pins(self, col, row): + 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 """ diff --git a/compiler/modules/col_cap_array.py b/compiler/modules/col_cap_array.py index ee9302d8..d9fe78b5 100644 --- a/compiler/modules/col_cap_array.py +++ b/compiler/modules/col_cap_array.py @@ -50,9 +50,9 @@ class col_cap_array(bitcell_base_array): 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(col, row)) + self.connect_inst(self.get_bitcell_pins(row, col)) - def get_bitcell_pins(self, col, row): + 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 diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py index f4b240da..9004994b 100644 --- a/compiler/modules/dummy_array.py +++ b/compiler/modules/dummy_array.py @@ -12,8 +12,8 @@ class dummy_array(bitcell_base_array): """ Generate a dummy row/column for the replica array. """ - def __init__(self, cols, rows, column_offset=0, mirror=0, name=""): - super().__init__(cols, rows, name, column_offset) + def __init__(self, rows, cols, column_offset=0, mirror=0, name=""): + super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name) self.mirror = mirror self.create_netlist() @@ -51,7 +51,7 @@ class dummy_array(bitcell_base_array): 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(col, row)) + self.connect_inst(self.get_bitcell_pins(row, col)) def input_load(self): wl_wire = self.gen_wl_wire() diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py new file mode 100644 index 00000000..728f170f --- /dev/null +++ b/compiler/modules/global_bitcell_array.py @@ -0,0 +1,66 @@ +# 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. +# +from bitcell_base_array import bitcell_base_array +from tech import drc, spice +from globals import OPTS +from sram_factory import factory +import debug + +class global_bitcell_array(bitcell_base_array): + """ + Creates a global bitcell array with a number + of local arrays of a sizes given by a tuple in the list. + """ + def __init__(self, sizes, name=""): + # Each bank will have the same number of rows + self.rows = sizes[0][0] + for (r, c) in sizes: + debug.check(r[0] == self.rows, "Cannot have non-uniform number of rows in global array.") + # The total of all columns will be the number of columns + self.cols = sum(x[1] for x in sizes) + self.sizes = sizes + super().__init__(rows=self.rows, cols=self.cols, name=name) + + 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() + + self.add_layout_pins() + + self.add_boundary() + + self.DRC_LVS() + + def add_modules(self): + """ Add the modules used in this design """ + self.local_mods = [] + for (row, col) in self.sizes: + la = factory.create(module_type="local_bitcell_array", rows=row, cols=col) + self.add_mod(la) + self.local_mods.append(la) + + def create_instances(self): + """ Create the module instances used in this design """ + self.local_inst = {} + for i in range(self.sizes): + name = "local_array_{0}".format(i) + self.local_inst.append(self.add_inst(name=name, + mod=self.local_mods[i]) + self.connect_inst(self.get_bitcell_pins(row, col)) + + diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py new file mode 100644 index 00000000..fc3137c6 --- /dev/null +++ b/compiler/modules/local_bitcell_array.py @@ -0,0 +1,66 @@ +# 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. +# +from bitcell_base_array import bitcell_base_array +from tech import drc, spice +from globals import OPTS +from sram_factory import factory + + +class local_bitcell_array(bitcell_base_array): + """ + A local wordline array is a bitcell array with a wordline driver. + This can either be a single aray on its own if there is no hierarchical WL + or it can be combined into a larger array with hierarchical WL. + """ + def __init__(self, name, rows, cols): + super().__init__(name, rows, cols) + + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + # We don't offset this because we need to align + # the replica bitcell in the control logic + # self.offset_all_coordinates() + + 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("bit_r{0}_c{1}") + + self.add_layout_pins() + + self.add_boundary() + + self.DRC_LVS() + + def add_modules(self): + """ Add the modules used in this design """ + self.bit_array = factory.create(module_type="bitcell_array", + rows=self.rows, + cols=self.cols, + column_offset=self.column_offset) + self.add_mod(self.bit_array) + + self.wl_array = factory.create(module_type="wordline_driver_array", + rows=self.rows, + cols=self.cols) + self.add_mod(self.wl_array) + + def create_instances(self): + """ Create the module instances used in this design """ + self.bitcell_inst = self.add_inst(mod=self.bitcell_array) + self.connect_inst(self.get_bitcell_pins(row, col)) + self.wl_inst = self.add_inst(mod=self.wl_array) + self.connect_inst(self.get_bitcell_pins(row, col)) + diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 0c7e412e..0c08cd56 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -21,7 +21,7 @@ class replica_bitcell_array(design.design): Requires a regular bitcell array, replica bitcell, and dummy bitcell (Bl/BR disconnected). """ - def __init__(self, cols, rows, left_rbl, right_rbl, bitcell_ports, name): + def __init__(self, rows, cols, left_rbl, right_rbl, bitcell_ports, name): design.design.__init__(self, name) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) self.add_comment("rows: {0} cols: {1}".format(rows, cols)) diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index 9613e6fa..c75bc9ee 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -102,22 +102,22 @@ class replica_column(design.design): if (row > 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(0, row)) + 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(0, row)) + 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(0, row)) + self.connect_inst(self.get_bitcell_pins_col_cap(row, 0)) else: - self.connect_inst(self.get_bitcell_pins(0, row)) + self.connect_inst(self.get_bitcell_pins(row, 0)) else: self.cell_inst[row]=self.add_inst(name=name, mod=self.dummy_cell) - self.connect_inst(self.get_bitcell_pins(0, row)) + self.connect_inst(self.get_bitcell_pins(row, 0)) def place_instances(self): from tech import cell_properties @@ -191,7 +191,7 @@ class replica_column(design.design): else: self.copy_layout_pin(inst, pin_name) - def get_bitcell_pins(self, col, row): + 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 """ @@ -208,7 +208,7 @@ class replica_column(design.design): return bitcell_pins - def get_bitcell_pins_col_cap(self, col, row): + def get_bitcell_pins_col_cap(self, row, col): """ Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """ diff --git a/compiler/modules/row_cap_array.py b/compiler/modules/row_cap_array.py index f108d86e..bfbd035c 100644 --- a/compiler/modules/row_cap_array.py +++ b/compiler/modules/row_cap_array.py @@ -49,9 +49,9 @@ class row_cap_array(bitcell_base_array): 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(col, row)) + self.connect_inst(self.get_bitcell_pins(row, col)) - def get_bitcell_pins(self, col, row): + 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 diff --git a/compiler/modules/wordline_buffer_array.py b/compiler/modules/wordline_buffer_array.py new file mode 100644 index 00000000..7dad327d --- /dev/null +++ b/compiler/modules/wordline_buffer_array.py @@ -0,0 +1,137 @@ +# 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 +from tech import drc, layer +from vector import vector +from sram_factory import factory +from globals import OPTS + + +class wordline_buffer_array(design.design): + """ + Creates a Wordline Buffer/Inverter array + """ + + def __init__(self, name, rows, cols): + design.design.__init__(self, name) + debug.info(1, "Creating {0}".format(self.name)) + self.add_comment("rows: {0} cols: {1}".format(rows, cols)) + + self.rows = rows + self.cols = cols + + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + def create_netlist(self): + self.add_modules() + self.add_pins() + self.create_drivers() + + def create_layout(self): + if "li" in layer: + self.route_layer = "li" + else: + self.route_layer = "m1" + self.place_drivers() + self.route_layout() + self.route_vdd_gnd() + self.offset_all_coordinates() + self.add_boundary() + self.DRC_LVS() + + def add_pins(self): + # inputs to wordline_driver. + for i in range(self.rows): + self.add_pin("in_{0}".format(i), "INPUT") + # Outputs from wordline_driver. + for i in range(self.rows): + self.add_pin("wl_{0}".format(i), "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def add_modules(self): + self.wl_driver = factory.create(module_type="inv_dec", + size=self.cols) + self.add_mod(self.wl_driver) + + def route_vdd_gnd(self): + """ + Add a pin for each row of vdd/gnd which + are must-connects next level up. + """ + if OPTS.tech_name == "sky130": + for name in ["vdd", "gnd"]: + supply_pins = self.wld_inst[0].get_pins(name) + for pin in supply_pins: + self.add_layout_pin_segment_center(text=name, + layer=pin.layer, + start=pin.bc(), + end=vector(pin.cx(), self.height)) + else: + # Find the x offsets for where the vias/pins should be placed + xoffset_list = [self.wld_inst[0].rx()] + for num in range(self.rows): + # this will result in duplicate polygons for rails, but who cares + + # use the inverter offset even though it will be the and's too + (gate_offset, y_dir) = self.get_gate_offset(0, + self.wl_driver.height, + num) + # Route both supplies + for name in ["vdd", "gnd"]: + supply_pin = self.wld_inst[num].get_pin(name) + + # Add pins in two locations + for xoffset in xoffset_list: + pin_pos = vector(xoffset, supply_pin.cy()) + self.add_power_pin(name, pin_pos) + + def create_drivers(self): + self.wld_inst = [] + for row in range(self.rows): + self.wld_inst.append(self.add_inst(name="wld{0}".format(row), + mod=self.wl_driver)) + self.connect_inst(["in_{0}".format(row), + "wl_{0}".format(row), + "vdd", "gnd"]) + + def place_drivers(self): + + for row in range(self.rows): + if (row % 2): + y_offset = self.wl_driver.height * (row + 1) + inst_mirror = "MX" + else: + y_offset = self.wl_driver.height * row + inst_mirror = "R0" + + offset = [0, y_offset] + + self.wld_inst[row].place(offset=offset, + mirror=inst_mirror) + + self.width = self.wl_driver.width + self.height = self.wl_driver.height * self.rows + + def route_layout(self): + """ Route all of the signals """ + + for row in range(self.rows): + inst = self.wld_inst[row] + + self.copy_layout_pin(inst, "A", "in_{0}".format(row)) + + # output each WL on the right + wl_offset = inst.get_pin("Z").rc() + self.add_layout_pin_segment_center(text="wl_{0}".format(row), + layer=self.route_layer, + start=wl_offset, + end=wl_offset - vector(self.m1_width, 0)) diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index e8a3c110..f5f8e639 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -12,6 +12,7 @@ from vector import vector from sram_factory import factory from globals import OPTS + class wordline_driver_array(design.design): """ Creates a Wordline Driver diff --git a/compiler/tests/08_wordline_buffer_array_test.py b/compiler/tests/08_wordline_buffer_array_test.py new file mode 100755 index 00000000..a753a21a --- /dev/null +++ b/compiler/tests/08_wordline_buffer_array_test.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# 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 unittest +from testutils import * +import sys,os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class wordline_buffer_array_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + # check wordline driver for single port + debug.info(2, "Checking driver") + tx = factory.create(module_type="wordline_buffer_array", rows=8, cols=32) + self.local_check(tx) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From 2991534d3f2de86e6986cec02daa22523172de7b Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 23 Jul 2020 17:15:39 -0700 Subject: [PATCH 06/40] Drafting local bitline stuff. --- compiler/modules/local_bitcell_array.py | 33 +++++++++-------- compiler/modules/wordline_buffer_array.py | 6 ++-- compiler/tests/05_local_bitcell_array_test.py | 36 +++++++++++++++++++ 3 files changed, 58 insertions(+), 17 deletions(-) create mode 100755 compiler/tests/05_local_bitcell_array_test.py diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index fc3137c6..8b56ea19 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -13,12 +13,12 @@ from sram_factory import factory class local_bitcell_array(bitcell_base_array): """ - A local wordline array is a bitcell array with a wordline driver. + A local bitcell array is a bitcell array with a wordline driver. This can either be a single aray on its own if there is no hierarchical WL or it can be combined into a larger array with hierarchical WL. """ def __init__(self, name, rows, cols): - super().__init__(name, rows, cols) + super().__init__(name=name, rows=rows, cols=cols, column_offset=0) self.create_netlist() if not OPTS.netlist_only: @@ -36,7 +36,7 @@ class local_bitcell_array(bitcell_base_array): def create_layout(self): - self.place_array("bit_r{0}_c{1}") + self.place() self.add_layout_pins() @@ -46,21 +46,26 @@ class local_bitcell_array(bitcell_base_array): def add_modules(self): """ Add the modules used in this design """ - self.bit_array = factory.create(module_type="bitcell_array", - rows=self.rows, - cols=self.cols, - column_offset=self.column_offset) - self.add_mod(self.bit_array) + # This is just used for names + self.cell = factory.create(module_type="bitcell") + + self.bitcell_array = factory.create(module_type="bitcell_array", + rows=self.row_size, + cols=self.column_size) + self.add_mod(self.bitcell_array) - self.wl_array = factory.create(module_type="wordline_driver_array", - rows=self.rows, - cols=self.cols) + self.wl_array = factory.create(module_type="wordline_buffer_array", + rows=self.row_size, + cols=self.column_size) self.add_mod(self.wl_array) def create_instances(self): """ Create the module instances used in this design """ - self.bitcell_inst = self.add_inst(mod=self.bitcell_array) - self.connect_inst(self.get_bitcell_pins(row, col)) - self.wl_inst = self.add_inst(mod=self.wl_array) + self.array_inst = self.add_inst(mod=self.bitcell_array) + self.connect_inst(self.pins) + + #wl_names = self.get_ + self.wl_inst = self.add_inst(mod=self.wl_array, + offset=self.bitcell_inst.lr()) self.connect_inst(self.get_bitcell_pins(row, col)) diff --git a/compiler/modules/wordline_buffer_array.py b/compiler/modules/wordline_buffer_array.py index 7dad327d..be0fe1f7 100644 --- a/compiler/modules/wordline_buffer_array.py +++ b/compiler/modules/wordline_buffer_array.py @@ -53,7 +53,7 @@ class wordline_buffer_array(design.design): self.add_pin("in_{0}".format(i), "INPUT") # Outputs from wordline_driver. for i in range(self.rows): - self.add_pin("wl_{0}".format(i), "OUTPUT") + self.add_pin("out_{0}".format(i), "OUTPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") @@ -100,7 +100,7 @@ class wordline_buffer_array(design.design): self.wld_inst.append(self.add_inst(name="wld{0}".format(row), mod=self.wl_driver)) self.connect_inst(["in_{0}".format(row), - "wl_{0}".format(row), + "out_{0}".format(row), "vdd", "gnd"]) def place_drivers(self): @@ -131,7 +131,7 @@ class wordline_buffer_array(design.design): # output each WL on the right wl_offset = inst.get_pin("Z").rc() - self.add_layout_pin_segment_center(text="wl_{0}".format(row), + self.add_layout_pin_segment_center(text="out_{0}".format(row), layer=self.route_layer, start=wl_offset, end=wl_offset - vector(self.m1_width, 0)) diff --git a/compiler/tests/05_local_bitcell_array_test.py b/compiler/tests/05_local_bitcell_array_test.py new file mode 100755 index 00000000..1a717fb2 --- /dev/null +++ b/compiler/tests/05_local_bitcell_array_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# 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 unittest +from testutils import * +import sys,os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class local_bitcell_array_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + debug.info(2, "Testing 4x4 local bitcell array for 6t_cell") + a = factory.create(module_type="local_bitcell_array", cols=4, rows=4) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From 26b01e37c6514100eb8f0e68641b301295a8e289 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 27 Jul 2020 13:59:35 -0700 Subject: [PATCH 07/40] Fix pbuf test info --- compiler/tests/04_pbuf_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/tests/04_pbuf_test.py b/compiler/tests/04_pbuf_test.py index ffd06962..7ed92ab8 100755 --- a/compiler/tests/04_pbuf_test.py +++ b/compiler/tests/04_pbuf_test.py @@ -21,7 +21,7 @@ class pbuf_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - debug.info(2, "Testing inverter/buffer 4x 8x") + debug.info(2, "Testing buffer 8x") a = factory.create(module_type="pbuf", size=8) self.local_check(a) From 69cab426760def426a363934bb66a4e818ac15b2 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 27 Jul 2020 13:59:55 -0700 Subject: [PATCH 08/40] Add pbuf_dec gate --- compiler/pgates/pbuf_dec.py | 125 ++++++++++++++++++++++++++ compiler/tests/04_pbuf_dec_8x_test.py | 40 +++++++++ 2 files changed, 165 insertions(+) create mode 100644 compiler/pgates/pbuf_dec.py create mode 100755 compiler/tests/04_pbuf_dec_8x_test.py diff --git a/compiler/pgates/pbuf_dec.py b/compiler/pgates/pbuf_dec.py new file mode 100644 index 00000000..e5018b62 --- /dev/null +++ b/compiler/pgates/pbuf_dec.py @@ -0,0 +1,125 @@ +# 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 +from vector import vector +import pgate +from sram_factory import factory + + +class pbuf_dec(pgate.pgate): + """ + This is a simple buffer used for driving wordlines. + """ + def __init__(self, name, size=4, height=None): + + debug.info(1, "creating {0} with size of {1}".format(name, size)) + self.add_comment("size: {}".format(size)) + + self.stage_effort = 4 + self.size = size + self.height = height + + # Creates the netlist and layout + pgate.pgate.__init__(self, name, height) + + def create_netlist(self): + self.add_pins() + self.create_modules() + self.create_insts() + + def create_layout(self): + self.width = self.inv1.width + self.inv2.width + self.place_insts() + self.add_wires() + self.add_layout_pins() + self.route_supply_rails() + self.add_boundary() + + def add_pins(self): + self.add_pin("A", "INPUT") + self.add_pin("Z", "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def create_modules(self): + # Shield the cap, but have at least a stage effort of 4 + input_size = max(1, int(self.size / self.stage_effort)) + self.inv1 = factory.create(module_type="pinv_dec", + size=input_size, + height=self.height) + self.add_mod(self.inv1) + + self.inv2 = factory.create(module_type="pinv_dec", + size=self.size, + height=self.height) + self.add_mod(self.inv2) + + def create_insts(self): + self.inv1_inst = self.add_inst(name="buf_inv1", + mod=self.inv1) + self.connect_inst(["A", "zb_int", "vdd", "gnd"]) + + self.inv2_inst = self.add_inst(name="buf_inv2", + mod=self.inv2) + self.connect_inst(["zb_int", "Z", "vdd", "gnd"]) + + def place_insts(self): + # Add INV1 to the right + self.inv1_inst.place(vector(0, 0)) + + # Add INV2 to the right + self.inv2_inst.place(vector(self.inv1_inst.rx(), 0)) + + def add_wires(self): + # inv1 Z to inv2 A + z1_pin = self.inv1_inst.get_pin("Z") + a2_pin = self.inv2_inst.get_pin("A") + mid_loc = vector(a2_pin.cx(), z1_pin.cy()) + self.add_path(self.route_layer, + [z1_pin.rc(), mid_loc, a2_pin.lc()], + width=a2_pin.width()) + + def route_supply_rails(self): + """ Add vdd/gnd rails to the top, (middle), and bottom. """ + self.copy_layout_pin(self.inv1_inst, "vdd") + self.copy_layout_pin(self.inv1_inst, "gnd") + self.copy_layout_pin(self.inv2_inst, "vdd") + self.copy_layout_pin(self.inv2_inst, "gnd") + + def add_layout_pins(self): + z_pin = self.inv2_inst.get_pin("Z") + self.add_layout_pin_rect_center(text="Z", + layer=z_pin.layer, + offset=z_pin.center(), + width=z_pin.width(), + height=z_pin.height()) + + a_pin = self.inv1_inst.get_pin("A") + self.add_layout_pin_rect_center(text="A", + layer=a_pin.layer, + offset=a_pin.center(), + width=a_pin.width(), + height=a_pin.height()) + + def get_stage_efforts(self, external_cout, inp_is_rise=False): + """Get the stage efforts of the A -> Z path""" + stage_effort_list = [] + stage1_cout = self.inv2.get_cin() + stage1 = self.inv1.get_stage_effort(stage1_cout, inp_is_rise) + stage_effort_list.append(stage1) + last_stage_is_rise = stage1.is_rise + + stage2 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise) + stage_effort_list.append(stage2) + + return stage_effort_list + + def get_cin(self): + """Returns the relative capacitance of the input""" + input_cin = self.inv1.get_cin() + return input_cin diff --git a/compiler/tests/04_pbuf_dec_8x_test.py b/compiler/tests/04_pbuf_dec_8x_test.py new file mode 100755 index 00000000..ad1665fe --- /dev/null +++ b/compiler/tests/04_pbuf_dec_8x_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# 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 unittest +from testutils import * +import sys,os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + +class pbuf_dec_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(2, "Checking 8x size decoder buffer") + a = factory.create(module_type="pbuf_dec", size=8) + self.local_check(a) + + globals.end_openram() + +# instantiate a copdsay of the class to actually run the test +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From c65178f86c14cbbef87293019a7030fa232ffa94 Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Mon, 27 Jul 2020 15:43:50 -0700 Subject: [PATCH 09/40] Fixed issue with sen delay measure getting mixed with voltage checks --- compiler/characterizer/delay.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index b7faaec3..9d36fce7 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -185,8 +185,7 @@ class delay(simulation): self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name+"{}", "FALL", "RISE", measure_scale=1e9) self.sen_meas.meta_str = sram_op.READ_ZERO self.sen_meas.meta_add_delay = True - self.dout_volt_meas.append(self.sen_meas) - + return self.dout_volt_meas def create_read_bit_measures(self): From 9ea3616260820c2010316047a29916235d5ad0b8 Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Mon, 27 Jul 2020 15:47:02 -0700 Subject: [PATCH 10/40] Changed multiport characterization warning to better fit --- compiler/characterizer/delay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 9d36fce7..1fcd86f4 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -1350,7 +1350,7 @@ class delay(simulation): Return the analytical model results for the SRAM. """ if OPTS.num_rw_ports > 1 or OPTS.num_w_ports > 0 and OPTS.num_r_ports > 0: - debug.warning("Analytical characterization results are not supported for multiport.") + debug.warning("Analytical characterization for multiple read ports may be inaccurate.") # Probe set to 0th bit, does not matter for analytical delay. self.set_probe('0'*self.addr_size, 0) From c260297366f5724e9cdab51e493b175beb8d8358 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 27 Jul 2020 16:22:21 -0700 Subject: [PATCH 11/40] Allow replica_bitcell_array without the replica columns for local wordlines. --- compiler/modules/col_cap_array.py | 4 +- compiler/modules/local_bitcell_array.py | 1 - compiler/modules/replica_bitcell_array.py | 172 ++++++++++++------ compiler/modules/row_cap_array.py | 4 +- .../14_replica_bitcell_array_1rw_1r_test.py | 27 ++- 5 files changed, 141 insertions(+), 67 deletions(-) diff --git a/compiler/modules/col_cap_array.py b/compiler/modules/col_cap_array.py index d9fe78b5..a2bf8379 100644 --- a/compiler/modules/col_cap_array.py +++ b/compiler/modules/col_cap_array.py @@ -13,8 +13,8 @@ class col_cap_array(bitcell_base_array): """ Generate a dummy row/column for the replica array. """ - def __init__(self, cols, rows, column_offset=0, mirror=0, name=""): - super().__init__(cols, rows, name, column_offset) + def __init__(self, rows, cols, column_offset=0, mirror=0, name=""): + super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name) self.mirror = mirror self.no_instances = True diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index 8b56ea19..d446d29c 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -6,7 +6,6 @@ # All rights reserved. # from bitcell_base_array import bitcell_base_array -from tech import drc, spice from globals import OPTS from sram_factory import factory diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 0c08cd56..a0ce8e6e 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -21,7 +21,7 @@ class replica_bitcell_array(design.design): Requires a regular bitcell array, replica bitcell, and dummy bitcell (Bl/BR disconnected). """ - def __init__(self, rows, cols, left_rbl, right_rbl, bitcell_ports, name): + def __init__(self, rows, cols, left_rbl, right_rbl, bitcell_ports, name, add_replica=True): design.design.__init__(self, name) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) self.add_comment("rows: {0} cols: {1}".format(rows, cols)) @@ -31,15 +31,26 @@ class replica_bitcell_array(design.design): self.left_rbl = left_rbl self.right_rbl = right_rbl self.bitcell_ports = bitcell_ports + # If set to false, we increase the height for the replica wordline row, but don't + # actually add the column to this array. This is so the height matches other + # banks that have the replica columns. + # Number of replica columns to actually add + if add_replica: + self.add_left_rbl = self.left_rbl + self.add_right_rbl = self.right_rbl + else: + self.add_left_rbl = 0 + self.add_right_rbl = 0 debug.check(left_rbl + right_rbl == len(self.all_ports), "Invalid number of RBLs for port configuration.") debug.check(left_rbl + right_rbl == len(self.bitcell_ports), "Bitcell ports must match total RBLs.") - # Two dummy rows/cols plus replica for each port - self.extra_rows = 2 + left_rbl + right_rbl - self.extra_cols = 2 + left_rbl + right_rbl + # Two dummy rows plus replica even if we don't add the column + self.extra_rows = 2 + self.left_rbl + self.right_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: @@ -84,28 +95,28 @@ class replica_bitcell_array(design.design): # Bitcell array self.bitcell_array = factory.create(module_type="bitcell_array", - column_offset=1 + self.left_rbl, + column_offset=1 + self.add_left_rbl, cols=self.column_size, rows=self.row_size) self.add_mod(self.bitcell_array) # Replica bitlines self.replica_columns = {} - for bit in range(self.left_rbl + self.right_rbl): + for bit in range(self.add_left_rbl + self.add_right_rbl): # Creating left_rbl - if bit1 port) - for port in range(self.left_rbl): + for port in range(self.add_left_rbl): # Make names for all RBLs wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x), port) for x in range(len(self.cell.get_all_wl_names()))] # Keep track of the pin that is the RBL @@ -184,7 +195,7 @@ class replica_bitcell_array(design.design): # Regular WLs self.replica_col_wl_names.extend(self.bitcell_array_wl_names) # Right port WLs (one dummy for each port when we allow >1 port) - for port in range(self.left_rbl, self.left_rbl + self.right_rbl): + for port in range(self.add_left_rbl, self.add_left_rbl + self.add_right_rbl): # Make names for all RBLs wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x), port) for x in range(len(self.cell.get_all_wl_names()))] # Keep track of the pin that is the RBL @@ -192,14 +203,33 @@ class replica_bitcell_array(design.design): self.replica_col_wl_names.extend(wl_names) self.replica_col_wl_names.extend(["{0}_top".format(x) for x in self.dummy_cell_wl_names]) + # Create the full WL names include dummy, replica, and regular bit cells # Left/right dummy columns are connected identically to the replica column - self.dummy_col_wl_names = self.replica_col_wl_names + self.dummy_col_wl_names = [] + self.dummy_col_wl_names.extend(["{0}_bot".format(x) for x in self.dummy_cell_wl_names]) + # Left port WLs (one dummy for each port when we allow >1 port) + for port in range(self.left_rbl): + # Make names for all RBLs + wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x), port) for x in range(len(self.cell.get_all_wl_names()))] + # Keep track of the pin that is the RBL + self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]] + self.dummy_col_wl_names.extend(wl_names) + # Regular WLs + self.dummy_col_wl_names.extend(self.bitcell_array_wl_names) + # Right port WLs (one dummy for each port when we allow >1 port) + for port in range(self.left_rbl, self.left_rbl + self.right_rbl): + # Make names for all RBLs + wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x), port) for x in range(len(self.cell.get_all_wl_names()))] + # Keep track of the pin that is the RBL + self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]] + self.dummy_col_wl_names.extend(wl_names) + self.dummy_col_wl_names.extend(["{0}_top".format(x) for x in self.dummy_cell_wl_names]) # Per port bitline names self.replica_bl_names = {} self.replica_wl_names = {} # Array of all port bitline names - for port in range(self.left_rbl + self.right_rbl): + for port in range(self.add_left_rbl + self.add_right_rbl): left_names=["rbl_{0}_{1}".format(self.cell.get_bl_name(x), port) for x in range(len(self.all_ports))] right_names=["rbl_{0}_{1}".format(self.cell.get_br_name(x), port) for x in range(len(self.all_ports))] # Keep track of the left pins that are the RBL @@ -209,6 +239,8 @@ class replica_bitcell_array(design.design): bl_names = [x for t in zip(left_names, right_names) for x in t] self.replica_bl_names[port] = bl_names + # Array of all port wl names + for port in range(self.left_rbl + self.right_rbl): wl_names = ["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()] self.replica_wl_names[port] = wl_names @@ -243,13 +275,14 @@ class replica_bitcell_array(design.design): # Replica columns self.replica_col_inst = {} - for port in range(self.left_rbl + self.right_rbl): + for port in range(self.add_left_rbl + self.add_right_rbl): self.replica_col_inst[port]=self.add_inst(name="replica_col_{}".format(port), mod=self.replica_columns[port]) self.connect_inst(self.replica_bl_names[port] + self.replica_col_wl_names + supplies) - + # Dummy rows under the bitcell array (connected with with the replica cell wl) self.dummy_row_replica_inst = {} + # Note, this is the number of left and right even if we aren't adding the columns to this bitcell array! for port in range(self.left_rbl + self.right_rbl): self.dummy_row_replica_inst[port]=self.add_inst(name="dummy_row_{}".format(port), mod=self.dummy_row) @@ -277,41 +310,18 @@ class replica_bitcell_array(design.design): self.width = (self.column_size + self.extra_cols) * self.cell.width # This is a bitcell x bitcell offset to scale - offset = vector(self.cell.width, self.cell.height) + self.bitcell_offset = vector(self.cell.width, self.cell.height) + # Everything is computed with the main array at (0, 0) to start self.bitcell_array_inst.place(offset=[0, 0]) - # To the left of the bitcell array - for bit in range(self.left_rbl): - self.replica_col_inst[bit].place(offset=offset.scale(-bit - 1, -self.left_rbl - 1)) - # To the right of the bitcell array - for bit in range(self.right_rbl): - self.replica_col_inst[self.left_rbl + bit].place(offset=offset.scale(bit, -self.left_rbl - 1) + self.bitcell_array_inst.lr()) + self.add_replica_columns() + + self.add_end_caps() - # FIXME: These depend on the array size itself - # Far top dummy row (first row above array is NOT flipped) - flip_dummy = self.right_rbl % 2 - self.dummy_row_top_inst.place(offset=offset.scale(0, self.right_rbl + flip_dummy) + self.bitcell_array_inst.ul(), - mirror="MX" if flip_dummy else "R0") - # FIXME: These depend on the array size itself - # Far bottom dummy row (first row below array IS flipped) - flip_dummy = (self.left_rbl + 1) % 2 - self.dummy_row_bot_inst.place(offset=offset.scale(0, -self.left_rbl - 1 + flip_dummy), - mirror="MX" if flip_dummy else "R0") - # Far left dummy col - self.dummy_col_left_inst.place(offset=offset.scale(-self.left_rbl - 1, -self.left_rbl - 1)) - # Far right dummy col - self.dummy_col_right_inst.place(offset=offset.scale(self.right_rbl, -self.left_rbl - 1) + self.bitcell_array_inst.lr()) - - # Replica dummy rows - for bit in range(self.left_rbl): - self.dummy_row_replica_inst[bit].place(offset=offset.scale(0, -bit - bit % 2), - mirror="R0" if bit % 2 else "MX") - for bit in range(self.right_rbl): - self.dummy_row_replica_inst[self.left_rbl + bit].place(offset=offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul(), - mirror="MX" if bit % 2 else "R0") - - self.translate_all(offset.scale(-1 - self.left_rbl, -1 - self.left_rbl)) + # Array was at (0, 0) but move everything so it is at the lower left + # We move DOWN the number of left RBL even if we didn't add the column to this bitcell array + self.translate_all(self.bitcell_offset.scale(-1 - self.add_left_rbl, -1 - self.left_rbl)) self.add_layout_pins() @@ -319,6 +329,49 @@ class replica_bitcell_array(design.design): self.DRC_LVS() + def add_replica_columns(self): + """ Add replica columns on left and right of array """ + + # To the left of the bitcell array + for bit in range(self.add_left_rbl): + self.replica_col_inst[bit].place(offset=self.bitcell_offset.scale(-bit - 1, -self.add_left_rbl - 1)) + # To the right of the bitcell array + for bit in range(self.add_right_rbl): + self.replica_col_inst[self.add_left_rbl + bit].place(offset=self.bitcell_offset.scale(bit, -self.add_left_rbl - 1) + self.bitcell_array_inst.lr()) + + # Replica dummy rows + # Add the dummy rows even if we aren't adding the replica column to this bitcell array + for bit in range(self.left_rbl): + self.dummy_row_replica_inst[bit].place(offset=self.bitcell_offset.scale(0, -bit - bit % 2), + mirror="R0" if bit % 2 else "MX") + for bit in range(self.right_rbl): + self.dummy_row_replica_inst[self.left_rbl + bit].place(offset=self.bitcell_offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul(), + mirror="MX" if bit % 2 else "R0") + + def add_end_caps(self): + """ Add dummy cells or end caps around the array """ + + # FIXME: These depend on the array size itself + # Far top dummy row (first row above array is NOT flipped) + flip_dummy = self.right_rbl % 2 + dummy_row_offset = self.bitcell_offset.scale(0, self.right_rbl + flip_dummy) + self.bitcell_array_inst.ul() + self.dummy_row_top_inst.place(offset=dummy_row_offset, + mirror="MX" if flip_dummy else "R0") + # FIXME: These depend on the array size itself + # Far bottom dummy row (first row below array IS flipped) + flip_dummy = (self.left_rbl + 1) % 2 + dummy_row_offset = self.bitcell_offset.scale(0, -self.left_rbl - 1 + flip_dummy) + self.dummy_row_bot_inst.place(offset=dummy_row_offset, + mirror="MX" if flip_dummy else "R0") + # Far left dummy col + # Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array + dummy_col_offset = self.bitcell_offset.scale(-self.add_left_rbl - 1, -self.left_rbl - 1) + self.dummy_col_left_inst.place(offset=dummy_col_offset) + # Far right dummy col + # Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array + dummy_col_offset = self.bitcell_offset.scale(self.add_right_rbl, -self.left_rbl - 1) + self.bitcell_array_inst.lr() + self.dummy_col_right_inst.place(offset=dummy_col_offset) + def add_layout_pins(self): """ Add the layout pins """ @@ -345,13 +398,13 @@ class replica_bitcell_array(design.design): height=self.height) # Replica wordlines - for port in range(self.left_rbl + self.right_rbl): + for port in range(self.add_left_rbl + self.add_right_rbl): inst = self.replica_col_inst[port] for (pin_name, wl_name) in zip(self.cell.get_all_wl_names(), self.replica_wl_names[port]): # +1 for dummy row pin_bit = port + 1 # +row_size if above the array - if port>=self.left_rbl: + if port>=self.add_left_rbl: pin_bit += self.row_size pin_name += "_{}".format(pin_bit) @@ -362,12 +415,13 @@ class replica_bitcell_array(design.design): offset=pin.ll().scale(0, 1), width=self.width, height=pin.height()) - + # Replica bitlines - for port in range(self.left_rbl + self.right_rbl): + for port in range(self.add_left_rbl + self.add_right_rbl): inst = self.replica_col_inst[port] for (pin_name, bl_name) in zip(self.cell.get_all_bitline_names(), self.replica_bl_names[port]): pin = inst.get_pin(pin_name) + if bl_name in self.rbl_bl_names or bl_name in self.rbl_br_names: name = bl_name else: diff --git a/compiler/modules/row_cap_array.py b/compiler/modules/row_cap_array.py index bfbd035c..58b33c89 100644 --- a/compiler/modules/row_cap_array.py +++ b/compiler/modules/row_cap_array.py @@ -13,8 +13,8 @@ class row_cap_array(bitcell_base_array): """ Generate a dummy row/column for the replica array. """ - def __init__(self, cols, rows, column_offset=0, mirror=0, name=""): - super().__init__(cols, rows, name, column_offset) + def __init__(self, rows, cols, column_offset=0, mirror=0, name=""): + super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name) self.mirror = mirror self.no_instances = True self.create_netlist() diff --git a/compiler/tests/14_replica_bitcell_array_1rw_1r_test.py b/compiler/tests/14_replica_bitcell_array_1rw_1r_test.py index 626725c4..bfb35cd7 100755 --- a/compiler/tests/14_replica_bitcell_array_1rw_1r_test.py +++ b/compiler/tests/14_replica_bitcell_array_1rw_1r_test.py @@ -24,14 +24,35 @@ class replica_bitcell_array_1rw_1r_test(openram_test): OPTS.num_w_ports = 0 globals.setup_bitcell() - debug.info(2, "Testing 4x4 array for cell_1rw_1r") - a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=1, bitcell_ports=[0, 1]) + debug.info(2, "Testing 4x4 non-replica array for cell_1rw_1r") + a = factory.create(module_type="replica_bitcell_array", + cols=4, + rows=4, + left_rbl=1, + right_rbl=1, + bitcell_ports=[0, 1], + add_replica=False) self.local_check(a) + debug.info(2, "Testing 4x4 array for cell_1rw_1r") + a = factory.create(module_type="replica_bitcell_array", + cols=4, + rows=4, + left_rbl=1, + right_rbl=1, + bitcell_ports=[0, 1]) + self.local_check(a) + + # Sky 130 has restrictions on the symmetries if OPTS.tech_name != "sky130": debug.info(2, "Testing 4x4 array for cell_1rw_1r") - a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=2, right_rbl=0, bitcell_ports=[0, 1]) + a = factory.create(module_type="replica_bitcell_array", + cols=4, + rows=4, + left_rbl=2, + right_rbl=0, + bitcell_ports=[0, 1]) self.local_check(a) globals.end_openram() From b4dafac489d4f618bcb3fc080a97f5688e5f1fac Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Mon, 27 Jul 2020 23:55:03 -0700 Subject: [PATCH 12/40] Fixed issue with sen measurement not being added --- compiler/characterizer/delay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 1fcd86f4..afb9c7f6 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -186,7 +186,7 @@ class delay(simulation): self.sen_meas.meta_str = sram_op.READ_ZERO self.sen_meas.meta_add_delay = True - return self.dout_volt_meas + return self.dout_volt_meas + [self.sen_meas] def create_read_bit_measures(self): """ Adds bit measurements for read0 and read1 cycles """ From 2fa561f98f5aee68ba26f611da370439c4e979d8 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 29 Jul 2020 10:08:13 -0700 Subject: [PATCH 13/40] Local bitcell array edits. Skip test by default. --- compiler/modules/bitcell_base_array.py | 2 +- compiler/modules/local_bitcell_array.py | 40 ++++++++++++------- compiler/tests/05_local_bitcell_array_test.py | 2 +- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 793cfc34..2ef710e3 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -12,7 +12,7 @@ from tech import cell_properties class bitcell_base_array(design.design): """ - Abstract base class for bitcell-arrays -- bitcell, dummy + Abstract base class for bitcell-arrays -- bitcell, dummy, replica """ def __init__(self, name, rows, cols, column_offset): design.design.__init__(self, name) diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index d446d29c..a9b98490 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -5,20 +5,28 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from bitcell_base_array import bitcell_base_array +import design from globals import OPTS from sram_factory import factory -class local_bitcell_array(bitcell_base_array): +class local_bitcell_array(design.design): """ A local bitcell array is a bitcell array with a wordline driver. This can either be a single aray on its own if there is no hierarchical WL or it can be combined into a larger array with hierarchical WL. """ - def __init__(self, name, rows, cols): - super().__init__(name=name, rows=rows, cols=cols, column_offset=0) + def __init__(self, rows, cols, ports, left_rbl=0, right_rbl=0, name=""): + design.design.__init__(self, name) + debug.info(2, "create sram of size {0} with {1} words".format(self.word_size, + self.num_words)) + self.rows = rows + self.cols = cols + self.left_rbl = left_rbl + self.right_rbl = right_rbl + self.all_ports = ports + self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -48,23 +56,27 @@ class local_bitcell_array(bitcell_base_array): # This is just used for names self.cell = factory.create(module_type="bitcell") - self.bitcell_array = factory.create(module_type="bitcell_array", - rows=self.row_size, - cols=self.column_size) + self.bitcell_array = factory.create(module_type="replica_bitcell_array", + cols=self.cols, + rows=self.rows, + left_rbl=self.left_rbl, + right_rbl=self.right_rbl, + bitcell_ports=self.all_ports) self.add_mod(self.bitcell_array) self.wl_array = factory.create(module_type="wordline_buffer_array", - rows=self.row_size, - cols=self.column_size) + rows=self.rows, + cols=self.cols) self.add_mod(self.wl_array) def create_instances(self): """ Create the module instances used in this design """ - self.array_inst = self.add_inst(mod=self.bitcell_array) + + self.wl_inst = self.add_inst(mod=self.wl_array) + self.connect_inst(self.pins) + + self.array_inst = self.add_inst(mod=self.bitcell_array, + offset=self.wl_inst.lr()) self.connect_inst(self.pins) - #wl_names = self.get_ - self.wl_inst = self.add_inst(mod=self.wl_array, - offset=self.bitcell_inst.lr()) - self.connect_inst(self.get_bitcell_pins(row, col)) diff --git a/compiler/tests/05_local_bitcell_array_test.py b/compiler/tests/05_local_bitcell_array_test.py index 1a717fb2..c5b26b06 100755 --- a/compiler/tests/05_local_bitcell_array_test.py +++ b/compiler/tests/05_local_bitcell_array_test.py @@ -15,7 +15,7 @@ from globals import OPTS from sram_factory import factory import debug - +@unittest.skip("SKIPPING 05_local_bitcell_array_test") class local_bitcell_array_test(openram_test): def runTest(self): From f23d2e36a798685c3d0795f6c4c711da0229afd7 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 29 Jul 2020 10:31:18 -0700 Subject: [PATCH 14/40] Don't obstruct control logic signals with dffs when no column mux. --- compiler/sram/sram_1bank.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index a5dfb0e5..fc390f37 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -160,7 +160,10 @@ class sram_1bank(sram_base): port = 0 # Add the col address flops below the bank to the right of the control logic x_offset = self.control_logic_insts[port].rx() + self.dff.width - y_offset = - self.data_bus_size[port] - self.dff.height + # Place it a data bus below the x-axis, but at least as low as the control logic to not block + # the control logic signals + y_offset = min(-self.data_bus_size[port] - self.dff.height, + self.control_logic_insts[port].by()) if self.col_addr_dff: self.col_addr_pos[port] = vector(x_offset, y_offset) @@ -201,7 +204,10 @@ class sram_1bank(sram_base): # Add the col address flops below the bank to the right of the control logic x_offset = self.control_logic_insts[port].lx() - 2 * self.dff.width - y_offset = self.bank.height + self.data_bus_size[port] + self.dff.height + # Place it a data bus below the x-axis, but at least as high as the control logic to not block + # the control logic signals + y_offset = max(self.bank.height + self.data_bus_size[port] + self.dff.height, + self.control_logic_insts[port].uy() - self.dff.height) if self.col_addr_dff: self.col_addr_pos[port] = vector(x_offset, y_offset) From c6f2edc20d03f292ff19b1f709761f84d6a6eba6 Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Wed, 29 Jul 2020 19:50:06 -0700 Subject: [PATCH 15/40] Changed warning message for multiport analytical characterization. --- compiler/characterizer/delay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index afb9c7f6..3f5d61af 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -1350,7 +1350,7 @@ class delay(simulation): Return the analytical model results for the SRAM. """ if OPTS.num_rw_ports > 1 or OPTS.num_w_ports > 0 and OPTS.num_r_ports > 0: - debug.warning("Analytical characterization for multiple read ports may be inaccurate.") + debug.warning("In analytical mode, all ports have the timing of the first read port.") # Probe set to 0th bit, does not matter for analytical delay. self.set_probe('0'*self.addr_size, 0) From 8fa0065aafb8e98f3b275d2508fb51ee13059cb7 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 30 Jul 2020 11:09:19 -0700 Subject: [PATCH 16/40] Undo PR 82 changes -- broke unit test. --- compiler/verify/calibre.py | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 6d1786c9..443c91ca 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -135,11 +135,11 @@ def write_calibre_lvs_script(cell_name, final_verification): def write_calibre_pex_script(cell_name, extract, output, final_verification): """ Write a pex script that can either just extract the netlist or the netlist+parasitics """ if output == None: - output = cell_name + ".pex.netlist" + output = name + ".pex.netlist" # check if lvs report has been done # if not run drc and lvs - if not os.path.isfile(OPTS.openram_temp + cell_name + ".lvs.report"): + if not os.path.isfile(cell_name + ".lvs.report"): gds_name = OPTS.openram_temp +"/"+ cell_name + ".gds" sp_name = OPTS.openram_temp +"/"+ cell_name + ".sp" run_drc(cell_name, gds_name) @@ -155,7 +155,7 @@ def write_calibre_pex_script(cell_name, extract, output, final_verification): 'pexSourcePath': cell_name + ".sp", 'pexSourcePrimary': cell_name, 'pexReportFile': cell_name + ".pex.report", - 'pexPexNetlistFile': output, + 'pexPexNetlistFile': cell_name + ".pex.netlist", 'pexPexReportFile': cell_name + ".pex.report", 'pexMaskDBFile': cell_name + ".maskdb", 'cmnFDIDEFLayoutPath': cell_name + ".def", @@ -195,8 +195,8 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False): filter_gds(cell_name, OPTS.openram_temp + "temp.gds", OPTS.openram_temp + cell_name + ".gds") else: # Copy file to local dir if it isn't already - if not os.path.isfile(gds_name): - shutil.copy(OPTS.output_path+os.path.basename(gds_name),gds_name) + if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): + shutil.copy(gds_name, OPTS.openram_temp) drc_runset = write_calibre_drc_script(cell_name, extract, final_verification) @@ -241,14 +241,10 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): lvs_runset = write_calibre_lvs_script(cell_name, final_verification) # Copy file to local dir if it isn't already -# if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): -# shutil.copy(gds_name, OPTS.openram_temp) -# if os.path.dirname(sp_name)!=OPTS.openram_temp.rstrip('/'): -# shutil.copy(sp_name, OPTS.openram_temp) - if not os.path.isfile(gds_name): - shutil.copy(OPTS.output_path+os.path.basename(gds_name), gds_name) - if not os.path.isfile(sp_name): - shutil.copy(OPTS.output_path+os.path.basename(sp_name), sp_name) + if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): + shutil.copy(gds_name, OPTS.openram_temp) + if os.path.dirname(sp_name)!=OPTS.openram_temp.rstrip('/'): + shutil.copy(sp_name, OPTS.openram_temp) (outfile, errfile, resultsfile) = run_script(cell_name, "lvs") @@ -331,11 +327,6 @@ def run_pex(cell_name, gds_name, sp_name, output=None, final_verification=False) write_calibre_pex_script(cell_name,True,output,final_verification) - if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)): - shutil.copy(gds_name, OPTS.openram_temp + os.path.basename(gds_name)) - if not os.path.isfile(OPTS.openram_temp + os.path.basename(sp_name)): - shutil.copy(sp_name, OPTS.openram_temp + os.path.basename(sp_name)) - (outfile, errfile, resultsfile) = run_script(cell_name, "pex") From 487027a9f2694f364cf1f2d498dc63c2b2d6aae2 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 30 Jul 2020 11:35:13 -0700 Subject: [PATCH 17/40] Fix pex file names --- compiler/sram/sram.py | 4 ++-- compiler/verify/calibre.py | 23 ++++++++++++++++------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/compiler/sram/sram.py b/compiler/sram/sram.py index b2ab1124..686877da 100644 --- a/compiler/sram/sram.py +++ b/compiler/sram/sram.py @@ -100,9 +100,9 @@ class sram(): import verify start_time = datetime.datetime.now() # Output the extracted design if requested - sp_file = OPTS.output_path + "temp_pex.sp" + pexname = OPTS.output_path + self.s.name + ".pex.sp" spname = OPTS.output_path + self.s.name + ".sp" - verify.run_pex(self.s.name, gdsname, spname, output=sp_file) + verify.run_pex(self.s.name, gdsname, spname, output=pexname) print_time("Extraction", datetime.datetime.now(), start_time) else: # Use generated spice file for characterization diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 443c91ca..1c13103d 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -135,11 +135,11 @@ def write_calibre_lvs_script(cell_name, final_verification): def write_calibre_pex_script(cell_name, extract, output, final_verification): """ Write a pex script that can either just extract the netlist or the netlist+parasitics """ if output == None: - output = name + ".pex.netlist" + output = cell_name + ".pex.sp" # check if lvs report has been done # if not run drc and lvs - if not os.path.isfile(cell_name + ".lvs.report"): + if not os.path.isfile(OPTS.openram_temp + cell_name + ".lvs.report"): gds_name = OPTS.openram_temp +"/"+ cell_name + ".gds" sp_name = OPTS.openram_temp +"/"+ cell_name + ".sp" run_drc(cell_name, gds_name) @@ -155,7 +155,7 @@ def write_calibre_pex_script(cell_name, extract, output, final_verification): 'pexSourcePath': cell_name + ".sp", 'pexSourcePrimary': cell_name, 'pexReportFile': cell_name + ".pex.report", - 'pexPexNetlistFile': cell_name + ".pex.netlist", + 'pexPexNetlistFile': output, 'pexPexReportFile': cell_name + ".pex.report", 'pexMaskDBFile': cell_name + ".maskdb", 'cmnFDIDEFLayoutPath': cell_name + ".def", @@ -195,11 +195,14 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False): filter_gds(cell_name, OPTS.openram_temp + "temp.gds", OPTS.openram_temp + cell_name + ".gds") else: # Copy file to local dir if it isn't already - if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): + if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)): shutil.copy(gds_name, OPTS.openram_temp) drc_runset = write_calibre_drc_script(cell_name, extract, final_verification) + if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)): + shutil.copy(gds_name, OPTS.openram_temp + os.path.basename(gds_name)) + (outfile, errfile, resultsfile) = run_script(cell_name, "drc") # check the result for these lines in the summary: @@ -241,9 +244,9 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): lvs_runset = write_calibre_lvs_script(cell_name, final_verification) # Copy file to local dir if it isn't already - if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): + if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)): shutil.copy(gds_name, OPTS.openram_temp) - if os.path.dirname(sp_name)!=OPTS.openram_temp.rstrip('/'): + if not os.path.isfile(OPTS.openram_temp + os.path.basename(sp_name)): shutil.copy(sp_name, OPTS.openram_temp) (outfile, errfile, resultsfile) = run_script(cell_name, "lvs") @@ -325,8 +328,14 @@ def run_pex(cell_name, gds_name, sp_name, output=None, final_verification=False) global num_pex_runs num_pex_runs += 1 - write_calibre_pex_script(cell_name,True,output,final_verification) + write_calibre_pex_script(cell_name, True, output, final_verification) + # Copy file to local dir if it isn't already + if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)): + shutil.copy(gds_name, OPTS.openram_temp) + if not os.path.isfile(OPTS.openram_temp + os.path.basename(sp_name)): + shutil.copy(sp_name, OPTS.openram_temp) + (outfile, errfile, resultsfile) = run_script(cell_name, "pex") From dc55ededc1bb93e84b62877f95065d4411226e48 Mon Sep 17 00:00:00 2001 From: Bob Vanhoof Date: Fri, 31 Jul 2020 12:51:34 +0200 Subject: [PATCH 18/40] fix regession tests after calibre fix --- compiler/verify/calibre.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 6d1786c9..6ee41e5f 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -30,7 +30,7 @@ num_lvs_runs = 0 num_pex_runs = 0 -def write_calibre_drc_script(cell_name, extract, final_verification): +def write_calibre_drc_script(cell_name, extract, final_verification, gds_name): """ Write a Calibre runset file and script to run DRC """ # the runset file contains all the options to run calibre from tech import drc @@ -39,7 +39,7 @@ def write_calibre_drc_script(cell_name, extract, final_verification): drc_runset = { 'drcRulesFile': drc_rules, 'drcRunDir': OPTS.openram_temp, - 'drcLayoutPaths': cell_name + ".gds", + 'drcLayoutPaths': gds_name, 'drcLayoutPrimary': cell_name, 'drcLayoutSystem': 'GDSII', 'drcResultsformat': 'ASCII', @@ -68,7 +68,7 @@ def write_calibre_drc_script(cell_name, extract, final_verification): return drc_runset -def write_calibre_lvs_script(cell_name, final_verification): +def write_calibre_lvs_script(cell_name, final_verification, gds_name, sp_name): """ Write a Calibre runset file and script to run LVS """ from tech import drc @@ -76,9 +76,9 @@ def write_calibre_lvs_script(cell_name, final_verification): lvs_runset = { 'lvsRulesFile': lvs_rules, 'lvsRunDir': OPTS.openram_temp, - 'lvsLayoutPaths': cell_name + ".gds", + 'lvsLayoutPaths': gds_name, 'lvsLayoutPrimary': cell_name, - 'lvsSourcePath': cell_name + ".sp", + 'lvsSourcePath': sp_name, 'lvsSourcePrimary': cell_name, 'lvsSourceSystem': 'SPICE', 'lvsSpiceFile': "{}.spice".format(cell_name), @@ -198,7 +198,7 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False): if not os.path.isfile(gds_name): shutil.copy(OPTS.output_path+os.path.basename(gds_name),gds_name) - drc_runset = write_calibre_drc_script(cell_name, extract, final_verification) + drc_runset = write_calibre_drc_script(cell_name, extract, final_verification, gds_name) (outfile, errfile, resultsfile) = run_script(cell_name, "drc") @@ -238,7 +238,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): global num_lvs_runs num_lvs_runs += 1 - lvs_runset = write_calibre_lvs_script(cell_name, final_verification) + lvs_runset = write_calibre_lvs_script(cell_name, final_verification, gds_name, sp_name) # Copy file to local dir if it isn't already # if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): From 9b8ef5ef57cce9e89b60bca7ec5651ba04baaa43 Mon Sep 17 00:00:00 2001 From: Bob Vanhoof Date: Mon, 3 Aug 2020 10:16:12 +0200 Subject: [PATCH 19/40] fix: generated pex file was not passed correctly to lib characterizer --- compiler/sram/sram.py | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/sram/sram.py b/compiler/sram/sram.py index 686877da..ed09fbe0 100644 --- a/compiler/sram/sram.py +++ b/compiler/sram/sram.py @@ -103,6 +103,7 @@ class sram(): pexname = OPTS.output_path + self.s.name + ".pex.sp" spname = OPTS.output_path + self.s.name + ".sp" verify.run_pex(self.s.name, gdsname, spname, output=pexname) + sp_file = pexname print_time("Extraction", datetime.datetime.now(), start_time) else: # Use generated spice file for characterization From eef97ff21547f62ff8290885ec0037149b286c14 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 6 Aug 2020 11:17:49 -0700 Subject: [PATCH 20/40] Reabstracting bit and word line names. --- compiler/modules/bitcell_array.py | 27 +++--- compiler/modules/bitcell_base_array.py | 82 +++++++++---------- compiler/modules/local_bitcell_array.py | 13 ++- compiler/modules/replica_bitcell_array.py | 9 +- compiler/tests/05_local_bitcell_array_test.py | 9 +- 5 files changed, 67 insertions(+), 73 deletions(-) diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index ce72b137..81f1062f 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -13,9 +13,8 @@ from sram_factory import factory class bitcell_array(bitcell_base_array): """ - Creates a rows x cols array of memory cells. Assumes bit-lines - and word line is connected by abutment. - Connects the word lines and bit lines. + Creates a rows x cols array of memory cells. + Assumes bit-lines and word lines are connected by abutment. """ def __init__(self, rows, cols, column_offset=0, name=""): super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name) @@ -27,7 +26,7 @@ class bitcell_array(bitcell_base_array): # We don't offset this because we need to align # the replica bitcell in the control logic # self.offset_all_coordinates() - + def create_netlist(self): """ Create and connect the netlist """ self.add_modules() @@ -41,7 +40,7 @@ class bitcell_array(bitcell_base_array): self.add_layout_pins() self.add_boundary() - + self.DRC_LVS() def add_modules(self): @@ -58,20 +57,20 @@ class bitcell_array(bitcell_base_array): 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.""" - + # Dynamic Power from Bitline bl_wire = self.gen_bl_wire() cell_load = 2 * bl_wire.return_input_cap() bl_swing = OPTS.rbl_delay_percentage freq = spice["default_event_frequency"] bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing) - + # Calculate the bitcell power which currently only includes leakage cell_power = self.cell.analytical_power(corner, load) - + # Leakage power grows with entire array and bitlines. total_power = self.return_power(cell_power.dynamic + bitline_dynamic * self.column_size, cell_power.leakage * self.column_size * self.row_size) @@ -83,7 +82,8 @@ class bitcell_array(bitcell_base_array): else: width = self.width wl_wire = self.generate_rc_net(int(self.column_size), width, drc("minwidth_m1")) - wl_wire.wire_c = 2 * spice["min_tx_gate_c"] + wl_wire.wire_c # 2 access tx gate per cell + # 2 access tx gate per cell + wl_wire.wire_c = 2 * spice["min_tx_gate_c"] + wl_wire.wire_c return wl_wire def gen_bl_wire(self): @@ -93,7 +93,8 @@ class bitcell_array(bitcell_base_array): height = self.height bl_pos = 0 bl_wire = self.generate_rc_net(int(self.row_size - bl_pos), height, drc("minwidth_m1")) - bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell + # 1 access tx d/s per cell + bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c return bl_wire def get_wordline_cin(self): @@ -102,7 +103,7 @@ class bitcell_array(bitcell_base_array): bitcell_wl_cin = self.cell.get_wl_cin() total_cin = bitcell_wl_cin * self.column_size return total_cin - + def graph_exclude_bits(self, targ_row, targ_col): """Excludes bits in column from being added to graph except target""" # Function is not robust with column mux configurations @@ -111,7 +112,7 @@ class bitcell_array(bitcell_base_array): if row == targ_row and col == targ_col: continue self.graph_inst_exclude.add(self.cell_inst[row, col]) - + def get_cell_name(self, inst_name, row, col): """Gets the spice name of the target bitcell.""" return inst_name + '.x' + self.cell_inst[row, col].name, self.cell_inst[row, col] diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 2ef710e3..292831b5 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -8,6 +8,7 @@ import debug import design from tech import cell_properties +from sram_factory import factory class bitcell_base_array(design.design): @@ -15,7 +16,7 @@ class bitcell_base_array(design.design): Abstract base class for bitcell-arrays -- bitcell, dummy, replica """ def __init__(self, name, rows, cols, column_offset): - design.design.__init__(self, name) + super().__init__(name) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) self.add_comment("rows: {0} cols: {1}".format(rows, cols)) @@ -23,41 +24,40 @@ class bitcell_base_array(design.design): self.row_size = rows self.column_offset = column_offset - def get_all_bitline_names(self): + # Bitcell for port names only + self.cell = factory.create(module_type="bitcell") + + self.create_all_bitline_names() + self.create_all_wordline_names() - res = list() + def get_all_bitline_names(self, prefix=""): + return [prefix + x for x in self.bitline_names] + + def create_all_bitline_names(self): + self.bitline_names = list() bitline_names = self.cell.get_all_bitline_names() - # We have to keep the order of self.pins, otherwise we connect - # it wrong in the spice netlist - for pin in self.pins: - for bl_name in bitline_names: - if bl_name in pin: - res.append(pin) - return res + for col in range(self.column_size): + for cell_column in bitline_names: + self.bitline_names.append("{0}_{1}".format(cell_column, col)) - def get_all_wordline_names(self): + def get_all_wordline_names(self, prefix=""): + return [prefix + x for x in self.wordline_names] - res = list() + def create_all_wordline_names(self): + + self.wordline_names = list() wordline_names = self.cell.get_all_wl_names() - # We have to keep the order of self.pins, otherwise we connect - # it wrong in the spice netlist - for pin in self.pins: - for wl_name in wordline_names: - if wl_name in pin: - res.append(pin) - return res + for row in range(self.row_size): + for cell_row in wordline_names: + self.wordline_names.append("{0}_{1}".format(cell_row, row)) def add_pins(self): - row_list = self.cell.get_all_wl_names() - column_list = self.cell.get_all_bitline_names() - for col in range(self.column_size): - for cell_column in column_list: - self.add_pin(cell_column+"_{0}".format(col), "INOUT") - for row in range(self.row_size): - for cell_row in row_list: - self.add_pin(cell_row+"_{0}".format(row), "INPUT") + for bl_name in self.bitline_names: + self.add_pin(bl_name, "INOUT") + for wl_name in self.wordline_names: + self.add_pin(wl_name, "INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") @@ -66,13 +66,10 @@ class bitcell_base_array(design.design): indexed by column and row, for instance use in bitcell_array """ bitcell_pins = [] - - pin_names = self.cell.get_all_bitline_names() - for pin in pin_names: - bitcell_pins.append(pin + "_{0}".format(col)) - pin_names = self.cell.get_all_wl_names() - for pin in pin_names: - bitcell_pins.append(pin + "_{0}".format(row)) + # bitlines + bitcell_pins.extend([x for x in self.bitline_names if x.endswith("_{0}".format(col))]) + # wordlines + bitcell_pins.extend([x for x in self.wordline_names if x.endswith("_{0}".format(row))]) bitcell_pins.append("vdd") bitcell_pins.append("gnd") @@ -81,22 +78,21 @@ class bitcell_base_array(design.design): def add_layout_pins(self): """ Add the layout pins """ - row_list = self.cell.get_all_wl_names() - column_list = self.cell.get_all_bitline_names() - + bitline_names = self.cell.get_all_bitline_names() for col in range(self.column_size): - for cell_column in column_list: - bl_pin = self.cell_inst[0, col].get_pin(cell_column) - self.add_layout_pin(text=cell_column + "_{0}".format(col), + for bl_name in bitline_names: + bl_pin = self.cell_inst[0, col].get_pin(bl_name) + self.add_layout_pin(text="{0}_{1}".format(bl_name, col), layer=bl_pin.layer, offset=bl_pin.ll().scale(1, 0), width=bl_pin.width(), height=self.height) + wl_names = self.cell.get_all_wl_names() for row in range(self.row_size): - for cell_row in row_list: - wl_pin = self.cell_inst[row, 0].get_pin(cell_row) - self.add_layout_pin(text=cell_row + "_{0}".format(row), + for wl_name in wl_names: + wl_pin = self.cell_inst[row, 0].get_pin(wl_name) + self.add_layout_pin(text="{0}_{1}".format(wl_name, row), layer=wl_pin.layer, offset=wl_pin.ll().scale(0, 1), width=self.width, diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index a9b98490..ba19ad5e 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -8,6 +8,7 @@ import design from globals import OPTS from sram_factory import factory +import debug class local_bitcell_array(design.design): @@ -26,7 +27,7 @@ class local_bitcell_array(design.design): self.left_rbl = left_rbl self.right_rbl = right_rbl self.all_ports = ports - + self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -34,7 +35,7 @@ class local_bitcell_array(design.design): # We don't offset this because we need to align # the replica bitcell in the control logic # self.offset_all_coordinates() - + def create_netlist(self): """ Create and connect the netlist """ self.add_modules() @@ -48,14 +49,14 @@ class local_bitcell_array(design.design): self.add_layout_pins() self.add_boundary() - + self.DRC_LVS() def add_modules(self): """ Add the modules used in this design """ # This is just used for names self.cell = factory.create(module_type="bitcell") - + self.bitcell_array = factory.create(module_type="replica_bitcell_array", cols=self.cols, rows=self.rows, @@ -68,7 +69,7 @@ class local_bitcell_array(design.design): rows=self.rows, cols=self.cols) self.add_mod(self.wl_array) - + def create_instances(self): """ Create the module instances used in this design """ @@ -78,5 +79,3 @@ class local_bitcell_array(design.design): self.array_inst = self.add_inst(mod=self.bitcell_array, offset=self.wl_inst.lr()) self.connect_inst(self.pins) - - diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index a0ce8e6e..d035f7b4 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -5,14 +5,14 @@ # import debug -import design +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(design.design): +class replica_bitcell_array(bitcell_base_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 @@ -22,7 +22,7 @@ class replica_bitcell_array(design.design): bitcell (Bl/BR disconnected). """ def __init__(self, rows, cols, left_rbl, right_rbl, bitcell_ports, name, add_replica=True): - design.design.__init__(self, name) + super().__init__(name, rows, cols, column_offset=0) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) self.add_comment("rows: {0} cols: {1}".format(rows, cols)) @@ -90,9 +90,6 @@ class replica_bitcell_array(design.design): 1 x (rows + 4) """ - # Bitcell for port names only - self.cell = factory.create(module_type="bitcell") - # Bitcell array self.bitcell_array = factory.create(module_type="bitcell_array", column_offset=1 + self.add_left_rbl, diff --git a/compiler/tests/05_local_bitcell_array_test.py b/compiler/tests/05_local_bitcell_array_test.py index c5b26b06..99227694 100755 --- a/compiler/tests/05_local_bitcell_array_test.py +++ b/compiler/tests/05_local_bitcell_array_test.py @@ -8,14 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals -from globals import OPTS from sram_factory import factory import debug -@unittest.skip("SKIPPING 05_local_bitcell_array_test") + +#@unittest.skip("SKIPPING 05_local_bitcell_array_test") class local_bitcell_array_test(openram_test): def runTest(self): @@ -25,9 +25,10 @@ class local_bitcell_array_test(openram_test): debug.info(2, "Testing 4x4 local bitcell array for 6t_cell") a = factory.create(module_type="local_bitcell_array", cols=4, rows=4) self.local_check(a) - + globals.end_openram() + # run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() From 30976df48f2f3346831f7b71c8d98f42977a144d Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 6 Aug 2020 11:33:26 -0700 Subject: [PATCH 21/40] Change inheritance inits to use super --- compiler/base/channel_route.py | 2 +- compiler/base/contact.py | 2 +- compiler/base/design.py | 2 +- compiler/base/geometry.py | 8 ++++---- compiler/base/route.py | 2 +- compiler/characterizer/delay.py | 2 +- compiler/characterizer/functional.py | 2 +- compiler/characterizer/measurements.py | 12 ++++++------ compiler/characterizer/model_check.py | 4 ++-- compiler/modules/bank.py | 2 +- compiler/modules/bank_select.py | 2 +- compiler/modules/control_logic.py | 2 +- compiler/modules/delay_chain.py | 2 +- compiler/modules/dff_array.py | 2 +- compiler/modules/dff_buf.py | 2 +- compiler/modules/dff_buf_array.py | 2 +- compiler/modules/dff_inv.py | 2 +- compiler/modules/dff_inv_array.py | 2 +- compiler/modules/hierarchical_decoder.py | 2 +- compiler/modules/hierarchical_predecode.py | 2 +- compiler/modules/hierarchical_predecode2x4.py | 2 +- compiler/modules/hierarchical_predecode3x8.py | 2 +- compiler/modules/hierarchical_predecode4x16.py | 2 +- compiler/modules/multibank.py | 2 +- compiler/modules/port_address.py | 2 +- compiler/modules/port_data.py | 2 +- compiler/modules/precharge_array.py | 2 +- compiler/modules/replica_column.py | 2 +- compiler/modules/sense_amp.py | 2 +- compiler/modules/sense_amp_array.py | 2 +- compiler/modules/single_level_column_mux_array.py | 2 +- compiler/modules/tri_gate_array.py | 2 +- compiler/modules/wordline_driver_array.py | 2 +- compiler/modules/write_driver_array.py | 2 +- compiler/modules/write_mask_and_array.py | 2 +- compiler/pgates/pand2.py | 2 +- compiler/pgates/pand3.py | 2 +- compiler/pgates/pbuf.py | 2 +- compiler/pgates/pdriver.py | 2 +- compiler/pgates/pgate.py | 2 +- compiler/pgates/pinv.py | 2 +- compiler/pgates/pinv_dec.py | 2 +- compiler/pgates/pinvbuf.py | 2 +- compiler/pgates/pnand2.py | 2 +- compiler/pgates/pnand3.py | 2 +- compiler/pgates/pnor2.py | 2 +- compiler/pgates/precharge.py | 2 +- compiler/pgates/ptristate_inv.py | 2 +- compiler/pgates/ptx.py | 2 +- compiler/pgates/pwrite_driver.py | 2 +- compiler/pgates/single_level_column_mux.py | 2 +- compiler/pgates/wordline_driver.py | 2 +- 52 files changed, 61 insertions(+), 61 deletions(-) diff --git a/compiler/base/channel_route.py b/compiler/base/channel_route.py index 00ad6e37..5ec955c1 100644 --- a/compiler/base/channel_route.py +++ b/compiler/base/channel_route.py @@ -97,7 +97,7 @@ class channel_route(design.design): """ name = "cr_{0}".format(channel_route.unique_id) channel_route.unique_id += 1 - design.design.__init__(self, name) + super().__init__(name) self.netlist = netlist self.offset = offset diff --git a/compiler/base/contact.py b/compiler/base/contact.py index cc1ca27a..16c671d4 100644 --- a/compiler/base/contact.py +++ b/compiler/base/contact.py @@ -34,7 +34,7 @@ class contact(hierarchy_design.hierarchy_design): # This will ignore the name parameter since # we can guarantee a unique name here - hierarchy_design.hierarchy_design.__init__(self, name) + super().__init__(name) debug.info(4, "create contact object {0}".format(name)) self.add_comment("layers: {0}".format(layer_stack)) diff --git a/compiler/base/design.py b/compiler/base/design.py index 2b2d7711..2a79120d 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -20,7 +20,7 @@ class design(hierarchy_design): """ def __init__(self, name): - hierarchy_design.__init__(self, name) + super().__init__(name) self.setup_drc_constants() self.setup_layer_constants() diff --git a/compiler/base/geometry.py b/compiler/base/geometry.py index 32af7ee9..171210ad 100644 --- a/compiler/base/geometry.py +++ b/compiler/base/geometry.py @@ -160,7 +160,7 @@ class instance(geometry): """ def __init__(self, name, mod, offset=[0, 0], mirror="R0", rotate=0): """Initializes an instance to represent a module""" - geometry.__init__(self) + super().__init__() debug.check(mirror not in ["R90", "R180", "R270"], "Please use rotation and not mirroring during instantiation.") @@ -284,7 +284,7 @@ class path(geometry): def __init__(self, lpp, coordinates, path_width): """Initializes a path for the specified layer""" - geometry.__init__(self) + super().__init__() self.name = "path" self.layerNumber = lpp[0] self.layerPurpose = lpp[1] @@ -322,7 +322,7 @@ class label(geometry): def __init__(self, text, lpp, offset, zoom=-1): """Initializes a text label for specified layer""" - geometry.__init__(self) + super().__init__() self.name = "label" self.text = text self.layerNumber = lpp[0] @@ -366,7 +366,7 @@ class rectangle(geometry): def __init__(self, lpp, offset, width, height): """Initializes a rectangular shape for specified layer""" - geometry.__init__(self) + super().__init__() self.name = "rect" self.layerNumber = lpp[0] self.layerPurpose = lpp[1] diff --git a/compiler/base/route.py b/compiler/base/route.py index c3e446a3..4e3d8a60 100644 --- a/compiler/base/route.py +++ b/compiler/base/route.py @@ -30,7 +30,7 @@ class route(design): def __init__(self, obj, layer_stack, path, layer_widths=[None,1,None]): name = "route_{0}".format(route.unique_route_id) route.unique_route_id += 1 - design.__init__(self, name) + super().__init__(name) debug.info(3, "create route obj {0}".format(name)) self.obj = obj diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 3f5d61af..54d6217c 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -41,7 +41,7 @@ class delay(simulation): """ def __init__(self, sram, spfile, corner): - simulation.__init__(self, sram, spfile, corner) + super().__init__(sram, spfile, corner) self.targ_read_ports = [] self.targ_write_ports = [] diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index 2c391e38..8574c4f6 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -24,7 +24,7 @@ class functional(simulation): """ def __init__(self, sram, spfile, corner): - simulation.__init__(self, sram, spfile, corner) + super().__init__(sram, spfile, corner) # Seed the characterizer with a constant seed for unit tests if OPTS.is_unit_test: diff --git a/compiler/characterizer/measurements.py b/compiler/characterizer/measurements.py index 54f9973f..7d32c4f7 100644 --- a/compiler/characterizer/measurements.py +++ b/compiler/characterizer/measurements.py @@ -58,7 +58,7 @@ class delay_measure(spice_measurement): def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, targ_dir_str,\ trig_vdd=0.5, targ_vdd=0.5, measure_scale=None, has_port=True): - spice_measurement.__init__(self, measure_name, measure_scale, has_port) + super().__init__(measure_name, measure_scale, has_port) self.set_meas_constants(trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd, targ_vdd) def get_measure_function(self): @@ -95,7 +95,7 @@ class delay_measure(spice_measurement): class slew_measure(delay_measure): def __init__(self, measure_name, signal_name, slew_dir_str, measure_scale=None, has_port=True): - spice_measurement.__init__(self, measure_name, measure_scale, has_port) + super().__init__(measure_name, measure_scale, has_port) self.set_meas_constants(signal_name, slew_dir_str) def set_meas_constants(self, signal_name, slew_dir_str): @@ -120,7 +120,7 @@ class power_measure(spice_measurement): """Generates a spice measurement for the average power between two time points.""" def __init__(self, measure_name, power_type="", measure_scale=None, has_port=True): - spice_measurement.__init__(self, measure_name, measure_scale, has_port) + super().__init__(measure_name, measure_scale, has_port) self.set_meas_constants(power_type) def get_measure_function(self): @@ -144,7 +144,7 @@ class voltage_when_measure(spice_measurement): """Generates a spice measurement to measure the voltage of a signal based on the voltage of another.""" def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, trig_vdd, measure_scale=None, has_port=True): - spice_measurement.__init__(self, measure_name, measure_scale, has_port) + super().__init__(measure_name, measure_scale, has_port) self.set_meas_constants(trig_name, targ_name, trig_dir_str, trig_vdd) def get_measure_function(self): @@ -177,7 +177,7 @@ class voltage_at_measure(spice_measurement): The time is considered variant with different periods.""" def __init__(self, measure_name, targ_name, measure_scale=None, has_port=True): - spice_measurement.__init__(self, measure_name, measure_scale, has_port) + super().__init__(measure_name, measure_scale, has_port) self.set_meas_constants(targ_name) def get_measure_function(self): @@ -198,4 +198,4 @@ class voltage_at_measure(spice_measurement): meas_name = self.name targ_name = self.targ_name_no_port return (meas_name,targ_name,time_at) - \ No newline at end of file + diff --git a/compiler/characterizer/model_check.py b/compiler/characterizer/model_check.py index b35c3c47..52100001 100644 --- a/compiler/characterizer/model_check.py +++ b/compiler/characterizer/model_check.py @@ -26,7 +26,7 @@ class model_check(delay): """ def __init__(self, sram, spfile, corner, custom_delaychain=False): - delay.__init__(self,sram,spfile,corner) + super().__init__(sram, spfile, corner) self.period = tech.spice["feasible_period"] self.create_data_names() self.custom_delaychain=custom_delaychain @@ -446,4 +446,4 @@ class model_check(delay): return name_dict - \ No newline at end of file + diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index b0707edb..cac1e278 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -36,7 +36,7 @@ class bank(design.design): if name == "": name = "bank_{0}_{1}".format(self.word_size, self.num_words) - design.design.__init__(self, name) + super().__init__(name) debug.info(2, "create sram of size {0} with {1} words".format(self.word_size, self.num_words)) diff --git a/compiler/modules/bank_select.py b/compiler/modules/bank_select.py index b6246268..8a776d30 100644 --- a/compiler/modules/bank_select.py +++ b/compiler/modules/bank_select.py @@ -24,7 +24,7 @@ class bank_select(design.design): """ def __init__(self, name="bank_select", port="rw"): - design.design.__init__(self, name) + super().__init__(name) self.port = port diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index a4e26a6f..a17f5aa7 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -23,7 +23,7 @@ class control_logic(design.design): def __init__(self, num_rows, words_per_row, word_size, spare_columns=None, sram=None, port_type="rw", name=""): """ Constructor """ name = "control_logic_" + port_type - design.design.__init__(self, name) + super().__init__(name) debug.info(1, "Creating {}".format(name)) self.add_comment("num_rows: {0}".format(num_rows)) self.add_comment("words_per_row: {0}".format(words_per_row)) diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index c261138a..246299c1 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -21,7 +21,7 @@ class delay_chain(design.design): def __init__(self, name, fanout_list): """init function""" - design.design.__init__(self, name) + super().__init__(name) debug.info(1, "creating delay chain {0}".format(str(fanout_list))) self.add_comment("fanouts: {0}".format(str(fanout_list))) diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index d3f9b68e..c4f85a6d 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -24,7 +24,7 @@ class dff_array(design.design): if name=="": name = "dff_array_{0}x{1}".format(rows, columns) - design.design.__init__(self, name) + super().__init__(name) debug.info(1, "Creating {0} rows={1} cols={2}".format(self.name, self.rows, self.columns)) self.add_comment("rows: {0} cols: {1}".format(rows, columns)) diff --git a/compiler/modules/dff_buf.py b/compiler/modules/dff_buf.py index a1e54a4d..1657d7a8 100644 --- a/compiler/modules/dff_buf.py +++ b/compiler/modules/dff_buf.py @@ -27,7 +27,7 @@ class dff_buf(design.design): if name=="": name = "dff_buf_{0}".format(dff_buf.unique_id) dff_buf.unique_id += 1 - design.design.__init__(self, name) + super().__init__(name) debug.info(1, "Creating {}".format(self.name)) self.add_comment("inv1: {0} inv2: {1}".format(inv1_size, inv2_size)) diff --git a/compiler/modules/dff_buf_array.py b/compiler/modules/dff_buf_array.py index 1cbd9284..88852d45 100644 --- a/compiler/modules/dff_buf_array.py +++ b/compiler/modules/dff_buf_array.py @@ -27,7 +27,7 @@ class dff_buf_array(design.design): if name=="": name = "dff_buf_array_{0}x{1}_{2}".format(rows, columns, dff_buf_array.unique_id) dff_buf_array.unique_id += 1 - design.design.__init__(self, name) + super().__init__(name) debug.info(1, "Creating {}".format(self.name)) self.add_comment("rows: {0} cols: {1}".format(rows, columns)) self.add_comment("inv1: {0} inv2: {1}".format(inv1_size, inv2_size)) diff --git a/compiler/modules/dff_inv.py b/compiler/modules/dff_inv.py index 9dcb84c5..033312ef 100644 --- a/compiler/modules/dff_inv.py +++ b/compiler/modules/dff_inv.py @@ -25,7 +25,7 @@ class dff_inv(design.design): if name=="": name = "dff_inv_{0}".format(dff_inv.unique_id) dff_inv.unique_id += 1 - design.design.__init__(self, name) + super().__init__(name) debug.info(1, "Creating {}".format(self.name)) self.add_comment("inv: {0}".format(inv_size)) diff --git a/compiler/modules/dff_inv_array.py b/compiler/modules/dff_inv_array.py index aadb4257..6b08bcce 100644 --- a/compiler/modules/dff_inv_array.py +++ b/compiler/modules/dff_inv_array.py @@ -27,7 +27,7 @@ class dff_inv_array(design.design): if name=="": name = "dff_inv_array_{0}x{1}_{2}".format(rows, columns, dff_inv_array.unique_id) dff_inv_array.unique_id += 1 - design.design.__init__(self, name) + super().__init__(name) debug.info(1, "Creating {}".format(self.name)) self.add_comment("rows: {0} cols: {1}".format(rows, columns)) self.add_comment("inv1: {0}".format(inv1_size)) diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index dbacd051..e32fe1c6 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -18,7 +18,7 @@ class hierarchical_decoder(design.design): Dynamically generated hierarchical decoder. """ def __init__(self, name, num_outputs): - design.design.__init__(self, name) + super().__init__(name) self.AND_FORMAT = "DEC_AND_{0}" diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index a89f5fa6..9c34735d 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -31,7 +31,7 @@ class hierarchical_predecode(design.design): self.column_decoder = (height != b.height) self.number_of_outputs = int(math.pow(2, self.number_of_inputs)) - design.design.__init__(self, name) + super().__init__(name) def add_pins(self): for k in range(self.number_of_inputs): diff --git a/compiler/modules/hierarchical_predecode2x4.py b/compiler/modules/hierarchical_predecode2x4.py index 9c7ddfa3..3c1daa6a 100644 --- a/compiler/modules/hierarchical_predecode2x4.py +++ b/compiler/modules/hierarchical_predecode2x4.py @@ -14,7 +14,7 @@ class hierarchical_predecode2x4(hierarchical_predecode): Pre 2x4 decoder used in hierarchical_decoder. """ def __init__(self, name, height=None): - hierarchical_predecode.__init__(self, name, 2, height) + super().__init__( name, 2, height) self.create_netlist() if not OPTS.netlist_only: diff --git a/compiler/modules/hierarchical_predecode3x8.py b/compiler/modules/hierarchical_predecode3x8.py index e8c44e48..7513ed7c 100644 --- a/compiler/modules/hierarchical_predecode3x8.py +++ b/compiler/modules/hierarchical_predecode3x8.py @@ -14,7 +14,7 @@ class hierarchical_predecode3x8(hierarchical_predecode): Pre 3x8 decoder used in hierarchical_decoder. """ def __init__(self, name, height=None): - hierarchical_predecode.__init__(self, name, 3, height) + super().__init__(name, 3, height) self.create_netlist() if not OPTS.netlist_only: diff --git a/compiler/modules/hierarchical_predecode4x16.py b/compiler/modules/hierarchical_predecode4x16.py index 4a258bfb..3b423fde 100644 --- a/compiler/modules/hierarchical_predecode4x16.py +++ b/compiler/modules/hierarchical_predecode4x16.py @@ -14,7 +14,7 @@ class hierarchical_predecode4x16(hierarchical_predecode): Pre 4x16 decoder used in hierarchical_decoder. """ def __init__(self, name, height=None): - hierarchical_predecode.__init__(self, name, 4, height) + super().__init__(name, 4, height) self.create_netlist() if not OPTS.netlist_only: diff --git a/compiler/modules/multibank.py b/compiler/modules/multibank.py index bf19954b..48bf5f1f 100644 --- a/compiler/modules/multibank.py +++ b/compiler/modules/multibank.py @@ -26,7 +26,7 @@ class multibank(design.design): def __init__(self, name, word_size, num_words, words_per_row, num_banks=1): - design.design.__init__(self, name) + super().__init__(name) debug.info(2, "create sram of size {0} with {1} words".format(word_size,num_words)) self.word_size = word_size diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 980c9d96..532463a7 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -25,7 +25,7 @@ class port_address(design.design): if name == "": name = "port_address_{0}_{1}".format(cols, rows) - design.design.__init__(self, name) + super().__init__(name) debug.info(2, "create data port of cols {0} rows {1}".format(cols, rows)) self.create_netlist() diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index bd6b39e2..eb827f2f 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -32,7 +32,7 @@ class port_data(design.design): if name == "": name = "port_data_{0}".format(self.port) - design.design.__init__(self, name) + super().__init__(name) debug.info(2, "create data port of size {0} with {1} words per row".format(self.word_size, self.words_per_row)) diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index d37de64f..c2d3d986 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -20,7 +20,7 @@ class precharge_array(design.design): """ def __init__(self, name, columns, size=1, bitcell_bl="bl", bitcell_br="br", column_offset=0): - design.design.__init__(self, name) + 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)) diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index 9613e6fa..31ca4180 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -22,7 +22,7 @@ class replica_column(design.design): def __init__(self, name, rows, left_rbl, right_rbl, replica_bit, column_offset=0): - design.design.__init__(self, name) + super().__init__(name) self.rows = rows self.left_rbl = left_rbl diff --git a/compiler/modules/sense_amp.py b/compiler/modules/sense_amp.py index 35fbdf42..67703903 100644 --- a/compiler/modules/sense_amp.py +++ b/compiler/modules/sense_amp.py @@ -50,7 +50,7 @@ class sense_amp(design.design): return props.sense_amp.pin.en def __init__(self, name): - design.design.__init__(self, name) + super().__init__(name) debug.info(2, "Create sense_amp") self.width = sense_amp.width diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 98cbee66..20f6e06f 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -22,7 +22,7 @@ class sense_amp_array(design.design): def __init__(self, name, word_size, words_per_row, num_spare_cols=None, column_offset=0): - design.design.__init__(self, name) + super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("word_size {0}".format(word_size)) self.add_comment("words_per_row: {0}".format(words_per_row)) diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 8b01d111..f57bbb20 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -21,7 +21,7 @@ class single_level_column_mux_array(design.design): """ def __init__(self, name, columns, word_size, bitcell_bl="bl", bitcell_br="br", column_offset=0): - design.design.__init__(self, name) + 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)) diff --git a/compiler/modules/tri_gate_array.py b/compiler/modules/tri_gate_array.py index e7ebd802..c329a04b 100644 --- a/compiler/modules/tri_gate_array.py +++ b/compiler/modules/tri_gate_array.py @@ -19,7 +19,7 @@ class tri_gate_array(design.design): def __init__(self, columns, word_size, name): """Intial function of tri gate array """ - design.design.__init__(self, name) + super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.columns = columns diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index e8a3c110..61f51404 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -19,7 +19,7 @@ class wordline_driver_array(design.design): """ def __init__(self, name, rows, cols): - design.design.__init__(self, name) + super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("rows: {0} cols: {1}".format(rows, cols)) diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index a6eb1384..665142ec 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -21,7 +21,7 @@ class write_driver_array(design.design): def __init__(self, name, columns, word_size, num_spare_cols=None, write_size=None, column_offset=0): - design.design.__init__(self, name) + super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("columns: {0}".format(columns)) self.add_comment("word_size {0}".format(word_size)) diff --git a/compiler/modules/write_mask_and_array.py b/compiler/modules/write_mask_and_array.py index d48aefef..9b083512 100644 --- a/compiler/modules/write_mask_and_array.py +++ b/compiler/modules/write_mask_and_array.py @@ -19,7 +19,7 @@ class write_mask_and_array(design.design): """ def __init__(self, name, columns, word_size, write_size, column_offset=0): - design.design.__init__(self, name) + super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("columns: {0}".format(columns)) self.add_comment("word_size {0}".format(word_size)) diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index 435ace1f..a46485d0 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -22,7 +22,7 @@ class pand2(pgate.pgate): self.vertical = vertical self.size = size - pgate.pgate.__init__(self, name, height, add_wells) + super().__init__(name, height, add_wells) def create_netlist(self): self.add_pins() diff --git a/compiler/pgates/pand3.py b/compiler/pgates/pand3.py index 92429921..72a57f74 100644 --- a/compiler/pgates/pand3.py +++ b/compiler/pgates/pand3.py @@ -23,7 +23,7 @@ class pand3(pgate.pgate): self.size = size # Creates the netlist and layout - pgate.pgate.__init__(self, name, height, add_wells) + super().__init__(name, height, add_wells) def create_netlist(self): self.add_pins() diff --git a/compiler/pgates/pbuf.py b/compiler/pgates/pbuf.py index 8b9c4eab..d82e2091 100644 --- a/compiler/pgates/pbuf.py +++ b/compiler/pgates/pbuf.py @@ -25,7 +25,7 @@ class pbuf(pgate.pgate): self.height = height # Creates the netlist and layout - pgate.pgate.__init__(self, name, height) + super().__init__(name, height) def create_netlist(self): self.add_pins() diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index 578a11c4..8916f0fa 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -35,7 +35,7 @@ class pdriver(pgate.pgate): debug.error("Cannot specify both size_list and inverting.", -1) # Creates the netlist and layout - pgate.pgate.__init__(self, name, height, add_wells) + super().__init__(name, height, add_wells) def compute_sizes(self): # size_list specified diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index 1e55d5fb..57d93e6f 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -26,7 +26,7 @@ class pgate(design.design): def __init__(self, name, height=None, add_wells=True): """ Creates a generic cell """ - design.design.__init__(self, name) + super().__init__(, name) if height: self.height = height diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index 4caf2a18..db46b6b1 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -44,7 +44,7 @@ class pinv(pgate.pgate): self.pmos_size = beta * size self.beta = beta - pgate.pgate.__init__(self, name, height, add_wells) + super().__init__(name, height, add_wells) def create_netlist(self): """ Calls all functions related to the generation of the netlist """ diff --git a/compiler/pgates/pinv_dec.py b/compiler/pgates/pinv_dec.py index 672bde2d..90c8e579 100644 --- a/compiler/pgates/pinv_dec.py +++ b/compiler/pgates/pinv_dec.py @@ -38,7 +38,7 @@ class pinv_dec(pinv.pinv): else: self.supply_layer = "m2" - pinv.pinv.__init__(self, name, size, beta, self.cell_height, add_wells) + super().__init__(, name, size, beta, self.cell_height, add_wells) def determine_tx_mults(self): """ diff --git a/compiler/pgates/pinvbuf.py b/compiler/pgates/pinvbuf.py index 5b286e9b..f746736c 100644 --- a/compiler/pgates/pinvbuf.py +++ b/compiler/pgates/pinvbuf.py @@ -32,7 +32,7 @@ class pinvbuf(pgate.pgate): self.predriver_size = max(int(self.size / (self.stage_effort / 2)), 1) # Creates the netlist and layout - pgate.pgate.__init__(self, name) + super().__init__(name) def create_netlist(self): self.add_pins() diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index fb6bb210..c1295a1b 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -43,7 +43,7 @@ class pnand2(pgate.pgate): self.pmos_width = self.nearest_bin("pmos", self.pmos_width) # Creates the netlist and layout - pgate.pgate.__init__(self, name, height, add_wells) + super().__init__(name, height, add_wells) def create_netlist(self): self.add_pins() diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index e4e71e61..efcbe369 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -46,7 +46,7 @@ class pnand3(pgate.pgate): self.pmos_width = self.nearest_bin("pmos", self.pmos_width) # Creates the netlist and layout - pgate.pgate.__init__(self, name, height, add_wells) + super().__init__(name, height, add_wells) def add_pins(self): """ Adds pins for spice netlist """ diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index aad405e8..331a0745 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -42,7 +42,7 @@ class pnor2(pgate.pgate): self.pmos_width = self.nearest_bin("pmos", self.pmos_width) # Creates the netlist and layout - pgate.pgate.__init__(self, name, height, add_wells) + super().__init__(name, height, add_wells) def create_netlist(self): self.add_pins() diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index 52d24390..d948056d 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -23,7 +23,7 @@ class precharge(design.design): def __init__(self, name, size=1, bitcell_bl="bl", bitcell_br="br"): debug.info(2, "creating precharge cell {0}".format(name)) - design.design.__init__(self, name) + super().__init__(, name) self.bitcell = factory.create(module_type="bitcell") self.beta = parameter["beta"] diff --git a/compiler/pgates/ptristate_inv.py b/compiler/pgates/ptristate_inv.py index 9fd5f8b6..affc157e 100644 --- a/compiler/pgates/ptristate_inv.py +++ b/compiler/pgates/ptristate_inv.py @@ -38,7 +38,7 @@ class ptristate_inv(pgate.pgate): self.pmos_width = self.pmos_size * drc("minwidth_tx") # Creates the netlist and layout - pgate.pgate.__init__(self, name, height) + super().__init__(name, height) def create_netlist(self): """ Calls all functions related to the generation of the netlist """ diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index b6f839f3..6de86346 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -75,7 +75,7 @@ class ptx(design.design): # replace periods with underscore for newer spice compatibility name = name.replace('.', '_') debug.info(3, "creating ptx {0}".format(name)) - design.design.__init__(self, name) + super().__init__(, name) self.tx_type = tx_type self.mults = mults diff --git a/compiler/pgates/pwrite_driver.py b/compiler/pgates/pwrite_driver.py index 87db7b20..2d091fd0 100644 --- a/compiler/pgates/pwrite_driver.py +++ b/compiler/pgates/pwrite_driver.py @@ -22,7 +22,7 @@ class pwrite_driver(design.design): def __init__(self, name, size=0): debug.error("pwrite_driver not implemented yet.", -1) debug.info(1, "creating pwrite_driver {}".format(name)) - design.design.__init__(self, name) + super().__init__(, name) self.size = size self.beta = parameter["beta"] self.pmos_width = self.beta*self.size*parameter["min_tx_size"] diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py index d2dbacc1..cd9be887 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/single_level_column_mux.py @@ -30,7 +30,7 @@ class single_level_column_mux(pgate.pgate): self.bitcell_bl = bitcell_bl self.bitcell_br = bitcell_br - pgate.pgate.__init__(self, name) + super().__init__(name) def get_bl_names(self): return "bl" diff --git a/compiler/pgates/wordline_driver.py b/compiler/pgates/wordline_driver.py index c8cf1326..b8fa4631 100644 --- a/compiler/pgates/wordline_driver.py +++ b/compiler/pgates/wordline_driver.py @@ -21,7 +21,7 @@ class wordline_driver(design.design): def __init__(self, name, size=1, height=None): debug.info(1, "Creating wordline_driver {}".format(name)) self.add_comment("size: {}".format(size)) - design.design.__init__(self, name) + super().__init__(, name) if height is None: b = factory.create(module_type="bitcell") From 8e890c2014476ad26bf97d2605841888051383a7 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 11 Aug 2020 15:00:29 -0700 Subject: [PATCH 22/40] Replica bitcell with all the fixings --- compiler/modules/bank.py | 2 +- compiler/modules/local_bitcell_array.py | 55 +++- compiler/modules/replica_bitcell_array.py | 273 +++++++++--------- compiler/modules/replica_column.py | 2 - compiler/modules/wordline_buffer_array.py | 5 +- compiler/tests/05_local_bitcell_array_test.py | 8 +- 6 files changed, 197 insertions(+), 148 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index b0707edb..4d0b09fb 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -392,7 +392,7 @@ class bank(design.design): def create_bitcell_array(self): """ Creating Bitcell Array """ - + import pdb; pdb.set_trace() self.bitcell_array_inst=self.add_inst(name="replica_bitcell_array", mod=self.bitcell_array) diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index ba19ad5e..da203de7 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -5,22 +5,22 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design +import bitcell_base_array from globals import OPTS from sram_factory import factory +from vector import vector import debug - -class local_bitcell_array(design.design): +class local_bitcell_array(bitcell_base_array.bitcell_base_array): """ A local bitcell array is a bitcell array with a wordline driver. This can either be a single aray on its own if there is no hierarchical WL or it can be combined into a larger array with hierarchical WL. """ - def __init__(self, rows, cols, ports, left_rbl=0, right_rbl=0, name=""): - design.design.__init__(self, name) - debug.info(2, "create sram of size {0} with {1} words".format(self.word_size, - self.num_words)) + def __init__(self, rows, cols, ports, left_rbl=0, right_rbl=0, add_replica=True, name=""): + super().__init__(name, rows, cols, 0) + debug.info(2, "create local array of size {} rows x {} cols words".format(rows, + cols + left_rbl + right_rbl)) self.rows = rows self.cols = cols @@ -66,16 +66,47 @@ class local_bitcell_array(design.design): self.add_mod(self.bitcell_array) self.wl_array = factory.create(module_type="wordline_buffer_array", - rows=self.rows, + rows=self.rows + len(self.all_ports), cols=self.cols) self.add_mod(self.wl_array) + def add_pins(self): + + self.bitline_names = self.bitcell_array.get_all_bitline_names() + self.add_pin_list(self.bitline_names, "INOUT") + self.wordline_names = self.bitcell_array.get_all_wordline_names() + self.add_pin_list(self.wordline_names, "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + def create_instances(self): """ Create the module instances used in this design """ - self.wl_inst = self.add_inst(mod=self.wl_array) - self.connect_inst(self.pins) + internal_wl_names = [x + "i" for x in self.wordline_names] + self.wl_inst = self.add_inst(name="wl_driver", + mod=self.wl_array) + self.connect_inst(self.wordline_names + internal_wl_names + ["vdd", "gnd"]) - self.array_inst = self.add_inst(mod=self.bitcell_array, + self.array_inst = self.add_inst(name="array", + mod=self.bitcell_array, offset=self.wl_inst.lr()) - self.connect_inst(self.pins) + self.connect_inst(self.bitline_names + internal_wl_names + ["vdd", "gnd"]) + + def place(self): + """ Place the bitcelll array to the right of the wl driver. """ + + self.wl_inst.place(vector(0, 0)) + self.array_inst.place(self.wl_inst.lr()) + + self.height = self.bitcell_array.height + self.width = self.array_inst.rx() + + def add_layout_pins(self): + + for (x, y) in zip(self.bitline_names, self.bitcell_array.get_inouts()): + self.copy_layout_pin(self.array_inst, y, x) + + for (x, y) in zip(self.wordline_names, self.wl_array.get_inputs()): + self.copy_layout_pin(self.wl_inst, y, x) + + diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index d035f7b4..2511ea80 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -42,9 +42,9 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.add_left_rbl = 0 self.add_right_rbl = 0 - debug.check(left_rbl + right_rbl == len(self.all_ports), + debug.check(left_rbl + right_rbl <= len(self.all_ports), "Invalid number of RBLs for port configuration.") - debug.check(left_rbl + right_rbl == len(self.bitcell_ports), + debug.check(left_rbl + right_rbl <= len(self.bitcell_ports), "Bitcell ports must match total RBLs.") # Two dummy rows plus replica even if we don't add the column @@ -134,27 +134,26 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): end_caps_enabled = False # Dummy Row or Col Cap, depending on bitcell array properties - edge_row_module_type = ("col_cap_array" if end_caps_enabled else "dummy_array") - - self.edge_row = factory.create(module_type=edge_row_module_type, + 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.edge_row) + self.add_mod(self.col_cap) # Dummy Col or Row Cap, depending on bitcell array properties - edge_col_module_type = ("row_cap_array" if end_caps_enabled else "dummy_array") + row_cap_module_type = ("row_cap_array" if end_caps_enabled else "dummy_array") - self.edge_col_left = factory.create(module_type=edge_col_module_type, + 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.left_rbl + 1) % 2) - self.add_mod(self.edge_col_left) + self.add_mod(self.row_cap_left) - self.edge_col_right = factory.create(module_type=edge_col_module_type, + self.row_cap_right = factory.create(module_type=row_cap_module_type, cols=1, # dummy column # + left replica column(s) @@ -163,100 +162,111 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): column_offset = 1 + self.add_left_rbl + self.column_size + self.add_right_rbl, rows=self.row_size + self.extra_rows, mirror=(self.left_rbl + 1) %2) - self.add_mod(self.edge_col_right) + self.add_mod(self.row_cap_right) def add_pins(self): - self.bitcell_array_wl_names = self.bitcell_array.get_all_wordline_names() - self.bitcell_array_bl_names = self.bitcell_array.get_all_bitline_names() + + self.add_bitline_pins() + self.add_wordline_pins() + + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def add_bitline_pins(self): + + # All bitline names for all ports + self.bitline_names = [] + # Bitline names for each port + self.bitline_names_by_port = [[] for x in self.all_ports] + # Replica wordlines by port + self.replica_bitline_names = [[] for x in self.all_ports] + # Replica wordlines by port (bl only) + self.replica_bl_names = [[] for x in self.all_ports] + # Dummy wordlines by port + self.dummy_bitline_names = [] + + # Regular array bitline names + self.bitcell_array_bitline_names = self.bitcell_array.get_all_bitline_names() # These are the non-indexed names - self.dummy_cell_wl_names = ["dummy_" + x for x in self.cell.get_all_wl_names()] - self.dummy_cell_bl_names = ["dummy_" + x for x in self.cell.get_all_bitline_names()] - self.dummy_row_bl_names = self.bitcell_array_bl_names + dummy_bitline_names = ["dummy_" + x for x in self.cell.get_all_bitline_names()] + self.dummy_bitline_names.append([x+"_left" for x in dummy_bitline_names]) + self.dummy_bitline_names.append([x+"_right" for x in dummy_bitline_names]) - # A dictionary because some ports may have nothing - self.rbl_bl_names = {} - self.rbl_br_names = {} - self.rbl_wl_names = {} - - # Create the full WL names include dummy, replica, and regular bit cells - self.replica_col_wl_names = [] - self.replica_col_wl_names.extend(["{0}_bot".format(x) for x in self.dummy_cell_wl_names]) - # Left port WLs (one dummy for each port when we allow >1 port) - for port in range(self.add_left_rbl): - # Make names for all RBLs - wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x), port) for x in range(len(self.cell.get_all_wl_names()))] - # Keep track of the pin that is the RBL - self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]] - self.replica_col_wl_names.extend(wl_names) - # Regular WLs - self.replica_col_wl_names.extend(self.bitcell_array_wl_names) - # Right port WLs (one dummy for each port when we allow >1 port) - for port in range(self.add_left_rbl, self.add_left_rbl + self.add_right_rbl): - # Make names for all RBLs - wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x), port) for x in range(len(self.cell.get_all_wl_names()))] - # Keep track of the pin that is the RBL - self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]] - self.replica_col_wl_names.extend(wl_names) - self.replica_col_wl_names.extend(["{0}_top".format(x) for x in self.dummy_cell_wl_names]) - - # Create the full WL names include dummy, replica, and regular bit cells - # Left/right dummy columns are connected identically to the replica column - self.dummy_col_wl_names = [] - self.dummy_col_wl_names.extend(["{0}_bot".format(x) for x in self.dummy_cell_wl_names]) - # Left port WLs (one dummy for each port when we allow >1 port) - for port in range(self.left_rbl): - # Make names for all RBLs - wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x), port) for x in range(len(self.cell.get_all_wl_names()))] - # Keep track of the pin that is the RBL - self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]] - self.dummy_col_wl_names.extend(wl_names) - # Regular WLs - self.dummy_col_wl_names.extend(self.bitcell_array_wl_names) - # Right port WLs (one dummy for each port when we allow >1 port) - for port in range(self.left_rbl, self.left_rbl + self.right_rbl): - # Make names for all RBLs - wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x), port) for x in range(len(self.cell.get_all_wl_names()))] - # Keep track of the pin that is the RBL - self.rbl_wl_names[port]=wl_names[self.bitcell_ports[port]] - self.dummy_col_wl_names.extend(wl_names) - self.dummy_col_wl_names.extend(["{0}_top".format(x) for x in self.dummy_cell_wl_names]) - - # Per port bitline names - self.replica_bl_names = {} - self.replica_wl_names = {} # Array of all port bitline names for port in range(self.add_left_rbl + self.add_right_rbl): left_names=["rbl_{0}_{1}".format(self.cell.get_bl_name(x), port) for x in range(len(self.all_ports))] right_names=["rbl_{0}_{1}".format(self.cell.get_br_name(x), port) for x in range(len(self.all_ports))] # Keep track of the left pins that are the RBL - self.rbl_bl_names[port]=left_names[self.bitcell_ports[port]] - self.rbl_br_names[port]=right_names[self.bitcell_ports[port]] + self.replica_bl_names[port]=left_names[self.bitcell_ports[port]] # Interleave the left and right lists - bl_names = [x for t in zip(left_names, right_names) for x in t] - self.replica_bl_names[port] = bl_names + bitline_names = [x for t in zip(left_names, right_names) for x in t] + self.replica_bitline_names[port] = bitline_names + + # Dummy bitlines are not connected to anything + # br pins are not connected to anything + for port in range(self.add_left_rbl): + self.bitline_names.extend(self.replica_bitline_names[port]) + self.bitline_names.extend(self.bitcell_array_bitline_names) + # br pins are not connected to anything + for port in range(self.left_rbl, self.left_rbl + self.right_rbl): + self.bitline_names.extend(self.replica_bitline_names[port]) + + self.add_pin_list(self.bitline_names, "INOUT") + + def add_wordline_pins(self): + + # All wordline names for all ports + self.wordline_names = [] + # Wordline names for each port + self.wordline_names_by_port = [[] for x in self.all_ports] + # Replica wordlines by port + self.replica_wordline_names = [[] for x in self.all_ports] + # Dummy wordlines + self.dummy_wordline_names = {} + + # Regular array wordline names + self.bitcell_array_wordline_names = self.bitcell_array.get_all_wordline_names() + + # These are the non-indexed names + dummy_cell_wl_names = ["dummy_" + x for x in self.cell.get_all_wl_names()] + + # Create the full WL names include dummy, replica, and regular bit cells + self.wordline_names = [] + + self.dummy_wordline_names["bot"] = ["{0}_bot".format(x) for x in dummy_cell_wl_names] + self.wordline_names.extend(self.dummy_wordline_names["bot"]) + + # Left port WLs + for port in range(self.left_rbl): + # Make names for all RBLs + wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x), port) for x in range(len(self.cell.get_all_wl_names()))] + # Keep track of the pin that is the RBL + self.replica_wordline_names[port] = wl_names + self.wordline_names.extend(wl_names) + + # Regular WLs + self.wordline_names.extend(self.bitcell_array_wordline_names) + + # Right port WLs + for port in range(self.left_rbl, self.left_rbl + self.right_rbl): + # Make names for all RBLs + wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x), port) for x in range(len(self.cell.get_all_wl_names()))] + # Keep track of the pin that is the RBL + self.replica_wordline_names[port] = wl_names + self.wordline_names.extend(wl_names) + + + self.dummy_wordline_names["top"] = ["{0}_top".format(x) for x in dummy_cell_wl_names] + self.wordline_names.extend(self.dummy_wordline_names["top"]) # Array of all port wl names for port in range(self.left_rbl + self.right_rbl): wl_names = ["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()] - self.replica_wl_names[port] = wl_names - - # External pins - self.add_pin_list(self.bitcell_array_bl_names, "INOUT") - # Need to sort by port order since dictionary values may not be in order - bl_names = [self.rbl_bl_names[x] for x in sorted(self.rbl_bl_names.keys())] - br_names = [self.rbl_br_names[x] for x in sorted(self.rbl_br_names.keys())] - for (bl_name, br_name) in zip(bl_names, br_names): - self.add_pin(bl_name, "OUTPUT") - self.add_pin(br_name, "OUTPUT") - self.add_pin_list(self.bitcell_array_wl_names, "INPUT") - # Need to sort by port order since dictionary values may not be in order - wl_names = [self.rbl_wl_names[x] for x in sorted(self.rbl_wl_names.keys())] - for pin_name in wl_names: - self.add_pin(pin_name, "INPUT") - self.add_pin("vdd", "POWER") - self.add_pin("gnd", "GROUND") + self.replica_wordline_names[port] = wl_names + self.add_pin_list(self.wordline_names, "INPUT") + def create_instances(self): """ Create the module instances used in this design """ @@ -268,14 +278,14 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Main array self.bitcell_array_inst=self.add_inst(name="bitcell_array", mod=self.bitcell_array) - self.connect_inst(self.bitcell_array_bl_names + self.bitcell_array_wl_names + supplies) + self.connect_inst(self.bitcell_array_bitline_names + self.bitcell_array_wordline_names + supplies) # Replica columns self.replica_col_inst = {} for port in range(self.add_left_rbl + self.add_right_rbl): self.replica_col_inst[port]=self.add_inst(name="replica_col_{}".format(port), mod=self.replica_columns[port]) - self.connect_inst(self.replica_bl_names[port] + self.replica_col_wl_names + supplies) + self.connect_inst(self.replica_bitline_names[port] + self.wordline_names + supplies) # Dummy rows under the bitcell array (connected with with the replica cell wl) self.dummy_row_replica_inst = {} @@ -283,23 +293,27 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): for port in range(self.left_rbl + self.right_rbl): self.dummy_row_replica_inst[port]=self.add_inst(name="dummy_row_{}".format(port), mod=self.dummy_row) - self.connect_inst(self.dummy_row_bl_names + self.replica_wl_names[port] + supplies) + self.connect_inst(self.bitcell_array_bitline_names + self.replica_wordline_names[port] + supplies) # Top/bottom dummy rows or col caps self.dummy_row_bot_inst=self.add_inst(name="dummy_row_bot", - mod=self.edge_row) - self.connect_inst(self.dummy_row_bl_names + [x + "_bot" for x in self.dummy_cell_wl_names] + supplies) + mod=self.col_cap) + self.connect_inst(self.bitcell_array_bitline_names + + self.dummy_wordline_names["bot"] + + supplies) self.dummy_row_top_inst=self.add_inst(name="dummy_row_top", - mod=self.edge_row) - self.connect_inst(self.dummy_row_bl_names + [x + "_top" for x in self.dummy_cell_wl_names] + supplies) + mod=self.col_cap) + self.connect_inst(self.bitcell_array_bitline_names + + self.dummy_wordline_names["top"] + + supplies) # Left/right Dummy columns self.dummy_col_left_inst=self.add_inst(name="dummy_col_left", - mod=self.edge_col_left) - self.connect_inst([x + "_left" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies) + mod=self.row_cap_left) + self.connect_inst(self.dummy_bitline_names[0] + self.wordline_names + supplies) self.dummy_col_right_inst=self.add_inst(name="dummy_col_right", - mod=self.edge_col_right) - self.connect_inst([x + "_right" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies) + mod=self.row_cap_right) + self.connect_inst(self.dummy_bitline_names[-1] + self.wordline_names + supplies) def create_layout(self): @@ -372,19 +386,20 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def add_layout_pins(self): """ Add the layout pins """ + # All wordlines # Main array wl and bl/br pin_names = self.bitcell_array.get_pin_names() for pin_name in pin_names: - for wl in self.bitcell_array_wl_names: + for wl in self.bitcell_array_wordline_names: if wl in pin_name: 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, + layer=pin.layer, offset=pin.ll().scale(0, 1), width=self.width, height=pin.height()) - for bitline in self.bitcell_array_bl_names: + for bitline in self.bitcell_array_bitline_names: if bitline in pin_name: pin_list = self.bitcell_array_inst.get_pins(pin_name) for pin in pin_list: @@ -394,32 +409,35 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): width=pin.width(), height=self.height) - # Replica wordlines - for port in range(self.add_left_rbl + self.add_right_rbl): - inst = self.replica_col_inst[port] - for (pin_name, wl_name) in zip(self.cell.get_all_wl_names(), self.replica_wl_names[port]): - # +1 for dummy row - pin_bit = port + 1 - # +row_size if above the array - if port>=self.add_left_rbl: - pin_bit += self.row_size + # Dummy wordlines + for (name, inst) in [("bot", self.dummy_row_bot_inst), ("top", self.dummy_row_top_inst)]: + for (pin_name, wl_name) in zip(self.cell.get_all_wl_names(), self.dummy_wordline_names[name]): + # It's always a single row + pin = inst.get_pin(pin_name + "_0") + self.add_layout_pin(text=wl_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 (port, inst) in list(self.dummy_row_replica_inst.items()): + for (pin_name, wl_name) in zip(self.cell.get_all_wl_names(), self.replica_wordline_names[port]): + pin = inst.get_pin(pin_name + "_0") + self.add_layout_pin(text=wl_name, + layer=pin.layer, + offset=pin.ll().scale(0, 1), + width=self.width, + height=pin.height()) - pin_name += "_{}".format(pin_bit) - pin = inst.get_pin(pin_name) - if wl_name in self.rbl_wl_names.values(): - self.add_layout_pin(text=wl_name, - layer=pin.layer, - offset=pin.ll().scale(0, 1), - width=self.width, - height=pin.height()) - # Replica bitlines for port in range(self.add_left_rbl + self.add_right_rbl): inst = self.replica_col_inst[port] - for (pin_name, bl_name) in zip(self.cell.get_all_bitline_names(), self.replica_bl_names[port]): + for (pin_name, bl_name) in zip(self.cell.get_all_bitline_names(), self.replica_bitline_names[port]): pin = inst.get_pin(pin_name) - if bl_name in self.rbl_bl_names or bl_name in self.rbl_br_names: + if bl_name in self.replica_bl_names: name = bl_name else: name = "rbl_{0}_{1}".format(pin_name, port) @@ -441,22 +459,17 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): loc=pin.center(), directions=("V", "V"), start_layer=pin.layer) - + for inst in list(self.replica_col_inst.values()): self.copy_layout_pin(inst, pin_name) - self.copy_layout_pin(inst, pin_name) def get_rbl_wl_name(self, port): """ Return the WL for the given RBL port """ - return self.rbl_wl_names[port] + return self.replica_wordline_names[port] def get_rbl_bl_name(self, port): """ Return the BL for the given RBL port """ - return self.rbl_bl_names[port] - - def get_rbl_br_name(self, port): - """ Return the BR for the given RBL port """ - return self.rbl_br_names[port] + return self.replica_bl_names[port] def analytical_power(self, corner, load): """Power of Bitcell array and bitline in nW.""" diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index c75bc9ee..eb3116d3 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -188,8 +188,6 @@ class replica_column(design.design): 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_bitcell_pins(self, row, col): """ Creates a list of connections in the bitcell, diff --git a/compiler/modules/wordline_buffer_array.py b/compiler/modules/wordline_buffer_array.py index be0fe1f7..7a1bf8d1 100644 --- a/compiler/modules/wordline_buffer_array.py +++ b/compiler/modules/wordline_buffer_array.py @@ -58,8 +58,11 @@ class wordline_buffer_array(design.design): self.add_pin("gnd", "GROUND") def add_modules(self): + b = factory.create(module_type="bitcell") + self.wl_driver = factory.create(module_type="inv_dec", - size=self.cols) + size=self.cols, + height=b.height) self.add_mod(self.wl_driver) def route_vdd_gnd(self): diff --git a/compiler/tests/05_local_bitcell_array_test.py b/compiler/tests/05_local_bitcell_array_test.py index 99227694..664d9ef8 100755 --- a/compiler/tests/05_local_bitcell_array_test.py +++ b/compiler/tests/05_local_bitcell_array_test.py @@ -22,10 +22,14 @@ class local_bitcell_array_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - debug.info(2, "Testing 4x4 local bitcell array for 6t_cell") - a = factory.create(module_type="local_bitcell_array", cols=4, rows=4) + debug.info(2, "Testing 4x4 local bitcell array for 6t_cell without replica") + a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, ports=[0], add_replica=False) self.local_check(a) + debug.info(2, "Testing 4x4 local bitcell array for 6t_cell with replica column") + a = factory.create(module_type="local_bitcell_array", cols=4, left_rbl=1, rows=4, ports=[0]) + self.local_check(a) + globals.end_openram() From a55909930f1d57ff20d79d92a239a6db3cb8f2f2 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 12 Aug 2020 09:49:14 -0700 Subject: [PATCH 23/40] Replace replcia_bitcell_array with new one in bank --- compiler/modules/bank.py | 42 ++++++++--------------- compiler/modules/replica_bitcell_array.py | 14 ++++++-- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 4d0b09fb..cd06a969 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -83,7 +83,7 @@ class bank(design.design): for bit in range(self.word_size + self.num_spare_cols): self.add_pin("dout{0}_{1}".format(port, bit), "OUTPUT") for port in self.all_ports: - self.add_pin(self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]), "OUTPUT") + self.add_pin_list(self.bitcell_array.get_rbl_bitline_names(self.port_rbl_map[port]), "OUTPUT") for port in self.write_ports: for bit in range(self.word_size + self.num_spare_cols): self.add_pin("din{0}_{1}".format(port, bit), "INPUT") @@ -392,24 +392,14 @@ class bank(design.design): def create_bitcell_array(self): """ Creating Bitcell Array """ - import pdb; pdb.set_trace() self.bitcell_array_inst=self.add_inst(name="replica_bitcell_array", mod=self.bitcell_array) - temp = [] - for col in range(self.num_cols + self.num_spare_cols): - for bitline in self.bitline_names: - temp.append("{0}_{1}".format(bitline, col)) - for rbl in range(self.num_rbl): - rbl_bl_name=self.bitcell_array.get_rbl_bl_name(rbl) - temp.append(rbl_bl_name) - rbl_br_name=self.bitcell_array.get_rbl_br_name(rbl) - temp.append(rbl_br_name) - for row in range(self.num_rows): - for wordline in self.wl_names: - temp.append("{0}_{1}".format(wordline, row)) - for port in self.all_ports: - temp.append("wl_en{0}".format(port)) + bitline_names = self.bitcell_array.get_bitline_names() + temp.extend(bitline_names) + # Replace RBL wordline with wl_en# + wordline_names = [x.replace("rbl_wl_", "wl_en") for x in self.bitcell_array.get_wordline_names()] + temp.extend(wordline_names) temp.append("vdd") temp.append("gnd") self.connect_inst(temp) @@ -427,10 +417,8 @@ class bank(design.design): mod=self.port_data[port]) temp = [] - rbl_bl_name=self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]) - rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port]) - temp.append(rbl_bl_name) - temp.append(rbl_br_name) + rbl_bl_names=self.bitcell_array.get_rbl_bitline_names(self.port_rbl_map[port]) + temp.extend(rbl_bl_names) for col in range(self.num_cols + self.num_spare_cols): temp.append("{0}_{1}".format(self.bl_names[port], col)) temp.append("{0}_{1}".format(self.br_names[port], col)) @@ -718,10 +706,9 @@ class bank(design.design): self.connect_bitline(inst1, inst2, inst1_br_name.format(self.num_cols+i), "spare" + inst2_br_name.format(i)) # Connect the replica bitlines - rbl_bl_name=self.bitcell_array.get_rbl_bl_name(self.port_rbl_map[port]) - rbl_br_name=self.bitcell_array.get_rbl_br_name(self.port_rbl_map[port]) - self.connect_bitline(inst1, inst2, rbl_bl_name, "rbl_bl") - self.connect_bitline(inst1, inst2, rbl_br_name, "rbl_br") + rbl_bl_names=self.bitcell_array.get_rbl_bitline_names(self.port_rbl_map[port]) + for (array_name, data_name) in zip(rbl_bl_names, ["rbl_bl", "rbl_br"]): + self.connect_bitline(inst1, inst2, array_name, data_name) def route_port_data_out(self, port): """ Add pins for the port data out """ @@ -974,9 +961,10 @@ class bank(design.design): connection.append((self.prefix + "p_en_bar{}".format(port), self.port_data_inst[port].get_pin("p_en_bar"))) - rbl_wl_name = self.bitcell_array.get_rbl_wl_name(self.port_rbl_map[port]) - connection.append((self.prefix + "wl_en{}".format(port), - self.bitcell_array_inst.get_pin(rbl_wl_name))) + rbl_wl_names = self.bitcell_array.get_rbl_wordline_names(self.port_rbl_map[port]) + for rbl_wl_name in rbl_wl_names: + connection.append((self.prefix + "wl_en{}".format(port), + self.bitcell_array_inst.get_pin(rbl_wl_name))) if port in self.write_ports: connection.append((self.prefix + "w_en{}".format(port), diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 2511ea80..1119d546 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -463,13 +463,21 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): for inst in list(self.replica_col_inst.values()): self.copy_layout_pin(inst, pin_name) - def get_rbl_wl_name(self, port): + def get_rbl_wordline_names(self, port): """ Return the WL for the given RBL port """ return self.replica_wordline_names[port] - def get_rbl_bl_name(self, port): + def get_rbl_bitline_names(self, port): """ Return the BL for the given RBL port """ - return self.replica_bl_names[port] + return self.replica_bitline_names[port] + + def get_wordline_names(self): + """ Return the wordline names """ + return self.wordline_names + + def get_bitline_names(self): + """ Return the bitline names """ + return self.bitline_names def analytical_power(self, corner, load): """Power of Bitcell array and bitline in nW.""" From 0bec6f0439b02362a786e88969826b9b9f6b0240 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 12 Aug 2020 10:41:21 -0700 Subject: [PATCH 24/40] Fix SRAM to use simulation spice instead of LVS spice --- compiler/sram/sram.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/sram/sram.py b/compiler/sram/sram.py index ed09fbe0..8cf926c6 100644 --- a/compiler/sram/sram.py +++ b/compiler/sram/sram.py @@ -90,9 +90,9 @@ class sram(): # Save the LVS file start_time = datetime.datetime.now() - spname = OPTS.output_path + self.s.name + ".lvs" - debug.print_raw("LVS: Writing to {0}".format(spname)) - self.lvs_write(spname) + lvsname = OPTS.output_path + self.s.name + ".lvs.sp" + debug.print_raw("LVS: Writing to {0}".format(lvsname)) + self.lvs_write(lvsname) print_time("LVS writing", datetime.datetime.now(), start_time) # Save the extracted spice file From 55814a8f74b43f3a7fe806da0718fd961f0929bb Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 12 Aug 2020 11:15:32 -0700 Subject: [PATCH 25/40] Fix syntax errors in pgates for super edits --- compiler/pgates/pgate.py | 2 +- compiler/pgates/precharge.py | 2 +- compiler/pgates/ptx.py | 2 +- compiler/pgates/pwrite_driver.py | 2 +- compiler/pgates/wordline_driver.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index 57d93e6f..082ef7b8 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -26,7 +26,7 @@ class pgate(design.design): def __init__(self, name, height=None, add_wells=True): """ Creates a generic cell """ - super().__init__(, name) + super().__init__(name) if height: self.height = height diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index d948056d..aefdbb86 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -23,7 +23,7 @@ class precharge(design.design): def __init__(self, name, size=1, bitcell_bl="bl", bitcell_br="br"): debug.info(2, "creating precharge cell {0}".format(name)) - super().__init__(, name) + super().__init__(name) self.bitcell = factory.create(module_type="bitcell") self.beta = parameter["beta"] diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index 6de86346..1e4393e7 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -75,7 +75,7 @@ class ptx(design.design): # replace periods with underscore for newer spice compatibility name = name.replace('.', '_') debug.info(3, "creating ptx {0}".format(name)) - super().__init__(, name) + super().__init__(name) self.tx_type = tx_type self.mults = mults diff --git a/compiler/pgates/pwrite_driver.py b/compiler/pgates/pwrite_driver.py index 2d091fd0..6ae448f9 100644 --- a/compiler/pgates/pwrite_driver.py +++ b/compiler/pgates/pwrite_driver.py @@ -22,7 +22,7 @@ class pwrite_driver(design.design): def __init__(self, name, size=0): debug.error("pwrite_driver not implemented yet.", -1) debug.info(1, "creating pwrite_driver {}".format(name)) - super().__init__(, name) + super().__init__(name) self.size = size self.beta = parameter["beta"] self.pmos_width = self.beta*self.size*parameter["min_tx_size"] diff --git a/compiler/pgates/wordline_driver.py b/compiler/pgates/wordline_driver.py index b8fa4631..a8ca76f8 100644 --- a/compiler/pgates/wordline_driver.py +++ b/compiler/pgates/wordline_driver.py @@ -21,7 +21,7 @@ class wordline_driver(design.design): def __init__(self, name, size=1, height=None): debug.info(1, "Creating wordline_driver {}".format(name)) self.add_comment("size: {}".format(size)) - super().__init__(, name) + super().__init__(name) if height is None: b = factory.create(module_type="bitcell") From 15c8c200f3c2e3a0655d9ec11769818ba592c44d Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 12 Aug 2020 12:10:12 -0700 Subject: [PATCH 26/40] Undo super() in measurement abstract class --- compiler/characterizer/measurements.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/characterizer/measurements.py b/compiler/characterizer/measurements.py index 7d32c4f7..31da8ac5 100644 --- a/compiler/characterizer/measurements.py +++ b/compiler/characterizer/measurements.py @@ -58,7 +58,7 @@ class delay_measure(spice_measurement): def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, targ_dir_str,\ trig_vdd=0.5, targ_vdd=0.5, measure_scale=None, has_port=True): - super().__init__(measure_name, measure_scale, has_port) + spice_measurement.__init__(self, measure_name, measure_scale, has_port) self.set_meas_constants(trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd, targ_vdd) def get_measure_function(self): @@ -95,7 +95,7 @@ class delay_measure(spice_measurement): class slew_measure(delay_measure): def __init__(self, measure_name, signal_name, slew_dir_str, measure_scale=None, has_port=True): - super().__init__(measure_name, measure_scale, has_port) + spice_measurement.__init__(self, measure_name, measure_scale, has_port) self.set_meas_constants(signal_name, slew_dir_str) def set_meas_constants(self, signal_name, slew_dir_str): @@ -120,7 +120,7 @@ class power_measure(spice_measurement): """Generates a spice measurement for the average power between two time points.""" def __init__(self, measure_name, power_type="", measure_scale=None, has_port=True): - super().__init__(measure_name, measure_scale, has_port) + spice_measurement.__init__(self, measure_name, measure_scale, has_port) self.set_meas_constants(power_type) def get_measure_function(self): @@ -144,7 +144,7 @@ class voltage_when_measure(spice_measurement): """Generates a spice measurement to measure the voltage of a signal based on the voltage of another.""" def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, trig_vdd, measure_scale=None, has_port=True): - super().__init__(measure_name, measure_scale, has_port) + spice_measurement.__init__(self, measure_name, measure_scale, has_port) self.set_meas_constants(trig_name, targ_name, trig_dir_str, trig_vdd) def get_measure_function(self): @@ -177,7 +177,7 @@ class voltage_at_measure(spice_measurement): The time is considered variant with different periods.""" def __init__(self, measure_name, targ_name, measure_scale=None, has_port=True): - super().__init__(measure_name, measure_scale, has_port) + spice_measurement.__init__(self, measure_name, measure_scale, has_port) self.set_meas_constants(targ_name) def get_measure_function(self): From 5fc643855365bcb157e8bfd06087ba30055c6d33 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 12 Aug 2020 13:22:28 -0700 Subject: [PATCH 27/40] Fix pinv_dec super call --- compiler/pgates/pinv_dec.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/pgates/pinv_dec.py b/compiler/pgates/pinv_dec.py index 90c8e579..458ce187 100644 --- a/compiler/pgates/pinv_dec.py +++ b/compiler/pgates/pinv_dec.py @@ -38,7 +38,7 @@ class pinv_dec(pinv.pinv): else: self.supply_layer = "m2" - super().__init__(, name, size, beta, self.cell_height, add_wells) + super().__init__(name, size, beta, self.cell_height, add_wells) def determine_tx_mults(self): """ From 7ac4574e4f2bbc97310e2906e09009b84877ae5b Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 12 Aug 2020 13:54:55 -0700 Subject: [PATCH 28/40] Use micron units for all simulation in sky130 --- compiler/pgates/ptx.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index b6f839f3..1d9a9361 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -129,7 +129,7 @@ class ptx(design.design): # be decided in the layout later. area_sd = 2.5 * self.poly_width * self.tx_width perimeter_sd = 2 * self.poly_width + 2 * self.tx_width - if OPTS.tech_name == "sky130" and OPTS.lvs_exe and OPTS.lvs_exe[0] == "calibre": + if OPTS.tech_name == "sky130": # sky130 simulation cannot use the mult parameter in simulation (self.tx_width, self.mults) = pgate.best_bin(self.tx_type, self.tx_width) main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type], @@ -148,20 +148,19 @@ class ptx(design.design): area_str = "pd={0:.2f}u ps={0:.2f}u as={1:.2f}p ad={1:.2f}p".format(perimeter_sd, area_sd) self.spice_device = main_str + area_str - self.spice.append("\n* ptx " + self.spice_device) + self.spice.append("\n* spice ptx " + self.spice_device) if OPTS.tech_name == "sky130" and OPTS.lvs_exe and OPTS.lvs_exe[0] == "calibre": # sky130 requires mult parameter too self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format(spice[self.tx_type], - self.mults, - self.tx_width, - drc("minwidth_poly")) + self.mults, + self.tx_width, + drc("minwidth_poly")) else: self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type], - self.mults, - self.tx_width, - drc("minwidth_poly")) - + self.mults, + self.tx_width, + drc("minwidth_poly")) def setup_layout_constants(self): """ Pre-compute some handy layout parameters. From 50525e70f40bbbbff50bcd91bd2b49b552550f64 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 13 Aug 2020 14:29:10 -0700 Subject: [PATCH 29/40] Fix up to SRAM level with new replica bitcell array ports. --- compiler/modules/bank.py | 78 +++++++++++++++++------ compiler/modules/replica_bitcell_array.py | 48 ++++++++------ compiler/sram/sram_base.py | 1 + 3 files changed, 90 insertions(+), 37 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index cd06a969..4b9c3990 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -83,7 +83,7 @@ class bank(design.design): for bit in range(self.word_size + self.num_spare_cols): self.add_pin("dout{0}_{1}".format(port, bit), "OUTPUT") for port in self.all_ports: - self.add_pin_list(self.bitcell_array.get_rbl_bitline_names(self.port_rbl_map[port]), "OUTPUT") + self.add_pin_list(self.bitcell_array.get_rbl_bitline_names(port), "OUTPUT") for port in self.write_ports: for bit in range(self.word_size + self.num_spare_cols): self.add_pin("din{0}_{1}".format(port, bit), "INPUT") @@ -114,6 +114,8 @@ class bank(design.design): def route_layout(self): """ Create routing amoung the modules """ self.route_central_bus() + + self.route_unused_wordlines() for port in self.all_ports: self.route_bitlines(port) @@ -375,7 +377,6 @@ class bank(design.design): rows=self.num_rows) self.add_mod(self.port_address) - self.port_rbl_map = self.all_ports self.num_rbl = len(self.all_ports) self.bitcell_array = factory.create(module_type="replica_bitcell_array", @@ -395,10 +396,24 @@ class bank(design.design): self.bitcell_array_inst=self.add_inst(name="replica_bitcell_array", mod=self.bitcell_array) temp = [] + rbl_names = self.bitcell_array.get_rbl_bitline_names() + temp.extend(rbl_names) bitline_names = self.bitcell_array.get_bitline_names() temp.extend(bitline_names) # Replace RBL wordline with wl_en# - wordline_names = [x.replace("rbl_wl_", "wl_en") for x in self.bitcell_array.get_wordline_names()] + wordline_names = self.bitcell_array.get_wordline_names() + + rbl_wl_names = [] + for port in self.all_ports: + rbl_wl_names.append(self.bitcell_array.get_rbl_wordline_names(port)) + + # Rename the RBL WL to the enable name + for port in self.all_ports: + wordline_names = [x.replace(rbl_wl_names[port], "wl_en{0}".format(port)) for x in wordline_names] + # Connect the other RBL WL to gnd + wordline_names = ["gnd" if x.startswith("rbl_wl") else x for x in wordline_names] + # Connect the dummy WL to gnd + wordline_names = ["gnd" if x.startswith("dummy") else x for x in wordline_names] temp.extend(wordline_names) temp.append("vdd") temp.append("gnd") @@ -410,14 +425,13 @@ class bank(design.design): def create_port_data(self): """ Creating Port Data """ - self.port_data_inst = [None] * len(self.all_ports) 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 = [] - rbl_bl_names=self.bitcell_array.get_rbl_bitline_names(self.port_rbl_map[port]) + rbl_bl_names = self.bitcell_array.get_rbl_bitline_names(port) temp.extend(rbl_bl_names) for col in range(self.num_cols + self.num_spare_cols): temp.append("{0}_{1}".format(self.bl_names[port], col)) @@ -441,7 +455,6 @@ class bank(design.design): for bit in range(self.num_spare_cols): temp.append("bank_spare_wen{0}_{1}".format(port, bit)) temp.extend(["vdd", "gnd"]) - self.connect_inst(temp) def place_port_data(self, offsets): @@ -466,7 +479,7 @@ class bank(design.design): temp = [] for bit in range(self.row_addr_size): temp.append("addr{0}_{1}".format(port, bit + self.col_addr_size)) - temp.append("wl_en{0}".format(port)) + temp.append("wl_en{}".format(port)) for row in range(self.num_rows): temp.append("{0}_{1}".format(self.wl_names[port], row)) temp.extend(["vdd", "gnd"]) @@ -654,7 +667,7 @@ class bank(design.design): # Port 0 # The bank is at (0,0), so this is to the left of the y-axis. # 2 pitches on the right for vias/jogs to access the inputs - control_bus_offset = vector(-self.m3_pitch * self.num_control_lines[0] - self.m3_pitch, self.min_y_offset) + control_bus_offset = vector(-self.m3_pitch * self.num_control_lines[0] - 2 * self.m3_pitch, self.min_y_offset) # The control bus is routed up to two pitches below the bitcell array control_bus_length = self.main_bitcell_array_bottom - self.min_y_offset - 2 * self.m1_pitch self.bus_pins[0] = self.create_bus(layer="m2", @@ -669,7 +682,7 @@ class bank(design.design): if len(self.all_ports)==2: # The other control bus is routed up to two pitches above the bitcell array control_bus_length = self.max_y_offset - self.main_bitcell_array_top - 2 * self.m1_pitch - control_bus_offset = vector(self.bitcell_array_right + self.m3_pitch, + control_bus_offset = vector(self.bitcell_array_right + 2 * self.m3_pitch, self.max_y_offset - control_bus_length) # The bus for the right port is reversed so that the rbl_wl is closest to the array self.bus_pins[1] = self.create_bus(layer="m2", @@ -702,11 +715,11 @@ class bank(design.design): # connect spare bitlines for i in range(self.num_spare_cols): - self.connect_bitline(inst1, inst2, inst1_bl_name.format(self.num_cols+i), "spare" + inst2_bl_name.format(i)) - self.connect_bitline(inst1, inst2, inst1_br_name.format(self.num_cols+i), "spare" + inst2_br_name.format(i)) + self.connect_bitline(inst1, inst2, inst1_bl_name.format(self.num_cols + i), "spare" + inst2_bl_name.format(i)) + self.connect_bitline(inst1, inst2, inst1_br_name.format(self.num_cols + i), "spare" + inst2_br_name.format(i)) # Connect the replica bitlines - rbl_bl_names=self.bitcell_array.get_rbl_bitline_names(self.port_rbl_map[port]) + rbl_bl_names = self.bitcell_array.get_rbl_bitline_names(port) for (array_name, data_name) in zip(rbl_bl_names, ["rbl_bl", "rbl_br"]): self.connect_bitline(inst1, inst2, array_name, data_name) @@ -949,7 +962,35 @@ class bank(design.design): self.add_label(text=data_name, layer="m1", offset=data_pin.center()) - + + def route_unused_wordlines(self): + """ Connect the unused RBL and dummy wordlines to gnd """ + gnd_wl_names = [] + + # Connect unused RBL WL to gnd + array_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("rbl")]) + dummy_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("dummy")]) + rbl_wl_names = set([self.bitcell_array.get_rbl_wordline_names(x) for x in self.all_ports]) + + gnd_wl_names = list((array_rbl_names - rbl_wl_names) | dummy_rbl_names) + + for wl_name in gnd_wl_names: + pin = self.bitcell_array_inst.get_pin(wl_name) + pin_layer = pin.layer + layer_pitch = getattr(self, "{}_pitch".format(pin_layer)) + left_pin_loc = pin.lc() + right_pin_loc = pin.rc() + + # Place the pins a track outside of the array + left_loc = left_pin_loc - vector(layer_pitch, 0) + right_loc = right_pin_loc + vector(layer_pitch, 0) + self.add_power_pin("gnd", left_loc) + self.add_power_pin("gnd", right_loc) + + # Add a path to connect to the array + self.add_path(pin_layer, [left_loc, left_pin_loc]) + self.add_path(pin_layer, [right_loc, right_pin_loc]) + def route_control_lines(self, port): """ Route the control lines of the entire bank """ @@ -961,11 +1002,10 @@ class bank(design.design): connection.append((self.prefix + "p_en_bar{}".format(port), self.port_data_inst[port].get_pin("p_en_bar"))) - rbl_wl_names = self.bitcell_array.get_rbl_wordline_names(self.port_rbl_map[port]) - for rbl_wl_name in rbl_wl_names: - connection.append((self.prefix + "wl_en{}".format(port), - self.bitcell_array_inst.get_pin(rbl_wl_name))) - + rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port) + connection.append((self.prefix + "wl_en{}".format(port), + self.bitcell_array_inst.get_pin(rbl_wl_name))) + if port in self.write_ports: connection.append((self.prefix + "w_en{}".format(port), self.port_data_inst[port].get_pin("w_en"))) @@ -1000,7 +1040,7 @@ class bank(design.design): self.add_wire(self.m1_stack, [pin_pos, mid_pos, control_pos]) self.add_via_center(layers=self.m1_stack, offset=control_pos) - + def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True): """Get the all the stage efforts for each stage in the path within the bank clk_buf to a wordline""" # Decoder is assumed to have settled before the negative edge of the clock. diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 1119d546..48da3630 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -174,7 +174,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def add_bitline_pins(self): - # All bitline names for all ports + # Regular bitline names for all ports self.bitline_names = [] # Bitline names for each port self.bitline_names_by_port = [[] for x in self.all_ports] @@ -183,15 +183,15 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Replica wordlines by port (bl only) self.replica_bl_names = [[] for x in self.all_ports] # Dummy wordlines by port - self.dummy_bitline_names = [] + self.dummy_bitline_names = [] # Regular array bitline names self.bitcell_array_bitline_names = self.bitcell_array.get_all_bitline_names() # These are the non-indexed names dummy_bitline_names = ["dummy_" + x for x in self.cell.get_all_bitline_names()] - self.dummy_bitline_names.append([x+"_left" for x in dummy_bitline_names]) - self.dummy_bitline_names.append([x+"_right" for x in dummy_bitline_names]) + self.dummy_bitline_names.append([x + "_left" for x in dummy_bitline_names]) + self.dummy_bitline_names.append([x + "_right" for x in dummy_bitline_names]) # Array of all port bitline names for port in range(self.add_left_rbl + self.add_right_rbl): @@ -204,14 +204,10 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.replica_bitline_names[port] = bitline_names # Dummy bitlines are not connected to anything - # br pins are not connected to anything - for port in range(self.add_left_rbl): - self.bitline_names.extend(self.replica_bitline_names[port]) self.bitline_names.extend(self.bitcell_array_bitline_names) - # br pins are not connected to anything - for port in range(self.left_rbl, self.left_rbl + self.right_rbl): - self.bitline_names.extend(self.replica_bitline_names[port]) + for port in self.all_ports: + self.add_pin_list(self.replica_bitline_names[port], "INOUT") self.add_pin_list(self.bitline_names, "INOUT") def add_wordline_pins(self): @@ -240,7 +236,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Left port WLs for port in range(self.left_rbl): # Make names for all RBLs - wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x), port) for x in range(len(self.cell.get_all_wl_names()))] + wl_names=["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()] # Keep track of the pin that is the RBL self.replica_wordline_names[port] = wl_names self.wordline_names.extend(wl_names) @@ -251,11 +247,10 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Right port WLs for port in range(self.left_rbl, self.left_rbl + self.right_rbl): # Make names for all RBLs - wl_names=["rbl_{0}_{1}".format(self.cell.get_wl_name(x), port) for x in range(len(self.cell.get_all_wl_names()))] + wl_names=["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()] # Keep track of the pin that is the RBL self.replica_wordline_names[port] = wl_names self.wordline_names.extend(wl_names) - self.dummy_wordline_names["top"] = ["{0}_top".format(x) for x in dummy_cell_wl_names] self.wordline_names.extend(self.dummy_wordline_names["top"]) @@ -463,13 +458,30 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): for inst in list(self.replica_col_inst.values()): self.copy_layout_pin(inst, pin_name) - def get_rbl_wordline_names(self, port): - """ Return the WL for the given RBL port """ - return self.replica_wordline_names[port] + def get_rbl_wordline_names(self, port=None): + """ + Return the ACTIVE WL for the given RBL port. + Inactive will be set to gnd. + """ + if port == None: + temp = [] + for port in self.all_ports: + temp.extend(self.replica_wordline_names[port]) + return temp + else: + wl_names = self.replica_wordline_names[port] + return wl_names[port] - def get_rbl_bitline_names(self, port): + def get_rbl_bitline_names(self, port=None): """ Return the BL for the given RBL port """ - return self.replica_bitline_names[port] + if port == None: + temp = [] + for port in self.all_ports: + temp.extend(self.replica_bitline_names[port]) + return temp + else: + bl_names = self.replica_bitline_names[port] + return bl_names[2 * port:2 * port + 2] def get_wordline_names(self): """ Return the wordline names """ diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 12af7cf6..23c05dbf 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -346,6 +346,7 @@ class sram_base(design, verilog, lef): temp.append("dout{0}[{1}]".format(port, bit)) for port in self.all_ports: temp.append("rbl_bl{0}".format(port)) + temp.append("rbl_br{0}".format(port)) for port in self.write_ports: for bit in range(self.word_size + self.num_spare_cols): temp.append("bank_din{0}[{1}]".format(port, bit)) From 797c41c75011d7506c19cd9bbbc06e442822bff1 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 13 Aug 2020 14:36:39 -0700 Subject: [PATCH 30/40] Skip local bitcell array test --- compiler/tests/05_local_bitcell_array_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/tests/05_local_bitcell_array_test.py b/compiler/tests/05_local_bitcell_array_test.py index 664d9ef8..29b3b1de 100755 --- a/compiler/tests/05_local_bitcell_array_test.py +++ b/compiler/tests/05_local_bitcell_array_test.py @@ -15,7 +15,7 @@ from sram_factory import factory import debug -#@unittest.skip("SKIPPING 05_local_bitcell_array_test") +@unittest.skip("SKIPPING 05_local_bitcell_array_test") class local_bitcell_array_test(openram_test): def runTest(self): From 2ac04efe2e466e0653dfadbf4520fc5a6d2c4239 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 13 Aug 2020 16:26:19 -0700 Subject: [PATCH 31/40] Must connect for replica cells other than top/bottom --- compiler/modules/replica_column.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index eb3116d3..c75bc9ee 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -188,6 +188,8 @@ class replica_column(design.design): 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_bitcell_pins(self, row, col): """ Creates a list of connections in the bitcell, From dfb593e9b4d1a19a1fefea8c7fefdfd22dc22f4d Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 14 Aug 2020 10:38:22 -0700 Subject: [PATCH 32/40] Add draft lyt file -- connectivity not working --- technology/scn4m_subm/tf/mosis.lyt | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 technology/scn4m_subm/tf/mosis.lyt diff --git a/technology/scn4m_subm/tf/mosis.lyt b/technology/scn4m_subm/tf/mosis.lyt new file mode 100644 index 00000000..8673627e --- /dev/null +++ b/technology/scn4m_subm/tf/mosis.lyt @@ -0,0 +1,27 @@ + + + SCMOS + + 0.001 + + mosis.lyp + true + + Active,ActX,Metal1 + Poly1,P1Con,Metal1 + Metal1,Via,Metal2 + Metal2,Via2,Metal3 + Metal3,Via3,Metal4 + Active='43/0' + Poly1='46/0' + P1Con='47/0' + ActX='48/0' + Metal1='49/0' + Via='50/0' + Metal2='51/0' + Via2='61/0' + Metal3.='62/0' + Via3='30/0' + Metal4='31/0' + + From 604e433e22a688413b0df46342569cad9b4da556 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 14 Aug 2020 10:40:31 -0700 Subject: [PATCH 33/40] Add readonly true for Magic scripts --- compiler/verify/magic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index ef98a09b..75bd53f0 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -77,6 +77,7 @@ def write_magic_script(cell_name, extract=False, final_verification=False): f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1])) f.write("gds polygon subcell true\n") f.write("gds warning default\n") + f.write("gds readonly true\n") f.write("gds read {}.gds\n".format(cell_name)) f.write("load {}\n".format(cell_name)) # Flatten the cell to get rid of DRCs spanning multiple layers From 170e3feb7dddb0512b02a1aef6caba94987944ec Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 14 Aug 2020 14:14:49 -0700 Subject: [PATCH 34/40] Fix order of replica wordlines and bitlines --- compiler/modules/replica_bitcell_array.py | 30 +++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 48da3630..1abd5553 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -101,15 +101,15 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.replica_columns = {} for bit in range(self.add_left_rbl + self.add_right_rbl): # Creating left_rbl - if bit Date: Fri, 14 Aug 2020 14:23:40 -0700 Subject: [PATCH 35/40] Extra space for unused wl contacts --- compiler/modules/bank.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 4b9c3990..2ed003ab 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -977,7 +977,7 @@ class bank(design.design): for wl_name in gnd_wl_names: pin = self.bitcell_array_inst.get_pin(wl_name) pin_layer = pin.layer - layer_pitch = getattr(self, "{}_pitch".format(pin_layer)) + layer_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer)) left_pin_loc = pin.lc() right_pin_loc = pin.rc() From 2c43d315db02b63306d27dbcf98430a9caf8c44a Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 17 Aug 2020 12:19:23 -0700 Subject: [PATCH 36/40] Revert gds readonly true --- compiler/verify/magic.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 75bd53f0..cb0efeff 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -77,7 +77,8 @@ def write_magic_script(cell_name, extract=False, final_verification=False): f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1])) f.write("gds polygon subcell true\n") f.write("gds warning default\n") - f.write("gds readonly true\n") + # This causes substrate contacts to not be extracted + f.write("# gds readonly true\n") f.write("gds read {}.gds\n".format(cell_name)) f.write("load {}\n".format(cell_name)) # Flatten the cell to get rid of DRCs spanning multiple layers From bddb251a845e9b810f40f1b8687fbd797e68dbe4 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 17 Aug 2020 12:32:44 -0700 Subject: [PATCH 37/40] More room for power contacts --- compiler/modules/bank.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 2ed003ab..59b8faa7 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -257,7 +257,7 @@ class bank(design.design): self.port_data_offsets[port] = vector(self.main_bitcell_array_left, self.bitcell_array_top) # LOWER RIGHT QUADRANT - # To the left of the bitcell array + # To the right of the bitcell array x_offset = self.bitcell_array_right + self.port_address.width + self.m2_gap self.port_address_offsets[port] = vector(x_offset, self.main_bitcell_array_bottom) @@ -682,7 +682,7 @@ class bank(design.design): if len(self.all_ports)==2: # The other control bus is routed up to two pitches above the bitcell array control_bus_length = self.max_y_offset - self.main_bitcell_array_top - 2 * self.m1_pitch - control_bus_offset = vector(self.bitcell_array_right + 2 * self.m3_pitch, + control_bus_offset = vector(self.bitcell_array_right + 2.5 * self.m3_pitch, self.max_y_offset - control_bus_length) # The bus for the right port is reversed so that the rbl_wl is closest to the array self.bus_pins[1] = self.create_bus(layer="m2", From 94bfad4113ac16807efa68a1b9edaeabc5fad286 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 17 Aug 2020 13:24:34 -0700 Subject: [PATCH 38/40] Horizontal gnd vias for unused array inputs --- compiler/modules/bank.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 59b8faa7..ea39fac4 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -984,8 +984,8 @@ class bank(design.design): # Place the pins a track outside of the array left_loc = left_pin_loc - vector(layer_pitch, 0) right_loc = right_pin_loc + vector(layer_pitch, 0) - self.add_power_pin("gnd", left_loc) - self.add_power_pin("gnd", right_loc) + self.add_power_pin("gnd", left_loc, directions=("H", "H")) + self.add_power_pin("gnd", right_loc, directions=("H", "H")) # Add a path to connect to the array self.add_path(pin_layer, [left_loc, left_pin_loc]) From 3a692e28469ef130f8c58440422ac8faf4275d74 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 17 Aug 2020 14:35:39 -0700 Subject: [PATCH 39/40] Comment updates --- compiler/base/design.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/base/design.py b/compiler/base/design.py index 2a79120d..ee985fec 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -230,13 +230,14 @@ class design(hierarchy_design): self.write_ports = [] # These are the write-only port indices. self.writeonly_ports = [] - # These are teh read/write and read-only port indice + # These are the read/write and read-only port indices self.read_ports = [] # These are the read-only port indices. self.readonly_ports = [] # These are all the ports self.all_ports = list(range(total_ports)) - + + # The order is always fixed as RW, W, R port_number = 0 for port in range(OPTS.num_rw_ports): self.readwrite_ports.append(port_number) From b1e55f9072b26679fe6330260a83bba315389eeb Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 17 Aug 2020 15:14:42 -0700 Subject: [PATCH 40/40] Add local bitcell array --- compiler/modules/local_bitcell_array.py | 94 +++++++++++++++---- compiler/tests/05_local_bitcell_array_test.py | 2 +- 2 files changed, 76 insertions(+), 20 deletions(-) diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index da203de7..cf5fbdee 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -9,6 +9,7 @@ import bitcell_base_array from globals import OPTS from sram_factory import factory from vector import vector +from tech import drc import debug class local_bitcell_array(bitcell_base_array.bitcell_base_array): @@ -24,10 +25,9 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): self.rows = rows self.cols = cols - self.left_rbl = left_rbl - self.right_rbl = right_rbl + self.add_replica=add_replica self.all_ports = ports - + self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -48,6 +48,8 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): self.add_layout_pins() + self.route() + self.add_boundary() self.DRC_LVS() @@ -60,9 +62,10 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): self.bitcell_array = factory.create(module_type="replica_bitcell_array", cols=self.cols, rows=self.rows, - left_rbl=self.left_rbl, - right_rbl=self.right_rbl, - bitcell_ports=self.all_ports) + left_rbl=1, + right_rbl=1 if len(self.all_ports)>1 else 0, + bitcell_ports=self.all_ports, + add_replica=self.add_replica) self.add_mod(self.bitcell_array) self.wl_array = factory.create(module_type="wordline_buffer_array", @@ -74,39 +77,92 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): self.bitline_names = self.bitcell_array.get_all_bitline_names() self.add_pin_list(self.bitline_names, "INOUT") - self.wordline_names = self.bitcell_array.get_all_wordline_names() + self.driver_wordline_inputs = [x for x in self.bitcell_array.get_all_wordline_names() if not x.startswith("dummy")] + self.driver_wordline_outputs = [x + "i" for x in self.driver_wordline_inputs] + self.array_wordline_inputs = [x + "i" if not x.startswith("dummy") else "gnd" for x in self.bitcell_array.get_all_wordline_names()] self.add_pin_list(self.wordline_names, "INPUT") + self.replica_names = self.bitcell_array.get_rbl_wordline_names() + self.add_pin_list(self.replica_names, "INPUT") + self.bitline_names = self.bitcell_array.get_inouts() self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") def create_instances(self): """ Create the module instances used in this design """ - - internal_wl_names = [x + "i" for x in self.wordline_names] + self.wl_inst = self.add_inst(name="wl_driver", mod=self.wl_array) - self.connect_inst(self.wordline_names + internal_wl_names + ["vdd", "gnd"]) + self.connect_inst(self.driver_wordline_inputs + self.driver_wordline_outputs + ["vdd", "gnd"]) - self.array_inst = self.add_inst(name="array", - mod=self.bitcell_array, - offset=self.wl_inst.lr()) - self.connect_inst(self.bitline_names + internal_wl_names + ["vdd", "gnd"]) + self.bitcell_array_inst = self.add_inst(name="array", + mod=self.bitcell_array, + offset=self.wl_inst.lr()) + self.connect_inst(self.bitline_names + self.array_wordline_inputs + ["vdd", "gnd"]) def place(self): """ Place the bitcelll array to the right of the wl driver. """ - self.wl_inst.place(vector(0, 0)) - self.array_inst.place(self.wl_inst.lr()) + self.wl_inst.place(vector(0, self.cell.height)) + # FIXME: Replace this with a tech specific paramter + driver_to_array_spacing = 3 * self.m3_pitch + self.bitcell_array_inst.place(vector(self.wl_inst.rx() + driver_to_array_spacing, + 0)) self.height = self.bitcell_array.height - self.width = self.array_inst.rx() + self.width = self.bitcell_array_inst.rx() + def route_unused_wordlines(self): + """ Connect the unused RBL and dummy wordlines to gnd """ + gnd_wl_names = [] + + # Connect unused RBL WL to gnd + array_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("rbl")]) + dummy_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("dummy")]) + rbl_wl_names = set([self.bitcell_array.get_rbl_wordline_names(x) for x in self.all_ports]) + + gnd_wl_names = list((array_rbl_names - rbl_wl_names) | dummy_rbl_names) + + for wl_name in gnd_wl_names: + pin = self.bitcell_array_inst.get_pin(wl_name) + pin_layer = pin.layer + layer_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer)) + left_pin_loc = pin.lc() + right_pin_loc = pin.rc() + + # Place the pins a track outside of the array + left_loc = left_pin_loc - vector(layer_pitch, 0) + right_loc = right_pin_loc + vector(layer_pitch, 0) + self.add_power_pin("gnd", left_loc, directions=("H", "H")) + self.add_power_pin("gnd", right_loc, directions=("H", "H")) + + # Add a path to connect to the array + self.add_path(pin_layer, [left_loc, left_pin_loc]) + self.add_path(pin_layer, [right_loc, right_pin_loc]) + def add_layout_pins(self): for (x, y) in zip(self.bitline_names, self.bitcell_array.get_inouts()): - self.copy_layout_pin(self.array_inst, y, x) + self.copy_layout_pin(self.bitcell_array_inst, y, x) - for (x, y) in zip(self.wordline_names, self.wl_array.get_inputs()): + for (x, y) in zip(self.driver_wordline_inputs, self.wl_array.get_inputs()): self.copy_layout_pin(self.wl_inst, y, x) + supply_insts = [self.wl_inst, self.bitcell_array_inst] + for pin_name in ["vdd", "gnd"]: + for inst in supply_insts: + pin_list = inst.get_pins(pin_name) + for pin in pin_list: + self.add_power_pin(name=pin_name, + loc=pin.center(), + start_layer=pin.layer) + + def route(self): + array_names = [x for x in self.bitcell_array.get_all_wordline_names() if not x.startswith("dummy")] + for (driver_name, array_name) in zip(self.wl_array.get_outputs(), array_names): + out_pin = self.wl_inst.get_pin(driver_name) + in_pin = self.bitcell_array_inst.get_pin(array_name) + mid_loc = self.wl_inst.rx() + 1.5 * self.m3_pitch + self.add_path(out_pin.layer, [out_pin.rc(), vector(mid_loc, out_pin.cy()), in_pin.lc()]) + + self.route_unused_wordlines() diff --git a/compiler/tests/05_local_bitcell_array_test.py b/compiler/tests/05_local_bitcell_array_test.py index 29b3b1de..664d9ef8 100755 --- a/compiler/tests/05_local_bitcell_array_test.py +++ b/compiler/tests/05_local_bitcell_array_test.py @@ -15,7 +15,7 @@ from sram_factory import factory import debug -@unittest.skip("SKIPPING 05_local_bitcell_array_test") +#@unittest.skip("SKIPPING 05_local_bitcell_array_test") class local_bitcell_array_test(openram_test): def runTest(self):