From a13d5359455bff97198966d19ab233a0b6683594 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 22 Jun 2020 11:33:02 -0700 Subject: [PATCH 01/20] PEP8 cleanup --- compiler/base/hierarchy_design.py | 7 +++---- compiler/base/hierarchy_spice.py | 13 ++++++++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index 87331315..20c40f21 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -27,8 +27,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): # If we have a separate lvs directory, then all the lvs files # should be in there (all or nothing!) lvs_dir = OPTS.openram_tech + "lvs_lib/" - # Calibre will do the scaling in s8 - if os.path.exists(lvs_dir): # and OPTS.lvs_exe[0]!="calibre": + if os.path.exists(lvs_dir): self.lvs_file = lvs_dir + name + ".sp" else: self.lvs_file = self.sp_file @@ -45,7 +44,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): if i.name == inst.name: break else: - debug.error("Couldn't find instance {0}".format(inst_name), -1) + debug.error("Couldn't find instance {0}".format(inst.name), -1) inst_map = inst.mod.pin_map return inst_map @@ -181,7 +180,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): """Given a list of nets, will compare the internal alias of a mod to determine if the nets have a connection to this mod's net (but not inst). """ - if exclusion_set == None: + if not exclusion_set: exclusion_set = set() try: self.name_dict diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 00d7ad44..0e41c4b0 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -10,9 +10,9 @@ import re import os import math import tech -from delay_data import * -from wire_spice_model import * -from power_data import * +from delay_data import delay_data +from wire_spice_model import wire_spice_model +from power_data import power_data import logical_effort @@ -263,7 +263,10 @@ class spice(): Recursive spice subcircuit write; Writes the spice subcircuit from the library or the dynamically generated one """ + if not self.spice: + # If spice isn't defined, we dynamically generate one. + # recursively write the modules for i in self.mods: if self.contains(i, usedMODS): @@ -316,7 +319,7 @@ class spice(): sp.write(".ENDS {0}\n".format(self.name)) else: - # write the subcircuit itself + # If spice is a hard module, output the spice file contents. # Including the file path makes the unit test fail for other users. # if os.path.isfile(self.sp_file): # sp.write("\n* {0}\n".format(self.sp_file)) @@ -356,7 +359,7 @@ class spice(): stage_effort = self.get_stage_effort(relative_cap) # If it fails, then keep running with a valid object. - if stage_effort == None: + if not stage_effort: return delay_data(0.0, 0.0) abs_delay = stage_effort.get_absolute_delay() From 54120f8405d02713fb73ab698cd22e278c266866 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 22 Jun 2020 12:35:37 -0700 Subject: [PATCH 02/20] Add option for removing subckt/instances of cells for row/col caps --- compiler/base/hierarchy_spice.py | 9 ++++++++- compiler/bitcells/col_cap_bitcell_1rw_1r.py | 1 + compiler/bitcells/row_cap_bitcell_1rw_1r.py | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 0e41c4b0..5ba60435 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -40,6 +40,8 @@ class spice(): # THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the # Spice format) self.conns = [] + # If this is set, it will out output subckt or isntances of this (for row/col caps etc.) + self.no_instances = False # Keep track of any comments to add the the spice try: self.commments @@ -264,7 +266,9 @@ class spice(): Writes the spice subcircuit from the library or the dynamically generated one """ - if not self.spice: + if self.no_instances: + return + elif not self.spice: # If spice isn't defined, we dynamically generate one. # recursively write the modules @@ -303,6 +307,9 @@ class spice(): # these are wires and paths if self.conns[i] == []: continue + # Instance with no devices in it needs no subckt/instance + if self.insts[i].mod.no_instances: + continue if lvs_netlist and hasattr(self.insts[i].mod, "lvs_device"): sp.write(self.insts[i].mod.lvs_device.format(self.insts[i].name, " ".join(self.conns[i]))) diff --git a/compiler/bitcells/col_cap_bitcell_1rw_1r.py b/compiler/bitcells/col_cap_bitcell_1rw_1r.py index 315ad23f..01818a12 100644 --- a/compiler/bitcells/col_cap_bitcell_1rw_1r.py +++ b/compiler/bitcells/col_cap_bitcell_1rw_1r.py @@ -41,3 +41,4 @@ class col_cap_bitcell_1rw_1r(bitcell_base.bitcell_base): self.height = col_cap_bitcell_1rw_1r.height self.pin_map = col_cap_bitcell_1rw_1r.pin_map self.add_pin_types(self.type_list) + self.no_instances = True diff --git a/compiler/bitcells/row_cap_bitcell_1rw_1r.py b/compiler/bitcells/row_cap_bitcell_1rw_1r.py index b50629f0..f7a3a687 100644 --- a/compiler/bitcells/row_cap_bitcell_1rw_1r.py +++ b/compiler/bitcells/row_cap_bitcell_1rw_1r.py @@ -41,3 +41,4 @@ class row_cap_bitcell_1rw_1r(bitcell_base.bitcell_base): self.height = row_cap_bitcell_1rw_1r.height self.pin_map = row_cap_bitcell_1rw_1r.pin_map self.add_pin_types(self.type_list) + self.no_instances = True From 0926eab9f54f141785f4898864985ed36b16f8a1 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 22 Jun 2020 12:55:18 -0700 Subject: [PATCH 03/20] PEP8 formatting --- compiler/modules/col_cap_array.py | 24 +++++++-------------- compiler/modules/row_cap_array.py | 35 +++++++++++-------------------- 2 files changed, 19 insertions(+), 40 deletions(-) diff --git a/compiler/modules/col_cap_array.py b/compiler/modules/col_cap_array.py index d74ab80a..ee9302d8 100644 --- a/compiler/modules/col_cap_array.py +++ b/compiler/modules/col_cap_array.py @@ -17,6 +17,7 @@ class col_cap_array(bitcell_base_array): super().__init__(cols, rows, name, column_offset) self.mirror = mirror + self.no_instances = True self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -47,8 +48,8 @@ class col_cap_array(bitcell_base_array): for col in range(self.column_size): for row in range(self.row_size): name = "bit_r{0}_c{1}".format(row, col) - self.cell_inst[row,col]=self.add_inst(name=name, - mod=self.dummy_cell) + self.cell_inst[row, col]=self.add_inst(name=name, + mod=self.dummy_cell) self.connect_inst(self.get_bitcell_pins(col, row)) def get_bitcell_pins(self, col, row): @@ -73,31 +74,20 @@ class col_cap_array(bitcell_base_array): 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), + bl_pin = self.cell_inst[0, col].get_pin(cell_column) + self.add_layout_pin(text=cell_column + "_{0}".format(col), layer=bl_pin.layer, - offset=bl_pin.ll().scale(1,0), + offset=bl_pin.ll().scale(1, 0), width=bl_pin.width(), height=self.height) # Add vdd/gnd via stacks for row in range(self.row_size): for col in range(self.column_size): - inst = self.cell_inst[row,col] + inst = self.cell_inst[row, col] for pin_name in ["vdd", "gnd"]: for pin in inst.get_pins(pin_name): self.add_power_pin(name=pin.name, loc=pin.center(), start_layer=pin.layer) - - # def input_load(self): - # wl_wire = self.gen_wl_wire() - # return wl_wire.return_input_cap() - # - # def get_wordline_cin(self): - # """Get the relative input capacitance from the wordline connections in all the bitcell""" - # #A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns - # bitcell_wl_cin = self.cell.get_wl_cin() - # total_cin = bitcell_wl_cin * self.column_size - # return total_cin diff --git a/compiler/modules/row_cap_array.py b/compiler/modules/row_cap_array.py index 2c7d4677..f108d86e 100644 --- a/compiler/modules/row_cap_array.py +++ b/compiler/modules/row_cap_array.py @@ -8,6 +8,7 @@ from sram_factory import factory from globals import OPTS from tech import cell_properties + class row_cap_array(bitcell_base_array): """ Generate a dummy row/column for the replica array. @@ -15,7 +16,7 @@ class row_cap_array(bitcell_base_array): def __init__(self, cols, rows, column_offset=0, mirror=0, name=""): super().__init__(cols, rows, name, column_offset) self.mirror = mirror - + self.no_instances = True self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -46,8 +47,8 @@ class row_cap_array(bitcell_base_array): for col in range(self.column_size): for row in range(1, self.row_size - 1): name = "bit_r{0}_c{1}".format(row, col) - self.cell_inst[row,col]=self.add_inst(name=name, - mod=self.dummy_cell) + self.cell_inst[row, col]=self.add_inst(name=name, + mod=self.dummy_cell) self.connect_inst(self.get_bitcell_pins(col, row)) def get_bitcell_pins(self, col, row): @@ -65,8 +66,8 @@ class row_cap_array(bitcell_base_array): def place_array(self, name_template, row_offset=0): # We increase it by a well enclosure so the precharges don't overlap our wells - self.height = self.row_size*self.cell.height - self.width = self.column_size*self.cell.width + self.height = self.row_size * self.cell.height + self.width = self.column_size * self.cell.width xoffset = 0.0 for col in range(self.column_size): @@ -74,7 +75,6 @@ class row_cap_array(bitcell_base_array): tempx, dir_y = self._adjust_x_offset(xoffset, col, self.column_offset) for row in range(1, self.row_size - 1): - name = name_template.format(row, col) tempy, dir_x = self._adjust_y_offset(yoffset, row, row_offset) if dir_x and dir_y: @@ -86,8 +86,8 @@ class row_cap_array(bitcell_base_array): else: dir_key = "" - self.cell_inst[row,col].place(offset=[tempx, tempy], - mirror=dir_key) + self.cell_inst[row, col].place(offset=[tempx, tempy], + mirror=dir_key) yoffset += self.cell.height xoffset += self.cell.width @@ -98,31 +98,20 @@ class row_cap_array(bitcell_base_array): for row in range(1, self.row_size - 1): 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), + wl_pin = self.cell_inst[row, 0].get_pin(cell_row) + self.add_layout_pin(text=cell_row + "_{0}".format(row), layer=wl_pin.layer, - offset=wl_pin.ll().scale(0,1), + offset=wl_pin.ll().scale(0, 1), width=self.width, height=wl_pin.height()) # Add vdd/gnd via stacks for row in range(1, self.row_size - 1): for col in range(self.column_size): - inst = self.cell_inst[row,col] + inst = self.cell_inst[row, col] for pin_name in ["vdd", "gnd"]: for pin in inst.get_pins(pin_name): self.add_power_pin(name=pin.name, loc=pin.center(), start_layer=pin.layer) - - # def input_load(self): - # wl_wire = self.gen_wl_wire() - # return wl_wire.return_input_cap() - # - # def get_wordline_cin(self): - # """Get the relative input capacitance from the wordline connections in all the bitcell""" - # #A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns - # bitcell_wl_cin = self.cell.get_wl_cin() - # total_cin = bitcell_wl_cin * self.column_size - # return total_cin From 40edbfa51f62789ee822085d23839114f69adf48 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 22 Jun 2020 15:41:59 -0700 Subject: [PATCH 04/20] Error out on single port in sky130 --- compiler/bitcells/bitcell.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/bitcells/bitcell.py b/compiler/bitcells/bitcell.py index 4ed2d053..e91d8c2f 100644 --- a/compiler/bitcells/bitcell.py +++ b/compiler/bitcells/bitcell.py @@ -10,7 +10,7 @@ import utils from tech import GDS, layer from tech import cell_properties as props import bitcell_base - +from globals import OPTS class bitcell(bitcell_base.bitcell_base): """ @@ -50,6 +50,8 @@ class bitcell(bitcell_base.bitcell_base): self.pin_map = bitcell.pin_map self.add_pin_types(self.type_list) self.nets_match = self.do_nets_exist(self.storage_nets) + + debug.check(OPTS.tech_name != "sky130", "sky130 does not yet support single port cells") def get_all_wl_names(self): """ Creates a list of all wordline pin names """ From 92fc30005c028db65376e784c57df1fb5d8043eb Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 22 Jun 2020 16:55:49 -0700 Subject: [PATCH 05/20] Use factory in and_dec tests --- compiler/tests/04_and2_dec_test.py | 11 +++++++---- compiler/tests/04_and3_dec_test.py | 11 +++++++---- compiler/tests/04_and4_dec_test.py | 13 ++++++++----- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/compiler/tests/04_and2_dec_test.py b/compiler/tests/04_and2_dec_test.py index 355d3b15..97ac5749 100755 --- a/compiler/tests/04_and2_dec_test.py +++ b/compiler/tests/04_and2_dec_test.py @@ -23,10 +23,13 @@ class and2_dec_test(openram_test): global verify import verify - import and2_dec - - debug.info(2, "Testing and2 gate 4x") - a = and2_dec.and2_dec(name="and2x4", size=4) + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(2, "Testing and2_dec gate") + a = factory.create(module_type="and2_dec") self.local_check(a) globals.end_openram() diff --git a/compiler/tests/04_and3_dec_test.py b/compiler/tests/04_and3_dec_test.py index 7794f36b..ec83335b 100755 --- a/compiler/tests/04_and3_dec_test.py +++ b/compiler/tests/04_and3_dec_test.py @@ -23,10 +23,13 @@ class and3_dec_test(openram_test): global verify import verify - import and3_dec - - debug.info(2, "Testing and3 gate 4x") - a = and3_dec.and3_dec(name="and3x4", size=4) + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(2, "Testing and3_dec gate") + a = factory.create(module_type="and3_dec") self.local_check(a) globals.end_openram() diff --git a/compiler/tests/04_and4_dec_test.py b/compiler/tests/04_and4_dec_test.py index 7794f36b..bdd91c40 100755 --- a/compiler/tests/04_and4_dec_test.py +++ b/compiler/tests/04_and4_dec_test.py @@ -15,7 +15,7 @@ from globals import OPTS from sram_factory import factory import debug -class and3_dec_test(openram_test): +class and4_dec_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -23,10 +23,13 @@ class and3_dec_test(openram_test): global verify import verify - import and3_dec - - debug.info(2, "Testing and3 gate 4x") - a = and3_dec.and3_dec(name="and3x4", size=4) + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(2, "Testing and4_dec gate") + a = factory.create(module_type="and4_dec") self.local_check(a) globals.end_openram() From 7ea3366ef1b554b326202460a05001882b4d1389 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 22 Jun 2020 16:58:01 -0700 Subject: [PATCH 06/20] Disable magic filter in sky130 --- compiler/verify/calibre.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index d4f31960..0a975599 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -189,7 +189,7 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False): num_drc_runs += 1 # Filter the layouts through magic as a GDS filter for nsdm/psdm/nwell merging - if OPTS.tech_name == "sky130": + if OPTS.tech_name == "sky130" and False: shutil.copy(gds_name, OPTS.openram_temp + "temp.gds") from magic import filter_gds filter_gds(cell_name, OPTS.openram_temp + "temp.gds", OPTS.openram_temp + cell_name + ".gds") From 1a528f9739db719eded519d0afc682d2a3988fcc Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 23 Jun 2020 10:08:28 -0700 Subject: [PATCH 07/20] Skip and4_dec test --- compiler/tests/04_and4_dec_test.py | 2 ++ compiler/tests/{skip_tests_s8.txt => skip_tests_sky130.txt} | 0 2 files changed, 2 insertions(+) rename compiler/tests/{skip_tests_s8.txt => skip_tests_sky130.txt} (100%) diff --git a/compiler/tests/04_and4_dec_test.py b/compiler/tests/04_and4_dec_test.py index bdd91c40..ffd7788a 100755 --- a/compiler/tests/04_and4_dec_test.py +++ b/compiler/tests/04_and4_dec_test.py @@ -15,6 +15,8 @@ from globals import OPTS from sram_factory import factory import debug + +@unittest.skip("SKIPPING 04_and4_dec_test") class and4_dec_test(openram_test): def runTest(self): diff --git a/compiler/tests/skip_tests_s8.txt b/compiler/tests/skip_tests_sky130.txt similarity index 100% rename from compiler/tests/skip_tests_s8.txt rename to compiler/tests/skip_tests_sky130.txt From 031862c7495c20518a717fd55005ca98a5eeb226 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 23 Jun 2020 11:56:50 -0700 Subject: [PATCH 08/20] Add metal enclosure to base case of center via stack. --- compiler/base/hierarchy_layout.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index c9b6a7a8..9331f31d 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -599,6 +599,10 @@ class layout(): """ if from_layer == to_layer: + # In the case where we have no vias added, make sure that there is at least + # a metal enclosure. This helps with center-line path routing. + self.add_rect_center(layer=from_layer, + offset=offset) return last_via from_id = layer_indices[from_layer] From e849a9b973e3c316838140aa955db5ce08fb29c1 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 23 Jun 2020 14:53:24 -0700 Subject: [PATCH 09/20] Use different LVS libs based on tech and sky130 --- compiler/base/hierarchy_design.py | 8 ++++++-- compiler/pgates/ptx.py | 28 +++++++++++++--------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index 20c40f21..ac3fb30b 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -11,7 +11,7 @@ import verify import debug import os from globals import OPTS - +import tech class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): """ @@ -26,7 +26,11 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): # If we have a separate lvs directory, then all the lvs files # should be in there (all or nothing!) - lvs_dir = OPTS.openram_tech + "lvs_lib/" + try: + lvs_subdir = tech.lvs_lib + except AttributeError: + lvs_subdir = "lvs_lib" + lvs_dir = OPTS.openram_tech + lvs_subdir + "/" if os.path.exists(lvs_dir): self.lvs_file = lvs_dir + name + ".sp" else: diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index fb127158..9af08e61 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -131,8 +131,8 @@ 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": - # sky130 technology is in microns, also needs mult parameter + if OPTS.tech_name == "sky130" and OPTS.lvs_exe[0] == "calibre": + # sky130 simulation cannot use the mult parameter in simulation (self.tx_width, self.mults) = pgate.bin_width(self.tx_type, self.tx_width) main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type], self.mults, @@ -152,19 +152,17 @@ class ptx(design.design): self.spice_device = main_str + area_str self.spice.append("\n* ptx " + self.spice_device) - # LVS lib is always in SI units - if os.path.exists(OPTS.openram_tech + "lvs_lib"): - if OPTS.tech_name == "sky130": - # 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")) - 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")) + if OPTS.tech_name == "sky130" 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")) + 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")) def setup_layout_constants(self): """ From 83001e1ab51e97d269194ffccf30e809c34e8094 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 23 Jun 2020 15:39:26 -0700 Subject: [PATCH 10/20] PEP8 formatting --- compiler/base/hierarchy_spice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 5ba60435..5a15fce5 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -215,7 +215,7 @@ class spice(): # We don't define self.lvs and will use self.spice if dynamically created # or they are the same file - if self.lvs_file!=self.sp_file and os.path.isfile(self.lvs_file): + if self.lvs_file != self.sp_file and os.path.isfile(self.lvs_file): debug.info(3, "opening {0}".format(self.lvs_file)) f = open(self.lvs_file) self.lvs = f.readlines() From cfa234a4d0307643f1da33bae846189d3fee3862 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 23 Jun 2020 15:39:42 -0700 Subject: [PATCH 11/20] Extra space between decoders for well spacing --- compiler/modules/hierarchical_decoder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 8830d397..3233bdc8 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -152,7 +152,7 @@ class hierarchical_decoder(design.design): self.predecoder_width = self.pre2_4.width # How much space between each predecoder - self.predecoder_spacing = self.and2.height + self.predecoder_spacing = 2 * self.and2.height self.predecoder_height = self.pre2_4.height * self.no_of_pre2x4 + self.pre3_8.height * self.no_of_pre3x8 \ + (self.no_of_pre2x4 + self.no_of_pre3x8 - 1) * self.predecoder_spacing From 22c821f5d868865910d4bffb82f8e23a0bf01373 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 23 Jun 2020 15:40:00 -0700 Subject: [PATCH 12/20] Change port_address test to 256 for riscv --- compiler/tests/18_port_address_1rw_1r_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/tests/18_port_address_1rw_1r_test.py b/compiler/tests/18_port_address_1rw_1r_test.py index ff09dec9..caf2cb96 100755 --- a/compiler/tests/18_port_address_1rw_1r_test.py +++ b/compiler/tests/18_port_address_1rw_1r_test.py @@ -30,8 +30,8 @@ class port_address_1rw_1r_test(openram_test): a = factory.create("port_address", cols=16, rows=16) self.local_check(a) - debug.info(1, "Port address 512 rows") - a = factory.create("port_address", cols=256, rows=512) + debug.info(1, "Port address 256 rows") + a = factory.create("port_address", cols=256, rows=256) self.local_check(a) globals.end_openram() From 4e83e8c648025c40898b785a29898228e2fd1966 Mon Sep 17 00:00:00 2001 From: Joey Kunzler Date: Tue, 23 Jun 2020 18:13:17 -0700 Subject: [PATCH 13/20] added contact to locali for wmask --- compiler/modules/write_mask_and_array.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/modules/write_mask_and_array.py b/compiler/modules/write_mask_and_array.py index 581f9484..f337ab7a 100644 --- a/compiler/modules/write_mask_and_array.py +++ b/compiler/modules/write_mask_and_array.py @@ -10,7 +10,7 @@ import debug from sram_factory import factory from vector import vector from globals import OPTS - +from tech import layer class write_mask_and_array(design.design): """ @@ -93,7 +93,7 @@ class write_mask_and_array(design.design): self.width = self.bitcell.width * self.columns self.height = self.and2.height - + for i in range(self.num_wmasks): base = vector(i * self.wmask_en_len, 0) self.and2_insts[i].place(base) @@ -121,16 +121,17 @@ class write_mask_and_array(design.design): for supply in ["gnd", "vdd"]: supply_pin=self.and2_insts[i].get_pin(supply) - self.add_power_pin(supply, supply_pin.center()) + if "li" in layer: + self.add_power_pin(supply, supply_pin.center(), start_layer="li", directions = ("H", "H")) + else: + self.add_power_pin(supply, supply_pin.center()) for supply in ["gnd", "vdd"]: supply_pin_left = self.and2_insts[0].get_pin(supply) supply_pin_right = self.and2_insts[self.num_wmasks - 1].get_pin(supply) self.add_path(supply_pin_left.layer, [supply_pin_left.lc(), supply_pin_right.rc()]) - + def get_cin(self): """Get the relative capacitance of all the input connections in the bank""" # The enable is connected to an and2 for every row. return self.and2.get_cin() * len(self.and2_insts) - - From 22ed725a35446fe3f10d9509d1f11d6d85f56cf9 Mon Sep 17 00:00:00 2001 From: Joey Kunzler Date: Tue, 23 Jun 2020 18:16:14 -0700 Subject: [PATCH 14/20] made 1rw_1r tests for write driver and wmask, fixed typo in portdata_wmask_1rw_1r_test --- .../10_write_driver_array_1rw_1r_test.py | 44 ++++++++++++++++ .../10_write_mask_and_array_1rw_1r_test.py | 51 +++++++++++++++++++ .../tests/18_port_data_wmask_1rw_1r_test.py | 5 ++ 3 files changed, 100 insertions(+) create mode 100644 compiler/tests/10_write_driver_array_1rw_1r_test.py create mode 100644 compiler/tests/10_write_mask_and_array_1rw_1r_test.py diff --git a/compiler/tests/10_write_driver_array_1rw_1r_test.py b/compiler/tests/10_write_driver_array_1rw_1r_test.py new file mode 100644 index 00000000..4acbf053 --- /dev/null +++ b/compiler/tests/10_write_driver_array_1rw_1r_test.py @@ -0,0 +1,44 @@ +#!/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 write_driver_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, "Testing write_driver_array for columns=8, word_size=8") + a = factory.create(module_type="write_driver_array", columns=8, word_size=8) + self.local_check(a) + + debug.info(2, "Testing write_driver_array for columns=16, word_size=8") + a = factory.create(module_type="write_driver_array", columns=16, word_size=8) + 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()) diff --git a/compiler/tests/10_write_mask_and_array_1rw_1r_test.py b/compiler/tests/10_write_mask_and_array_1rw_1r_test.py new file mode 100644 index 00000000..73988db9 --- /dev/null +++ b/compiler/tests/10_write_mask_and_array_1rw_1r_test.py @@ -0,0 +1,51 @@ +#!/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 write_mask_and_array_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, "Testing write_mask_and_array for columns=8, word_size=8, write_size=4") + a = factory.create(module_type="write_mask_and_array", columns=8, word_size=8, write_size=4) + self.local_check(a) + + debug.info(2, "Testing write_mask_and_array for columns=16, word_size=16, write_size=4") + a = factory.create(module_type="write_mask_and_array", columns=16, word_size=16, write_size=4) + self.local_check(a) + + debug.info(2, "Testing write_mask_and_array for columns=16, word_size=8, write_size=2") + a = factory.create(module_type="write_mask_and_array", columns=16, word_size=8, write_size=2) + 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()) diff --git a/compiler/tests/18_port_data_wmask_1rw_1r_test.py b/compiler/tests/18_port_data_wmask_1rw_1r_test.py index 52d1c4fb..74aa7fc0 100755 --- a/compiler/tests/18_port_data_wmask_1rw_1r_test.py +++ b/compiler/tests/18_port_data_wmask_1rw_1r_test.py @@ -22,6 +22,11 @@ class port_data_wmask_1rw_1r_test(openram_test): globals.init_openram(config_file) from sram_config import sram_config + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + c = sram_config(word_size=16, write_size=4, num_words=16) From b3d1161957aa0a13f0af5b2764f8c53070dab151 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 24 Jun 2020 08:19:25 -0700 Subject: [PATCH 15/20] Add u+x permissions to new tests --- compiler/tests/10_write_driver_array_1rw_1r_test.py | 0 compiler/tests/10_write_mask_and_array_1rw_1r_test.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 compiler/tests/10_write_driver_array_1rw_1r_test.py mode change 100644 => 100755 compiler/tests/10_write_mask_and_array_1rw_1r_test.py diff --git a/compiler/tests/10_write_driver_array_1rw_1r_test.py b/compiler/tests/10_write_driver_array_1rw_1r_test.py old mode 100644 new mode 100755 diff --git a/compiler/tests/10_write_mask_and_array_1rw_1r_test.py b/compiler/tests/10_write_mask_and_array_1rw_1r_test.py old mode 100644 new mode 100755 From a32b5b13e8852a9f68fafbe8fc888aa18fca2160 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 24 Jun 2020 08:26:15 -0700 Subject: [PATCH 16/20] Rename nwell yoffset for consistency --- compiler/pgates/pgate.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index 09074960..104d7a06 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -150,7 +150,7 @@ class pgate(design.design): """ Extend the n/p wells to cover whole cell """ # This should match the cells in the cell library - self.nwell_y_offset = 0.48 * self.height + self.nwell_yoffset = 0.48 * self.height full_height = self.height + 0.5 * self.m1_width # FIXME: float rounding problem @@ -158,8 +158,8 @@ class pgate(design.design): # Add a rail width to extend the well to the top of the rail nwell_max_offset = max(self.find_highest_layer_coords("nwell").y, full_height) - nwell_position = vector(0, self.nwell_y_offset) - vector(self.well_extend_active, 0) - nwell_height = nwell_max_offset - self.nwell_y_offset + nwell_position = vector(0, self.nwell_yoffset) - vector(self.well_extend_active, 0) + nwell_height = nwell_max_offset - self.nwell_yoffset self.add_rect(layer="nwell", offset=nwell_position, width=self.width + 2 * self.well_extend_active, @@ -175,7 +175,7 @@ class pgate(design.design): pwell_min_offset = min(self.find_lowest_layer_coords("pwell").y, -0.5 * self.m1_width) pwell_position = vector(-self.well_extend_active, pwell_min_offset) - pwell_height = self.nwell_y_offset - pwell_position.y + pwell_height = self.nwell_yoffset - pwell_position.y self.add_rect(layer="pwell", offset=pwell_position, width=self.width + 2 * self.well_extend_active, From cddb16dabce5c1d945c9bb80a21ea871ca564a5f Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 24 Jun 2020 09:17:39 -0700 Subject: [PATCH 17/20] Separate active and poly contact to gate rule --- compiler/base/design.py | 3 ++- compiler/pgates/pnand2.py | 4 ++-- compiler/pgates/pnand3.py | 7 +++---- compiler/pgates/precharge.py | 2 +- compiler/pgates/ptx.py | 6 +++--- technology/freepdk45/tech/tech.py | 4 ++-- technology/scn4m_subm/tech/tech.py | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/base/design.py b/compiler/base/design.py index 1fded37e..2b2d7711 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -205,7 +205,8 @@ class design(hierarchy_design): print("poly_to_active", self.poly_to_active) print("poly_extend_active", self.poly_extend_active) print("poly_to_contact", self.poly_to_contact) - print("contact_to_gate", self.contact_to_gate) + print("active_contact_to_gate", self.active_contact_to_gate) + print("poly_contact_to_gate", self.poly_contact_to_gate) print("well_enclose_active", self.well_enclose_active) print("implant_enclose_active", self.implant_enclose_active) print("implant_space", self.implant_space) diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index 12323885..9cc530c0 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -184,7 +184,7 @@ class pnand2(pgate.pgate): # doesn't use nmos uy because that is calculated using offset + poly height active_top = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height active_to_poly_contact = active_top + self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height - active_to_poly_contact2 = active_top + drc("contact_to_gate") + 0.5 * self.route_layer_width + active_to_poly_contact2 = active_top + self.poly_contact_to_gate + 0.5 * self.route_layer_width self.inputA_yoffset = max(active_contact_to_poly_contact, active_to_poly_contact, active_to_poly_contact2) @@ -200,7 +200,7 @@ class pnand2(pgate.pgate): # active_contact_to_poly_contact = self.output_yoffset - self.route_layer_space - 0.5 * contact.poly_contact.second_layer_height # active_bottom = self.pmos1_inst.by() # active_to_poly_contact = active_bottom - self.poly_to_active - 0.5 * contact.poly_contact.first_layer_height - # active_to_poly_contact2 = active_bottom - drc("contact_to_gate") - 0.5 * self.route_layer_width + # active_to_poly_contact2 = active_bottom - self.poly_contact_to_gate - 0.5 * self.route_layer_width # self.inputB_yoffset = min(active_contact_to_poly_contact, # active_to_poly_contact, # active_to_poly_contact2) diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index e227d7af..03652b9b 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -222,7 +222,7 @@ class pnand3(pgate.pgate): # doesn't use nmos uy because that is calculated using offset + poly height active_top = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height active_to_poly_contact = active_top + self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height - active_to_poly_contact2 = active_top + drc("contact_to_gate") + 0.5 * self.route_layer_width + active_to_poly_contact2 = active_top + self.poly_contact_to_gate + 0.5 * self.route_layer_width self.inputA_yoffset = max(active_contact_to_poly_contact, active_to_poly_contact, active_to_poly_contact2) @@ -233,15 +233,14 @@ class pnand3(pgate.pgate): "A", position="left") - # Put B right on the well line - self.inputB_yoffset = self.inputA_yoffset + non_contact_pitch + self.inputB_yoffset = self.inputA_yoffset + 1.2 * self.m3_pitch self.route_input_gate(self.pmos2_inst, self.nmos2_inst, self.inputB_yoffset, "B", position="center") - self.inputC_yoffset = self.inputB_yoffset + non_contact_pitch + self.inputC_yoffset = self.inputB_yoffset + 1.2 * self.m3_pitch self.route_input_gate(self.pmos3_inst, self.nmos3_inst, self.inputC_yoffset, diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index fdce1a35..dc016cab 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -196,7 +196,7 @@ class precharge(design.design): pin_offset = self.lower_pmos_inst.get_pin("G").lr() # This is an extra space down for some techs with contact to active spacing contact_space = max(self.poly_space, - self.contact_to_gate) + 0.5 * contact.poly_contact.first_layer_height + self.poly_contact_to_gate) + 0.5 * contact.poly_contact.first_layer_height offset = pin_offset - vector(0, contact_space) self.add_via_stack_center(from_layer="poly", to_layer=self.en_layer, diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index 9af08e61..8be003b2 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -196,7 +196,7 @@ class ptx(design.design): # This is the spacing between the poly gates self.min_poly_pitch = self.poly_space + self.poly_width self.contacted_poly_pitch = self.poly_space + contact.poly_contact.width - self.contact_pitch = 2 * self.contact_to_gate + self.poly_width + self.contact_width + self.contact_pitch = 2 * self.active_contact_to_gate + self.poly_width + self.contact_width self.poly_pitch = max(self.min_poly_pitch, self.contacted_poly_pitch, self.contact_pitch) @@ -206,7 +206,7 @@ class ptx(design.design): # Active width is determined by enclosure on both ends and contacted pitch, # at least one poly and n-1 poly pitches self.active_width = 2 * self.end_to_contact + self.active_contact.width \ - + 2 * self.contact_to_gate + self.poly_width + (self.mults - 1) * self.poly_pitch + + 2 * self.active_contact_to_gate + self.poly_width + (self.mults - 1) * self.poly_pitch # Active height is just the transistor width self.active_height = self.tx_width @@ -321,7 +321,7 @@ class ptx(design.design): """ # poly is one contacted spacing from the end and down an extension poly_offset = self.contact_offset \ - + vector(0.5 * self.active_contact.width + 0.5 * self.poly_width + self.contact_to_gate, 0) + + vector(0.5 * self.active_contact.width + 0.5 * self.poly_width + self.active_contact_to_gate, 0) # poly_positions are the bottom center of the poly gates self.poly_positions = [] diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index c0379e44..6de01254 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -234,9 +234,9 @@ drc.add_enclosure("active", enclosure = 0.005) # CONTACT.6 Minimum spacing of contact and gate -drc["contact_to_gate"] = 0.0375 #changed from 0.035 +drc["active_contact_to_gate"] = 0.0375 #changed from 0.035 # CONTACT.7 Minimum spacing of contact and poly -drc["contact_to_poly"] = 0.090 +drc["poly_contact_to_gate"] = 0.090 # CONTACT.1 Minimum width of contact # CONTACT.2 Minimum spacing of contact diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 745b381e..55826ec5 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -217,9 +217,9 @@ drc.add_enclosure("active", layer = "contact", enclosure = _lambda_) # Reserved for other technologies -drc["contact_to_gate"] = 2*_lambda_ +drc["active_contact_to_gate"] = 2*_lambda_ # 5.4 Minimum spacing to gate of transistor -drc["contact_to_poly"] = 2*_lambda_ +drc["poly_contact_to_gate"] = 2*_lambda_ # 6.1 Exact contact size # 5.3 Minimum contact spacing From 13409083301834f77115e4abd3a417dff5009e4f Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 24 Jun 2020 09:24:26 -0700 Subject: [PATCH 18/20] Remove fudge factor for pin spacing --- compiler/pgates/pnand3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index 03652b9b..1fd5146f 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -233,14 +233,14 @@ class pnand3(pgate.pgate): "A", position="left") - self.inputB_yoffset = self.inputA_yoffset + 1.2 * self.m3_pitch + self.inputB_yoffset = self.inputA_yoffset + self.m3_pitch self.route_input_gate(self.pmos2_inst, self.nmos2_inst, self.inputB_yoffset, "B", position="center") - self.inputC_yoffset = self.inputB_yoffset + 1.2 * self.m3_pitch + self.inputC_yoffset = self.inputB_yoffset + self.m3_pitch self.route_input_gate(self.pmos3_inst, self.nmos3_inst, self.inputC_yoffset, From 98ec9442c61966cd602eebfddf68990dcddcdc30 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 24 Jun 2020 10:00:00 -0700 Subject: [PATCH 19/20] Add npc enclosure for pnand2, pnand3, pnor2 --- compiler/pgates/pgate.py | 27 +++++++++++++++++++++++++++ compiler/pgates/pnand2.py | 4 ++++ compiler/pgates/pnand3.py | 3 +++ compiler/pgates/pnor2.py | 3 +++ 4 files changed, 37 insertions(+) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index 104d7a06..bb105f36 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -43,6 +43,9 @@ class pgate(design.design): self.route_layer_space = getattr(self, "{}_space".format(self.route_layer)) self.route_layer_pitch = getattr(self, "{}_pitch".format(self.route_layer)) + # hack for enclosing input pin with npc + self.input_pin_vias = [] + # This is the space from a S/D contact to the supply rail contact_to_vdd_rail_space = 0.5 * self.route_layer_width + self.route_layer_space # This is a poly-to-poly of a flipped cell @@ -132,6 +135,8 @@ class pgate(design.design): offset=contact_offset, directions=directions) + self.input_pin_vias.append(via) + self.add_layout_pin_rect_center(text=name, layer=self.route_layer, offset=contact_offset, @@ -146,6 +151,28 @@ class pgate(design.design): height=contact.poly_contact.first_layer_width, width=left_gate_offset.x - contact_offset.x) + def enclose_npc(self): + """ Enclose the poly contacts with npc layer """ + ll = None + ur = None + for via in self.input_pin_vias: + # Find ll/ur + if not ll: + ll = via.ll() + else: + ll = ll.min(via.ll()) + if not ur: + ur = via.ur() + else: + ur = ur.max(via.ur()) + + npc_enclose_poly = drc("npc_enclose_poly") + npc_enclose_offset = vector(npc_enclose_poly, npc_enclose_poly) + self.add_rect(layer="npc", + offset=ll - npc_enclose_offset, + width=(ur.x - ll.x) + 2 * npc_enclose_poly, + height=(ur.y - ll.y) + 2 * npc_enclose_poly) + def extend_wells(self): """ Extend the n/p wells to cover whole cell """ diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index 9cc530c0..6a65f721 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -212,6 +212,10 @@ class pnand2(pgate.pgate): "B", position="center") + if OPTS.tech_name == "sky130": + self.enclose_npc() + + def route_output(self): """ Route the Z output """ diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index 1fd5146f..0c2bc081 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -246,6 +246,9 @@ class pnand3(pgate.pgate): self.inputC_yoffset, "C", position="right") + + if OPTS.tech_name == "sky130": + self.enclose_npc() def route_output(self): """ Route the Z output """ diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index 3cceb7f4..7f75ddd1 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -211,6 +211,9 @@ class pnor2(pgate.pgate): self.output_yoffset = self.inputA_yoffset + self.m1_nonpref_pitch + if OPTS.tech_name == "sky130": + self.enclose_npc() + def route_output(self): """ Route the Z output """ # PMOS2 (right) drain From 93d65e84e1ae95a4c754520a3fe42caccdc1894e Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 24 Jun 2020 10:26:49 -0700 Subject: [PATCH 20/20] Fix power pin layer problems in delay line --- compiler/modules/delay_chain.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index ad9bc1cc..c07395f5 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -178,10 +178,14 @@ class delay_chain(design.design): load_list = self.load_inst_map[inst] for pin_name in ["vdd", "gnd"]: pin = load_list[0].get_pin(pin_name) - self.add_power_pin(pin_name, pin.rc() - vector(self.m1_pitch, 0)) + self.add_power_pin(pin_name, + pin.rc() - vector(self.m1_pitch, 0), + start_layer=pin.layer) - pin = load_list[-1].get_pin(pin_name) - self.add_power_pin(pin_name, pin.rc() - vector(0.5 * self.m1_pitch, 0)) + pin = load_list[-2].get_pin(pin_name) + self.add_power_pin(pin_name, + pin.rc() - vector(self.m1_pitch, 0), + start_layer=pin.layer) def add_layout_pins(self):