From dbe8a7f1af7ffcc90a133cf73482ad0e02e1565e Mon Sep 17 00:00:00 2001 From: jcirimel Date: Tue, 9 Feb 2021 20:51:50 -0800 Subject: [PATCH 01/34] fix pwell pin shape bug --- compiler/base/design.py | 10 +++++++++- compiler/base/utils.py | 15 +++++++++------ compiler/gdsMill/gdsMill/vlsiLayout.py | 20 +++++++++++++++++--- technology/freepdk45/tech/tech.py | 2 ++ technology/scn3me_subm/tech/tech.py | 1 + technology/scn4m_subm/tech/tech.py | 2 ++ 6 files changed, 40 insertions(+), 10 deletions(-) diff --git a/compiler/base/design.py b/compiler/base/design.py index c8bf3070..f5cc47fb 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -48,7 +48,10 @@ class design(hierarchy_design): self.add_pin_indices(prop.port_indices) self.add_pin_names(prop.port_map) self.add_pin_types(prop.port_types) - + + def debug_writer(self): + self.gds_write("/home/jesse/output/direct_rw.gds") + (width, height) = utils.get_libcell_size(self.cell_name, GDS["unit"], layer[prop.boundary_layer]) @@ -56,7 +59,12 @@ class design(hierarchy_design): self.pin_map = utils.get_libcell_pins(self.pins, self.cell_name, GDS["unit"]) + import gdsMill + reader = self.gds + writer = gdsMill.Gds2writer(reader) + writer.writeToFile('/home/jesse/output/direct_rw.gds') + self.gds_write("/home/jesse/output/direct_rw.gds") self.width = width self.height = height diff --git a/compiler/base/utils.py b/compiler/base/utils.py index ed016964..c1ac53eb 100644 --- a/compiler/base/utils.py +++ b/compiler/base/utils.py @@ -148,12 +148,15 @@ def get_gds_pins(pin_names, name, gds_filename, units): cell[str(pin_name)] = [] pin_list = cell_vlsi.getPinShape(str(pin_name)) for pin_shape in pin_list: - (lpp, boundary) = pin_shape - rect = [vector(boundary[0], boundary[1]), - vector(boundary[2], boundary[3])] - # this is a list because other cells/designs - # may have must-connect pins - cell[str(pin_name)].append(pin_layout(pin_name, rect, lpp)) + if pin_shape != None: + (lpp, boundary) = pin_shape + rect = [vector(boundary[0], boundary[1]), + vector(boundary[2], boundary[3])] + # this is a list because other cells/designs + # may have must-connect pins + if isinstance(lpp[1], list): + lpp = (lpp[0], None) + cell[str(pin_name)].append(pin_layout(pin_name, rect, lpp)) _GDS_PINS_CACHE[k] = cell return dict(cell) diff --git a/compiler/gdsMill/gdsMill/vlsiLayout.py b/compiler/gdsMill/gdsMill/vlsiLayout.py index bd9968dc..06e4cc66 100644 --- a/compiler/gdsMill/gdsMill/vlsiLayout.py +++ b/compiler/gdsMill/gdsMill/vlsiLayout.py @@ -3,7 +3,7 @@ from datetime import * import numpy as np import math import debug - +from tech import use_purpose, no_pin_shape class VlsiLayout: """Class represent a hierarchical layout""" @@ -215,9 +215,13 @@ class VlsiLayout: self.deduceHierarchy() # self.traverseTheHierarchy() self.populateCoordinateMap() - + #only ones with text for layerNumber in self.layerNumbersInUse: - self.processLabelPins((layerNumber, None)) + #if layerNumber not in no_pin_shape: + if layerNumber in use_purpose: + self.processLabelPins((layerNumber, use_purpose[layerNumber])) + else: + self.processLabelPins((layerNumber, None)) def populateCoordinateMap(self): def addToXyTree(startingStructureName = None,transformPath = None): @@ -903,6 +907,16 @@ def sameLPP(lpp1, lpp2): if lpp1[1] == None or lpp2[1] == None: return lpp1[0] == lpp2[0] + if isinstance(lpp1[1], list): + for i in range(len(lpp1[1])): + if lpp1[0] == lpp2[0] and lpp1[1][i] == lpp2[1]: + return True + + if isinstance(lpp2[1], list): + for i in range(len(lpp2[1])): + if lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1][i]: + return True + return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1] diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index 436d2ff4..03cbf2f9 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -135,6 +135,8 @@ layer["m10"] = (29, 0) layer["text"] = (239, 0) layer["boundary"]= (239, 0) +use_purpose = {} + # Layer names for external PDKs layer_names = {} layer_names["active"] = "active" diff --git a/technology/scn3me_subm/tech/tech.py b/technology/scn3me_subm/tech/tech.py index 0bd12162..018a15da 100755 --- a/technology/scn3me_subm/tech/tech.py +++ b/technology/scn3me_subm/tech/tech.py @@ -63,6 +63,7 @@ layer["text"] = (63, 0) layer["boundary"] = (63, 0) layer["blockage"] = (83, 0) +use_purpose = {} ################################################### ##END GDS Layer Map ################################################### diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 6591fbbc..8b857eb5 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -119,6 +119,8 @@ layer["m4"] = (31, 0) layer["text"] = (63, 0) layer["boundary"] = (63, 0) +use_purpose = {} + # Layer names for external PDKs layer_names = {} layer_names["active"] = "active" From f2d4794cc6f6104657095e9ce1b170668d97ba65 Mon Sep 17 00:00:00 2001 From: jcirimel Date: Tue, 9 Feb 2021 21:01:16 -0800 Subject: [PATCH 02/34] remove unused import --- compiler/gdsMill/gdsMill/vlsiLayout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/gdsMill/gdsMill/vlsiLayout.py b/compiler/gdsMill/gdsMill/vlsiLayout.py index 06e4cc66..2592d251 100644 --- a/compiler/gdsMill/gdsMill/vlsiLayout.py +++ b/compiler/gdsMill/gdsMill/vlsiLayout.py @@ -3,7 +3,7 @@ from datetime import * import numpy as np import math import debug -from tech import use_purpose, no_pin_shape +from tech import use_purpose class VlsiLayout: """Class represent a hierarchical layout""" From 2f1d7b879fd99f5b34bb55f84279585649c9a428 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 14 Apr 2021 15:09:25 -0700 Subject: [PATCH 03/34] make bank compatable with sky130 --- compiler/modules/bank.py | 24 ++++++++++++++---------- compiler/modules/port_data.py | 7 ++++++- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 7f7fb0d4..ce545b10 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -367,13 +367,6 @@ class bank(design.design): def add_modules(self): """ Add all the modules using the class loader """ - self.port_address = [] - for port in self.all_ports: - self.port_address.append(factory.create(module_type="port_address", - cols=self.num_cols + self.num_spare_cols, - rows=self.num_rows, - port=port)) - self.add_mod(self.port_address[port]) local_array_size = OPTS.local_array_size @@ -394,11 +387,22 @@ class bank(design.design): rows=self.num_rows) self.add_mod(self.bitcell_array) + self.port_address = [] + for port in self.all_ports: + self.port_address.append(factory.create(module_type="port_address", + cols=self.bitcell_array.column_size + self.num_spare_cols, + rows=self.bitcell_array.row_size, + port=port)) + self.add_mod(self.port_address[port]) + self.port_data = [] self.bit_offsets = self.get_column_offsets() for port in self.all_ports: temp_pre = factory.create(module_type="port_data", sram_config=self.sram_config, + dimension_override=True, + cols=self.bitcell_array.column_size + self.num_spare_cols, + rows=self.bitcell_array.row_size, port=port, bit_offsets=self.bit_offsets) self.port_data.append(temp_pre) @@ -445,10 +449,10 @@ class bank(design.design): temp.extend(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)]) temp.extend(self.bitcell_array.get_bitline_names(port)) if port in self.read_ports: - for bit in range(self.word_size + self.num_spare_cols): + for bit in range(int(self.bitcell_array.column_size/self.words_per_row) + self.num_spare_cols): temp.append("dout{0}_{1}".format(port, bit)) if port in self.write_ports: - for bit in range(self.word_size + self.num_spare_cols): + for bit in range(int(self.bitcell_array.column_size/self.words_per_row) + self.num_spare_cols): temp.append("din{0}_{1}".format(port, bit)) # Will be empty if no col addr lines sel_names = ["sel{0}_{1}".format(port, x) for x in range(self.num_col_addr_lines)] @@ -485,7 +489,7 @@ class bank(design.design): mod=self.port_address[port]) temp = [] - for bit in range(self.row_addr_size): + for bit in range(ceil(log(self.bitcell_array.row_size, 2))): temp.append("addr{0}_{1}".format(port, bit + self.col_addr_size)) temp.append("wl_en{}".format(port)) wordline_names = self.bitcell_array.get_wordline_names(port) diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 8afa8d06..478ae51d 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -20,9 +20,14 @@ class port_data(design.design): Port 0 always has the RBL on the left while port 1 is on the right. """ - def __init__(self, sram_config, port, bit_offsets=None, name=""): + def __init__(self, sram_config, port, bit_offsets=None, name="", rows=None, cols=None, dimension_override=False): sram_config.set_local_config(self) + if dimension_override: + self.num_rows = rows + self.num_cols = cols + self.word_size = int(self.num_cols/self.words_per_row) + self.port = port if self.write_size is not None: self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) From 4ea0fcd0681df0d60cb98fda0595898692a37ca5 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Fri, 23 Apr 2021 22:49:29 -0700 Subject: [PATCH 04/34] support multi cell wide precharge cells --- compiler/base/custom_cell_properties.py | 2 +- compiler/modules/port_data.py | 18 +++++++++++++----- compiler/modules/precharge_array.py | 2 +- compiler/modules/replica_bitcell_array.py | 2 +- compiler/options.py | 2 ++ compiler/pgates/precharge.py | 6 +++++- 6 files changed, 23 insertions(+), 9 deletions(-) diff --git a/compiler/base/custom_cell_properties.py b/compiler/base/custom_cell_properties.py index bb211842..76bb10ce 100644 --- a/compiler/base/custom_cell_properties.py +++ b/compiler/base/custom_cell_properties.py @@ -176,7 +176,7 @@ class cell_properties(): self.names["col_cap_bitcell_2port"] = "col_cap_cell_2rw" self.names["row_cap_bitcell_1port"] = "row_cap_cell_1rw" self.names["row_cap_bitcell_2port"] = "row_cap_cell_2rw" - + self.use_strap = False self._ptx = _ptx(model_is_subckt=False, bin_spice_models=False) diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 36ba5d0f..c9ebc193 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -11,6 +11,7 @@ from sram_factory import factory from collections import namedtuple from vector import vector from globals import OPTS +from tech import cell_properties from tech import layer_properties as layer_props @@ -39,9 +40,12 @@ class port_data(design.design): if not bit_offsets: bitcell = factory.create(module_type=OPTS.bitcell) + if(cell_properties.use_strap): + strap = factory.create(module_type=cell_properties.strap_module, version=cell_properties.strap_version) + precharge_width = bitcell.width + strap.width self.bit_offsets = [] for i in range(self.num_cols + self.num_spare_cols): - self.bit_offsets.append(i * bitcell.width) + self.bit_offsets.append(i * precharge_width) else: self.bit_offsets = bit_offsets @@ -196,14 +200,18 @@ class port_data(design.design): # and mirroring happens correctly # Used for names/dimensions only - self.cell = factory.create(module_type=OPTS.bitcell) - + cell = factory.create(module_type=OPTS.bitcell) + if(cell_properties.use_strap): + strap = factory.create(module_type=cell_properties.strap_module, version=cell_properties.strap_version) + precharge_width = cell.width + strap.width + if self.port == 0: # Append an offset on the left - precharge_bit_offsets = [self.bit_offsets[0] - self.cell.width] + self.bit_offsets + precharge_bit_offsets = [self.bit_offsets[0] - precharge_width] + self.bit_offsets else: # Append an offset on the right - precharge_bit_offsets = self.bit_offsets + [self.bit_offsets[-1] + self.cell.width] + precharge_bit_offsets = self.bit_offsets + [self.bit_offsets[-1] + precharge_width] + self.precharge_array = factory.create(module_type="precharge_array", columns=self.num_cols + self.num_spare_cols + 1, offsets=precharge_bit_offsets, diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index 8718dfd0..ed19b387 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -76,8 +76,8 @@ class precharge_array(design.design): size=self.size, bitcell_bl=self.bitcell_bl, bitcell_br=self.bitcell_br) + self.add_mod(self.pc_cell) - self.cell = factory.create(module_type=OPTS.bitcell) def add_layout_pins(self): diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 828941ae..5618c74e 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -6,7 +6,7 @@ import debug from bitcell_base_array import bitcell_base_array -from tech import drc, spice +from tech import drc, spice, cell_properties from vector import vector from globals import OPTS from sram_factory import factory diff --git a/compiler/options.py b/compiler/options.py index e3a9a76e..469c3236 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -72,7 +72,9 @@ class options(optparse.Values): # This is the temp directory where all intermediate results are stored. try: # If user defined the temporary location in their environment, use it + openram_temp = os.path.abspath(os.environ.get("OPENRAM_TMP")) + except: openram_temp = "/tmp" diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index d1999384..c8f6d819 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -30,7 +30,11 @@ class precharge(design.design): self.beta = parameter["beta"] self.ptx_width = self.beta * parameter["min_tx_size"] self.ptx_mults = 1 - self.width = self.bitcell.width + if(cell_props.use_strap): + strap = factory.create(module_type=cell_props.strap_module, version=cell_props.strap_version) + self.width = self.bitcell.width + strap.width + else: + self.width = self.bitcell.width self.bitcell_bl = bitcell_bl self.bitcell_br = bitcell_br self.bitcell_bl_pin =self.bitcell.get_pin(self.bitcell_bl) From 33e8bce79d080bcf49855908ecaee6053697f6a7 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Sun, 25 Apr 2021 01:22:36 -0700 Subject: [PATCH 05/34] dynamic predecode working --- compiler/modules/hierarchical_predecode.py | 50 ++++++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index f83516d2..2da123a1 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -12,6 +12,10 @@ from vector import vector from sram_factory import factory from globals import OPTS from tech import layer_properties as layer_props +from tech import layer_indices +from tech import layer_stacks +from tech import preferred_directions +from tech import drc class hierarchical_predecode(design.design): @@ -29,7 +33,7 @@ class hierarchical_predecode(design.design): self.cell_height = height self.column_decoder = column_decoder - + self.input_and_rail_pos = [] self.number_of_outputs = int(math.pow(2, self.number_of_inputs)) super().__init__(name) @@ -183,9 +187,9 @@ class hierarchical_predecode(design.design): def route(self): self.route_input_inverters() - self.route_output_inverters() - self.route_inputs_to_rails() self.route_input_ands() + self.route_output_inverters() + self.route_inputs_to_rails() self.route_output_ands() self.route_vdd_gnd() @@ -274,8 +278,45 @@ class hierarchical_predecode(design.design): # pins in the and gates. inv_out_pos = inv_out_pin.rc() y_offset = (inv_num + 1) * self.inv.height - self.output_layer_pitch - right_pos = inv_out_pos + vector(self.inv.width - self.inv.get_pin("Z").rx(), 0) rail_pos = vector(self.decode_rails[out_pin].cx(), y_offset) + + # create via for dimensions + from_layer = self.output_layer + to_layer = self.bus_layer + + cur_layer = from_layer + from_id = layer_indices[cur_layer] + to_id = layer_indices[to_layer] + + if from_id < to_id: # grow the stack up + search_id = 0 + next_id = 2 + else: # grow the stack down + search_id = 2 + next_id = 0 + + curr_stack = next(filter(lambda stack: stack[search_id] == cur_layer, layer_stacks), None) + + via = factory.create(module_type="contact", + layer_stack=curr_stack, + dimensions=[1, 1], + directions=self.bus_directions) + + overlapping_pin_space = drc["{0}_to_{0}".format(self.output_layer)] + total_buffer_space = (overlapping_pin_space + via.height) + while(True): + drc_error = 0 + for and_input in self.input_and_rail_pos: + if and_input.x == rail_pos.x: + if (abs(y_offset - and_input.y) < total_buffer_space) and (abs(y_offset - and_input.y) > via.height): + drc_error = 1 + if drc_error == 0: + break + else: + y_offset += drc["grid"] + rail_pos.y = y_offset + right_pos = inv_out_pos + vector(self.inv.width - self.inv.get_pin("Z").rx(), 0) + self.add_path(self.output_layer, [inv_out_pos, right_pos, vector(right_pos.x, y_offset), rail_pos]) self.add_via_stack_center(from_layer=inv_out_pin.layer, @@ -316,6 +357,7 @@ class hierarchical_predecode(design.design): to_layer=self.bus_layer, offset=rail_pos, directions=self.bus_directions) + self.input_and_rail_pos.append(rail_pos) if gate_pin == "A": direction = None else: From 3a3da9e0d7106f95f4c103b9cf0eb90f28bd5247 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Sun, 2 May 2021 21:49:09 -0700 Subject: [PATCH 06/34] 56 drc errors on col mux 1port --- compiler/globals.py | 4 +- compiler/modules/bank.py | 17 ++++--- compiler/modules/hierarchical_predecode.py | 1 + compiler/modules/port_data.py | 53 ++++++++++++++-------- compiler/modules/sense_amp_array.py | 16 +++++-- compiler/pgates/column_mux.py | 8 +++- compiler/pgates/precharge.py | 2 +- 7 files changed, 65 insertions(+), 36 deletions(-) diff --git a/compiler/globals.py b/compiler/globals.py index 68d055ff..1d813e97 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -238,8 +238,8 @@ def setup_bitcell(): OPTS.dummy_bitcell = "dummy_pbitcell" OPTS.replica_bitcell = "replica_pbitcell" else: - num_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports - OPTS.bitcell = "bitcell_{}port".format(num_ports) + OPTS.num_ports = OPTS.num_rw_ports + OPTS.num_w_ports + OPTS.num_r_ports + OPTS.bitcell = "bitcell_{}port".format(OPTS.num_ports) OPTS.dummy_bitcell = "dummy_" + OPTS.bitcell OPTS.replica_bitcell = "replica_" + OPTS.bitcell diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 1f06aef3..f02a4f0e 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -72,7 +72,7 @@ class bank(design.design): # self.add_lvs_correspondence_points() # Remember the bank center for further placement - self.bank_array_ll = self.offset_all_coordinates().scale(-1, -1) + #self.bank_array_ll = self.offset_all_coordinates().scale(-1, -1) self.bank_array_ur = self.bitcell_array_inst.ur() self.bank_array_ul = self.bitcell_array_inst.ul() self.DRC_LVS() @@ -362,7 +362,9 @@ class bank(design.design): # A space for wells or jogging m2 self.m2_gap = max(2 * drc("pwell_to_nwell") + drc("nwell_enclose_active"), - 3 * self.m2_pitch) + 3 * self.m2_pitch, + drc("nwell_to_nwell")) + def add_modules(self): """ Add all the modules using the class loader """ @@ -386,11 +388,12 @@ class bank(design.design): cols=self.num_cols + self.num_spare_cols, rows=self.num_rows) self.add_mod(self.bitcell_array) + self.num_spare_cols += (self.bitcell_array.column_size % (self.word_size *self.words_per_row)) self.port_address = [] for port in self.all_ports: self.port_address.append(factory.create(module_type="port_address", - cols=self.bitcell_array.column_size + self.num_spare_cols, + cols=self.bitcell_array.column_size, rows=self.bitcell_array.row_size, port=port)) self.add_mod(self.port_address[port]) @@ -401,8 +404,9 @@ class bank(design.design): temp_pre = factory.create(module_type="port_data", sram_config=self.sram_config, dimension_override=True, - cols=self.bitcell_array.column_size + self.num_spare_cols, + cols=self.bitcell_array.column_size - self.num_spare_cols, rows=self.bitcell_array.row_size, + num_spare_cols=self.num_spare_cols, port=port, bit_offsets=self.bit_offsets) self.port_data.append(temp_pre) @@ -430,7 +434,6 @@ class bank(design.design): temp.append("vdd") temp.append("gnd") - self.connect_inst(temp) def place_bitcell_array(self, offset): @@ -449,10 +452,10 @@ class bank(design.design): temp.extend(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)]) temp.extend(self.bitcell_array.get_bitline_names(port)) if port in self.read_ports: - for bit in range(int(self.bitcell_array.column_size/self.words_per_row) + self.num_spare_cols): + for bit in range(self.word_size + self.num_spare_cols): temp.append("dout{0}_{1}".format(port, bit)) if port in self.write_ports: - for bit in range(int(self.bitcell_array.column_size/self.words_per_row) + self.num_spare_cols): + for bit in range(self.word_size + self.num_spare_cols): temp.append("din{0}_{1}".format(port, bit)) # Will be empty if no col addr lines sel_names = ["sel{0}_{1}".format(port, x) for x in range(self.num_col_addr_lines)] diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index 2da123a1..386f9bb6 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -304,6 +304,7 @@ class hierarchical_predecode(design.design): overlapping_pin_space = drc["{0}_to_{0}".format(self.output_layer)] total_buffer_space = (overlapping_pin_space + via.height) + #FIXME: compute rail locations instead of just guessing and nudging while(True): drc_error = 0 for and_input in self.input_and_rail_pos: diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index c9ebc193..6f66d26f 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -21,26 +21,27 @@ class port_data(design.design): Port 0 always has the RBL on the left while port 1 is on the right. """ - def __init__(self, sram_config, port, bit_offsets=None, name="", rows=None, cols=None, dimension_override=False): + def __init__(self, sram_config, port, num_spare_cols=None, bit_offsets=None, name="", rows=None, cols=None, dimension_override=False): sram_config.set_local_config(self) if dimension_override: self.num_rows = rows self.num_cols = cols - self.word_size = int(self.num_cols/self.words_per_row) + self.word_size = sram_config.word_size self.port = port if self.write_size is not None: self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) else: self.num_wmasks = 0 - + + if num_spare_cols is not None: + self.num_spare_cols = num_spare_cols + self.num_spare_cols if self.num_spare_cols is None: self.num_spare_cols = 0 - if not bit_offsets: bitcell = factory.create(module_type=OPTS.bitcell) - if(cell_properties.use_strap): + if(cell_properties.use_strap == True and OPTS.num_ports == 1): strap = factory.create(module_type=cell_properties.strap_module, version=cell_properties.strap_version) precharge_width = bitcell.width + strap.width self.bit_offsets = [] @@ -48,7 +49,6 @@ class port_data(design.design): self.bit_offsets.append(i * precharge_width) else: self.bit_offsets = bit_offsets - if name == "": name = "port_data_{0}".format(self.port) super().__init__(name) @@ -126,7 +126,6 @@ class port_data(design.design): for bit in range(self.num_spare_cols): self.add_pin("sparebl_{0}".format(bit), "INOUT") self.add_pin("sparebr_{0}".format(bit), "INOUT") - if self.port in self.read_ports: for bit in range(self.word_size + self.num_spare_cols): self.add_pin("dout_{}".format(bit), "OUTPUT") @@ -201,10 +200,11 @@ class port_data(design.design): # Used for names/dimensions only cell = factory.create(module_type=OPTS.bitcell) - if(cell_properties.use_strap): + if(cell_properties.use_strap == True and OPTS.num_ports == 1): strap = factory.create(module_type=cell_properties.strap_module, version=cell_properties.strap_version) precharge_width = cell.width + strap.width - + else: + precharge_width = cell.width if self.port == 0: # Append an offset on the left precharge_bit_offsets = [self.bit_offsets[0] - precharge_width] + self.bit_offsets @@ -580,19 +580,32 @@ class port_data(design.design): off = 1 else: off = 0 + if OPTS.num_ports > 1: + self.channel_route_bitlines(inst1=self.column_mux_array_inst, + inst1_bls_template="{inst}_out_{bit}", + inst2=inst2, + num_bits=self.word_size, + inst1_start_bit=start_bit) - self.channel_route_bitlines(inst1=self.column_mux_array_inst, - inst1_bls_template="{inst}_out_{bit}", - inst2=inst2, - num_bits=self.word_size, - inst1_start_bit=start_bit) + self.channel_route_bitlines(inst1=self.precharge_array_inst, + inst1_bls_template="{inst}_{bit}", + inst2=inst2, + num_bits=self.num_spare_cols, + inst1_start_bit=self.num_cols + off, + inst2_start_bit=self.word_size) + else: + self.connect_bitlines(inst1=self.column_mux_array_inst, + inst1_bls_template="{inst}_out_{bit}", + inst2=inst2, + num_bits=self.word_size, + inst1_start_bit=start_bit) - self.channel_route_bitlines(inst1=self.precharge_array_inst, - inst1_bls_template="{inst}_{bit}", - inst2=inst2, - num_bits=self.num_spare_cols, - inst1_start_bit=self.num_cols + off, - inst2_start_bit=self.word_size) + self.connect_bitlines(inst1=self.precharge_array_inst, + inst1_bls_template="{inst}_{bit}", + inst2=inst2, + num_bits=self.num_spare_cols, + inst1_start_bit=self.num_cols + off, + inst2_start_bit=self.word_size) elif layer_props.port_data.channel_route_bitlines: self.channel_route_bitlines(inst1=inst1, diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 01b74c84..be9e9945 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -8,6 +8,7 @@ import design from vector import vector from sram_factory import factory +from tech import cell_properties import debug from globals import OPTS @@ -41,7 +42,6 @@ class sense_amp_array(design.design): self.en_layer = "m3" else: self.en_layer = "m1" - self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -109,15 +109,22 @@ class sense_amp_array(design.design): self.en_name, "vdd", "gnd"]) def place_sense_amp_array(self): - if self.bitcell.width > self.amp.width: - self.amp_spacing = self.bitcell.width + cell = factory.create(module_type=OPTS.bitcell) + if(cell_properties.use_strap == True and OPTS.num_ports == 1): + strap = factory.create(module_type=cell_properties.strap_module, version=cell_properties.strap_version) + precharge_width = cell.width + strap.width + else: + precharge_width = cell.width + + if precharge_width > self.amp.width: + self.amp_spacing = precharge_width else: self.amp_spacing = self.amp.width if not self.offsets: self.offsets = [] for i in range(self.num_cols + self.num_spare_cols): - self.offsets.append(i * self.bitcell.width) + self.offsets.append(i * precharge_width) for i, xoffset in enumerate(self.offsets[0:self.num_cols:self.words_per_row]): if self.bitcell.mirror.y and (i * self.words_per_row + self.column_offset) % 2: @@ -128,7 +135,6 @@ class sense_amp_array(design.design): amp_position = vector(xoffset, 0) self.local_insts[i].place(offset=amp_position, mirror=mirror) - # place spare sense amps (will share the same enable as regular sense amps) for i, xoffset in enumerate(self.offsets[self.num_cols:]): index = self.word_size + i diff --git a/compiler/pgates/column_mux.py b/compiler/pgates/column_mux.py index 1e8c5bf8..6153328a 100644 --- a/compiler/pgates/column_mux.py +++ b/compiler/pgates/column_mux.py @@ -56,7 +56,13 @@ class column_mux(pgate.pgate): self.place_ptx() - self.width = self.bitcell.width + cell = factory.create(module_type=OPTS.bitcell) + if(cell_props.use_strap == True and OPTS.num_ports == 1): + strap = factory.create(module_type=cell_props.strap_module, version=cell_props.strap_version) + precharge_width = cell.width + strap.width + else: + precharge_width = cell.width + self.width = precharge_width self.height = self.nmos_upper.uy() + self.pin_height self.connect_poly() diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index c8f6d819..951fe834 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -30,7 +30,7 @@ class precharge(design.design): self.beta = parameter["beta"] self.ptx_width = self.beta * parameter["min_tx_size"] self.ptx_mults = 1 - if(cell_props.use_strap): + if(cell_props.use_strap == True and OPTS.num_ports == 1): strap = factory.create(module_type=cell_props.strap_module, version=cell_props.strap_version) self.width = self.bitcell.width + strap.width else: From 64b1946d6ed60338b8384c8156aed824e0fce570 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Mon, 3 May 2021 12:52:07 -0700 Subject: [PATCH 07/34] sky130 singlebank drc clean --- compiler/pgates/column_mux.py | 11 +++++-- compiler/tests/19_single_bank_test.py | 42 +++++++++++++-------------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/compiler/pgates/column_mux.py b/compiler/pgates/column_mux.py index 6153328a..062ef02e 100644 --- a/compiler/pgates/column_mux.py +++ b/compiler/pgates/column_mux.py @@ -223,10 +223,15 @@ class column_mux(pgate.pgate): Add a well and implant over the whole cell. Also, add the pwell contact (if it exists) """ - + if(cell_props.use_strap == True and OPTS.num_ports == 1): + strap = factory.create(module_type=cell_props.strap_module, version=cell_props.strap_version) + rbc_width = self.bitcell.width + strap.width + else: + rbc_width = cell.width # Add it to the right, aligned in between the two tx - active_pos = vector(self.bitcell.width, + active_pos = vector(rbc_width, self.nmos_upper.by() - 0.5 * self.poly_space) + self.add_via_center(layers=self.active_stack, offset=active_pos, implant_type="p", @@ -245,5 +250,5 @@ class column_mux(pgate.pgate): if "pwell" in layer: self.add_rect(layer="pwell", offset=vector(0, 0), - width=self.bitcell.width, + width=rbc_width, height=self.height) diff --git a/compiler/tests/19_single_bank_test.py b/compiler/tests/19_single_bank_test.py index c8db9e2f..fd90e218 100755 --- a/compiler/tests/19_single_bank_test.py +++ b/compiler/tests/19_single_bank_test.py @@ -26,20 +26,20 @@ class single_bank_test(openram_test): c = sram_config(word_size=4, num_words=16) - c.words_per_row=1 - factory.reset() - c.recompute_sizes() - debug.info(1, "No column mux") - a = factory.create("bank", sram_config=c) - self.local_check(a) + # c.words_per_row=1 + # factory.reset() + # c.recompute_sizes() + # debug.info(1, "No column mux") + # a = factory.create("bank", sram_config=c) + # self.local_check(a) - c.num_words=32 - c.words_per_row=2 - factory.reset() - c.recompute_sizes() - debug.info(1, "Two way column mux") - a = factory.create("bank", sram_config=c) - self.local_check(a) + # c.num_words=32 + # c.words_per_row=2 + # factory.reset() + # c.recompute_sizes() + # debug.info(1, "Two way column mux") + # a = factory.create("bank", sram_config=c) + # self.local_check(a) c.num_words=64 c.words_per_row=4 @@ -49,14 +49,14 @@ class single_bank_test(openram_test): a = factory.create("bank", sram_config=c) self.local_check(a) - c.word_size=2 - c.num_words=128 - c.words_per_row=8 - factory.reset() - c.recompute_sizes() - debug.info(1, "Eight way column mux") - a = factory.create("bank", sram_config=c) - self.local_check(a) + #c.word_size=2 + #c.num_words=128 + #c.words_per_row=8 + #factory.reset() + #c.recompute_sizes() + #debug.info(1, "Eight way column mux") + #a = factory.create("bank", sram_config=c) + #self.local_check(a) globals.end_openram() From 31364e508ee99bd84ae4a8166feb6d1a86e1c584 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Mon, 3 May 2021 13:08:04 -0700 Subject: [PATCH 08/34] uncomment test (passing) --- compiler/pgates/column_mux.py | 2 +- compiler/tests/19_single_bank_test.py | 42 +++++++++++++-------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/compiler/pgates/column_mux.py b/compiler/pgates/column_mux.py index 062ef02e..0dd923ba 100644 --- a/compiler/pgates/column_mux.py +++ b/compiler/pgates/column_mux.py @@ -227,7 +227,7 @@ class column_mux(pgate.pgate): strap = factory.create(module_type=cell_props.strap_module, version=cell_props.strap_version) rbc_width = self.bitcell.width + strap.width else: - rbc_width = cell.width + rbc_width = self.bitcell.width # Add it to the right, aligned in between the two tx active_pos = vector(rbc_width, self.nmos_upper.by() - 0.5 * self.poly_space) diff --git a/compiler/tests/19_single_bank_test.py b/compiler/tests/19_single_bank_test.py index fd90e218..c8db9e2f 100755 --- a/compiler/tests/19_single_bank_test.py +++ b/compiler/tests/19_single_bank_test.py @@ -26,20 +26,20 @@ class single_bank_test(openram_test): c = sram_config(word_size=4, num_words=16) - # c.words_per_row=1 - # factory.reset() - # c.recompute_sizes() - # debug.info(1, "No column mux") - # a = factory.create("bank", sram_config=c) - # self.local_check(a) + c.words_per_row=1 + factory.reset() + c.recompute_sizes() + debug.info(1, "No column mux") + a = factory.create("bank", sram_config=c) + self.local_check(a) - # c.num_words=32 - # c.words_per_row=2 - # factory.reset() - # c.recompute_sizes() - # debug.info(1, "Two way column mux") - # a = factory.create("bank", sram_config=c) - # self.local_check(a) + c.num_words=32 + c.words_per_row=2 + factory.reset() + c.recompute_sizes() + debug.info(1, "Two way column mux") + a = factory.create("bank", sram_config=c) + self.local_check(a) c.num_words=64 c.words_per_row=4 @@ -49,14 +49,14 @@ class single_bank_test(openram_test): a = factory.create("bank", sram_config=c) self.local_check(a) - #c.word_size=2 - #c.num_words=128 - #c.words_per_row=8 - #factory.reset() - #c.recompute_sizes() - #debug.info(1, "Eight way column mux") - #a = factory.create("bank", sram_config=c) - #self.local_check(a) + c.word_size=2 + c.num_words=128 + c.words_per_row=8 + factory.reset() + c.recompute_sizes() + debug.info(1, "Eight way column mux") + a = factory.create("bank", sram_config=c) + self.local_check(a) globals.end_openram() From 4377619bf6d0645950abbe92faf5a346419825b9 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Mon, 3 May 2021 14:39:51 -0700 Subject: [PATCH 09/34] fixed port_data typo --- compiler/modules/port_data.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 6f66d26f..b4320583 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -44,6 +44,8 @@ class port_data(design.design): if(cell_properties.use_strap == True and OPTS.num_ports == 1): strap = factory.create(module_type=cell_properties.strap_module, version=cell_properties.strap_version) precharge_width = bitcell.width + strap.width + else: + precharge_width = bitcell.width self.bit_offsets = [] for i in range(self.num_cols + self.num_spare_cols): self.bit_offsets.append(i * precharge_width) From 14e087a5ebb6f6837f2803c368571da76a3a615c Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Mon, 3 May 2021 15:51:53 -0700 Subject: [PATCH 10/34] offset bank coordinates --- compiler/modules/bank.py | 2 +- compiler/sram/sram_1bank.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index f02a4f0e..317ebe8f 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -72,7 +72,7 @@ class bank(design.design): # self.add_lvs_correspondence_points() # Remember the bank center for further placement - #self.bank_array_ll = self.offset_all_coordinates().scale(-1, -1) + self.bank_array_ll = self.offset_all_coordinates().scale(-1, -1) self.bank_array_ur = self.bitcell_array_inst.ur() self.bank_array_ul = self.bitcell_array_inst.ul() self.DRC_LVS() diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 6bc2cd43..cf4c08e8 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -140,6 +140,7 @@ class sram_1bank(sram_base): # This includes 2 M2 pitches for the row addr clock line. # The delay line is aligned with the bitcell array while the control logic is aligned with the port_data # using the control_logic_center value. + breakpoint() self.control_pos[port] = vector(-self.control_logic_insts[port].width - 2 * self.m2_pitch, self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y) self.control_logic_insts[port].place(self.control_pos[port]) From a7d0a1ef3a938c3fe51cb6224280e7d87e473650 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Mon, 3 May 2021 16:54:54 -0700 Subject: [PATCH 11/34] remove breakpoint --- compiler/sram/sram_1bank.py | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index cf4c08e8..6bc2cd43 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -140,7 +140,6 @@ class sram_1bank(sram_base): # This includes 2 M2 pitches for the row addr clock line. # The delay line is aligned with the bitcell array while the control logic is aligned with the port_data # using the control_logic_center value. - breakpoint() self.control_pos[port] = vector(-self.control_logic_insts[port].width - 2 * self.m2_pitch, self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y) self.control_logic_insts[port].place(self.control_pos[port]) From 93b264bc4c2e606bc934f26abbb0c2554ede66aa Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Mon, 3 May 2021 21:59:05 -0700 Subject: [PATCH 12/34] allow spare col number override --- compiler/modules/port_data.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index b4320583..7bf5884f 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -22,7 +22,6 @@ class port_data(design.design): """ def __init__(self, sram_config, port, num_spare_cols=None, bit_offsets=None, name="", rows=None, cols=None, dimension_override=False): - sram_config.set_local_config(self) if dimension_override: self.num_rows = rows @@ -35,10 +34,9 @@ class port_data(design.design): else: self.num_wmasks = 0 - if num_spare_cols is not None: - self.num_spare_cols = num_spare_cols + self.num_spare_cols - if self.num_spare_cols is None: - self.num_spare_cols = 0 + + if self.num_spare_cols is None or self.num_spare_cols is 0: + self.num_spare_cols = num_spare_cols if not bit_offsets: bitcell = factory.create(module_type=OPTS.bitcell) if(cell_properties.use_strap == True and OPTS.num_ports == 1): From d0e9de1f136a16ac67017f16c3a9a826cf0087cf Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Tue, 4 May 2021 00:41:20 -0700 Subject: [PATCH 13/34] fix port data spare col --- compiler/modules/port_data.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 7bf5884f..3fbb8696 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -33,10 +33,12 @@ class port_data(design.design): self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) else: self.num_wmasks = 0 - - if self.num_spare_cols is None or self.num_spare_cols is 0: + if num_spare_cols: self.num_spare_cols = num_spare_cols + elif self.num_spare_cols is None: + self.num_spare_cols = 0 + if not bit_offsets: bitcell = factory.create(module_type=OPTS.bitcell) if(cell_properties.use_strap == True and OPTS.num_ports == 1): From 1b53d12df2f29bab0fd50647fea930eb87bfd4d5 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Tue, 4 May 2021 01:52:51 -0700 Subject: [PATCH 14/34] don't double count spare col --- compiler/modules/bank.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 317ebe8f..d1b5a90d 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -388,7 +388,8 @@ class bank(design.design): cols=self.num_cols + self.num_spare_cols, rows=self.num_rows) self.add_mod(self.bitcell_array) - self.num_spare_cols += (self.bitcell_array.column_size % (self.word_size *self.words_per_row)) + if self.num_spare_cols == 0: + self.num_spare_cols = (self.bitcell_array.column_size % (self.word_size *self.words_per_row)) self.port_address = [] for port in self.all_ports: From 6d8411d19ffbf6ca28fae5e0a71f47f9e9a2d44d Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Fri, 7 May 2021 11:29:43 -0700 Subject: [PATCH 15/34] use consistent amp spacing --- compiler/modules/sense_amp_array.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index be9e9945..713f4daf 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -124,7 +124,7 @@ class sense_amp_array(design.design): if not self.offsets: self.offsets = [] for i in range(self.num_cols + self.num_spare_cols): - self.offsets.append(i * precharge_width) + self.offsets.append(i * self.amp_spacing) for i, xoffset in enumerate(self.offsets[0:self.num_cols:self.words_per_row]): if self.bitcell.mirror.y and (i * self.words_per_row + self.column_offset) % 2: @@ -140,7 +140,7 @@ class sense_amp_array(design.design): index = self.word_size + i if self.bitcell.mirror.y and (index + self.column_offset) % 2: mirror = "MY" - xoffset = xoffset + self.amp_width + xoffset = xoffset + self.amp_spacing else: mirror = "" From e5662180e8126ed48108146329eb8b078ab943ba Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Fri, 7 May 2021 18:44:45 -0700 Subject: [PATCH 16/34] single port 20 series tests running --- compiler/sram/sram_base.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 7621f67b..ca9223e1 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -40,7 +40,7 @@ class sram_base(design, verilog, lef): if not self.num_spare_cols: self.num_spare_cols = 0 - def add_pins(self): + def add_pins(self): """ Add pins for entire SRAM. """ for port in self.write_ports: @@ -427,6 +427,12 @@ class sram_base(design, verilog, lef): self.bitcell = factory.create(module_type=OPTS.bitcell) self.dff = factory.create(module_type="dff") + # Create the bank module (up to four are instantiated) + self.bank = factory.create("bank", sram_config=self.sram_config, module_name="bank") + self.add_mod(self.bank) + + self.num_spare_cols = self.bank.num_spare_cols + # Create the address and control flops (but not the clk) self.row_addr_dff = factory.create("dff_array", module_name="row_addr_dff", rows=self.row_addr_size, columns=1) self.add_mod(self.row_addr_dff) @@ -448,10 +454,6 @@ class sram_base(design, verilog, lef): self.spare_wen_dff = factory.create("dff_array", module_name="spare_wen_dff", rows=1, columns=self.num_spare_cols) self.add_mod(self.spare_wen_dff) - # Create the bank module (up to four are instantiated) - self.bank = factory.create("bank", sram_config=self.sram_config, module_name="bank") - self.add_mod(self.bank) - # Create bank decoder if(self.num_banks > 1): self.add_multi_bank_modules() From f9eae3fb809d4a00ed2fb54b0a5a3105ffceddb2 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Mon, 24 May 2021 02:42:04 -0700 Subject: [PATCH 17/34] route bias pisn --- compiler/base/hierarchy_layout.py | 16 ++++++++++------ compiler/modules/bank.py | 8 +++++++- compiler/router/pin_group.py | 1 + compiler/verify/magic.py | 2 +- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 1e2add8d..d72e3be3 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -1203,22 +1203,24 @@ class layout(): height=ymax - ymin) return rect - def copy_power_pins(self, inst, name, add_vias=True): + def copy_power_pins(self, inst, name, add_vias=True, new_name=""): """ This will copy a power pin if it is on the lowest power_grid layer. If it is on M1, it will add a power via too. """ pins = inst.get_pins(name) for pin in pins: + if new_name == "": + new_name = pin.name if pin.layer == self.pwr_grid_layer: - self.add_layout_pin(name, + self.add_layout_pin(new_name, pin.layer, pin.ll(), pin.width(), pin.height()) elif add_vias: - self.copy_power_pin(pin) + self.copy_power_pin(pin, new_name=new_name) def add_io_pin(self, instance, pin_name, new_name, start_layer=None): """ @@ -1264,13 +1266,15 @@ class layout(): width=width, height=height) - def copy_power_pin(self, pin, loc=None, directions=None): + def copy_power_pin(self, pin, loc=None, directions=None, new_name=""): """ Add a single power pin from the lowest power_grid layer down to M1 (or li) at the given center location. The starting layer is specified to determine which vias are needed. """ + if new_name == "": + new_name = pin.name if not loc: loc = pin.center() @@ -1284,7 +1288,7 @@ class layout(): height = None if pin.layer == self.pwr_grid_layer: - self.add_layout_pin_rect_center(text=pin.name, + self.add_layout_pin_rect_center(text=new_name, layer=self.pwr_grid_layer, offset=loc, width=width, @@ -1299,7 +1303,7 @@ class layout(): width = via.width if not height: height = via.height - self.add_layout_pin_rect_center(text=pin.name, + self.add_layout_pin_rect_center(text=new_name, layer=self.pwr_grid_layer, offset=loc, width=width, diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 56cd854c..b0e09915 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -439,6 +439,9 @@ class bank(design.design): temp.append("vdd") temp.append("gnd") + if 'vpb' in self.bitcell_array_inst.mod.pins and 'vnb' in self.bitcell_array_inst.mod.pins: + temp.append('vpb') + temp.append('vnb') self.connect_inst(temp) def place_bitcell_array(self, offset): @@ -622,6 +625,10 @@ class bank(design.design): self.copy_power_pins(inst, "vdd", add_vias=False) self.copy_power_pins(inst, "gnd", add_vias=False) + #if 'vpb' in self.bitcell_array_inst.mod.pins and 'vnb' in self.bitcell_array_inst.mod.pins: + # for pin_name, supply_name in zip(['vpb','vnb'],['vdd','gnd']): + # self.copy_power_pins(self.bitcell_array_inst, pin_name, new_name=supply_name) + # If we use the pinvbuf as the decoder, we need to add power pins. # Other decoders already have them. if self.col_addr_size == 1: @@ -1070,7 +1077,6 @@ class bank(design.design): to_layer="m2", offset=control_pos) - def graph_exclude_precharge(self): """ Precharge adds a loop between bitlines, can be excluded to reduce complexity diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 5e6d6f89..4e511511 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -149,6 +149,7 @@ class pin_group: pin_list.append(enclosure) if len(pin_list) == 0: + breakpoint() debug.error("Did not find any enclosures for {}".format(self.name)) self.router.write_debug_gds("pin_enclosure_error.gds") diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 3983de7c..819bec1f 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -86,7 +86,7 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1])) # Do not run DRC for extraction/conversion f.write("drc off\n") - f.write("gds polygon subcell true\n") + # f.write("gds polygon subcell true\n") f.write("gds warning default\n") # These two options are temporarily disabled until Tim fixes a bug in magic related # to flattening channel routes and vias (hierarchy with no devices in it). Otherwise, From f6587badadaed83aff9631d17b1b86b019ec054c Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 28 May 2021 10:58:30 -0700 Subject: [PATCH 18/34] Improve supply routing for ring and side pins --- compiler/base/hierarchy_layout.py | 54 ++++++++++++++++++- compiler/base/lef.py | 14 ++--- compiler/base/pin_layout.py | 4 +- .../example_configs/sky130_sram_common.py | 4 +- compiler/router/grid.py | 40 +++++++++----- compiler/router/router.py | 54 +++++++------------ compiler/router/supply_tree_router.py | 2 +- compiler/sram/sram_1bank.py | 12 ++++- compiler/sram/sram_base.py | 17 +++--- 9 files changed, 134 insertions(+), 67 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index e603bdc3..839c9a4b 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -41,7 +41,8 @@ class layout(): self.width = None self.height = None - self.bounding_box = None + self.bounding_box = None # The rectangle shape + self.bbox = None # The ll, ur coords # Holds module/cell layout instances self.insts = [] # Set of names to check for duplicates @@ -1163,6 +1164,57 @@ class layout(): self.bbox = [self.bounding_box.ll(), self.bounding_box.ur()] + def get_bbox(self, side="all", big_margin=0, little_margin=0): + """ + Get the bounding box from the GDS + """ + gds_filename = OPTS.openram_temp + "temp.gds" + # If didn't specify a gds blockage file, write it out to read the gds + # This isn't efficient, but easy for now + # Load the gds file and read in all the shapes + self.gds_write(gds_filename) + layout = gdsMill.VlsiLayout(units=GDS["unit"]) + reader = gdsMill.Gds2reader(layout) + reader.loadFromFile(gds_filename) + top_name = layout.rootStructureName + + if not self.bbox: + # The boundary will determine the limits to the size + # of the routing grid + boundary = layout.measureBoundary(top_name) + # These must be un-indexed to get rid of the matrix type + ll = vector(boundary[0][0], boundary[0][1]) + ur = vector(boundary[1][0], boundary[1][1]) + else: + ll, ur = self.bbox + + ll_offset = vector(0, 0) + ur_offset = vector(0, 0) + if side in ["ring", "top"]: + ur_offset += vector(0, big_margin) + else: + ur_offset += vector(0, little_margin) + if side in ["ring", "bottom"]: + ll_offset += vector(0, big_margin) + else: + ll_offset += vector(0, little_margin) + if side in ["ring", "left"]: + ll_offset += vector(big_margin, 0) + else: + ll_offset += vector(little_margin, 0) + if side in ["ring", "right"]: + ur_offset += vector(big_margin, 0) + else: + ur_offset += vector(little_margin, 0) + bbox = (ll - ll_offset, ur + ur_offset) + size = ur - ll + debug.info(1, "Size: {0} x {1} with perimeter big margin {2} little margin {3}".format(size.x, + size.y, + big_margin, + little_margin)) + + return bbox + def add_enclosure(self, insts, layer="nwell", extend=0, leftx=None, rightx=None, topy=None, boty=None): """ Add a layer that surrounds the given instances. Useful diff --git a/compiler/base/lef.py b/compiler/base/lef.py index ce1eef1c..1d86a63e 100644 --- a/compiler/base/lef.py +++ b/compiler/base/lef.py @@ -112,23 +112,25 @@ class lef: for pin_name in self.pins: pins = self.get_pins(pin_name) for pin in pins: - inflated_pin = pin.inflated_pin(multiple=1) - another_iteration_needed = True - while another_iteration_needed: - another_iteration_needed = False + inflated_pin = pin.inflated_pin(multiple=2) + continue_fragmenting = True + while continue_fragmenting: + continue_fragmenting = False old_blockages = list(self.blockages[pin.layer]) for blockage in old_blockages: if blockage.overlaps(inflated_pin): intersection_shape = blockage.intersection(inflated_pin) - # If it is zero area, don't add the pin + # If it is zero area, don't split the blockage if intersection_shape[0][0]==intersection_shape[1][0] or intersection_shape[0][1]==intersection_shape[1][1]: continue - another_iteration_needed = True + # Remove the old blockage and add the new ones self.blockages[pin.layer].remove(blockage) intersection_pin = pin_layout("", intersection_shape, inflated_pin.layer) new_blockages = blockage.cut(intersection_pin) self.blockages[pin.layer].extend(new_blockages) + # We split something so make another pass + continue_fragmenting = True def lef_write_header(self): """ Header of LEF file """ diff --git a/compiler/base/pin_layout.py b/compiler/base/pin_layout.py index e6baa4fc..f27990f5 100644 --- a/compiler/base/pin_layout.py +++ b/compiler/base/pin_layout.py @@ -606,7 +606,9 @@ class pin_layout: # Don't add the existing shape in if it overlaps the pin shape if new_shape.contains(shape): continue - new_shapes.append(new_shape) + # Only add non-zero shapes + if new_shape.area() > 0: + new_shapes.append(new_shape) return new_shapes diff --git a/compiler/example_configs/sky130_sram_common.py b/compiler/example_configs/sky130_sram_common.py index 8efc8f10..a827b5a9 100644 --- a/compiler/example_configs/sky130_sram_common.py +++ b/compiler/example_configs/sky130_sram_common.py @@ -9,8 +9,8 @@ nominal_corner_only = True # Local wordlines have issues with met3 power routing for now #local_array_size = 16 -#route_supplies = "ring" -route_supplies = "left" +route_supplies = "ring" +#route_supplies = "left" check_lvsdrc = True #perimeter_pins = False #netlist_only = True diff --git a/compiler/router/grid.py b/compiler/router/grid.py index 404a716f..843fb3ed 100644 --- a/compiler/router/grid.py +++ b/compiler/router/grid.py @@ -37,6 +37,8 @@ class grid: # This is really lower left bottom layer and upper right top layer in 3D. self.ll = vector3d(ll.x, ll.y, 0).scale(self.track_factor).round() self.ur = vector3d(ur.x, ur.y, 0).scale(self.track_factor).round() + debug.info(1, "BBOX coords: ll=" + str(ll) + " ur=" + str(ur)) + debug.info(1, "BBOX grids: ll=" + str(self.ll) + " ur=" + str(self.ur)) # let's leave the map sparse, cells are created on demand to reduce memory self.map={} @@ -127,33 +129,47 @@ class grid: Side specifies which side. Layer specifies horizontal (0) or vertical (1) Width specifies how wide the perimter "stripe" should be. + Works from the inside out from the bbox (ll, ur) """ + if "ring" in side: + ring_width = width + else: + ring_width = 0 + + if "ring" in side: + ring_offset = offset + else: + ring_offset = 0 + perimeter_list = [] # Add the left/right columns - if side=="all" or side=="left": - for x in range(self.ll.x + offset, self.ll.x + width + offset, 1): - for y in range(self.ll.y + offset + margin, self.ur.y - offset - margin, 1): + if side=="all" or "left" in side: + for x in range(self.ll.x - offset, self.ll.x - width - offset, -1): + for y in range(self.ll.y - ring_offset - margin - ring_width + 1, self.ur.y + ring_offset + margin + ring_width, 1): for layer in layers: perimeter_list.append(vector3d(x, y, layer)) - if side=="all" or side=="right": - for x in range(self.ur.x - width - offset, self.ur.x - offset, 1): - for y in range(self.ll.y + offset + margin, self.ur.y - offset - margin, 1): + if side=="all" or "right" in side: + for x in range(self.ur.x + offset, self.ur.x + width + offset, 1): + for y in range(self.ll.y - ring_offset - margin - ring_width + 1, self.ur.y + ring_offset + margin + ring_width, 1): for layer in layers: perimeter_list.append(vector3d(x, y, layer)) - if side=="all" or side=="bottom": - for y in range(self.ll.y + offset, self.ll.y + width + offset, 1): - for x in range(self.ll.x + offset + margin, self.ur.x - offset - margin, 1): + if side=="all" or "bottom" in side: + for y in range(self.ll.y - offset, self.ll.y - width - offset, -1): + for x in range(self.ll.x - ring_offset - margin - ring_width + 1, self.ur.x + ring_offset + margin + ring_width, 1): for layer in layers: perimeter_list.append(vector3d(x, y, layer)) - if side=="all" or side=="top": - for y in range(self.ur.y - width - offset, self.ur.y - offset, 1): - for x in range(self.ll.x + offset + margin, self.ur.x - offset - margin, 1): + if side=="all" or "top" in side: + for y in range(self.ur.y + offset, self.ur.y + width + offset, 1): + for x in range(self.ll.x - ring_offset - margin - ring_width + 1, self.ur.x + ring_offset + margin + ring_width, 1): for layer in layers: perimeter_list.append(vector3d(x, y, layer)) + # Add them all to the map + self.add_map(perimeter_list) + return perimeter_list def add_perimeter_target(self, side="all", layers=[0, 1]): diff --git a/compiler/router/router.py b/compiler/router/router.py index dcfde6cf..d9903e49 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -82,31 +82,13 @@ class router(router_tech): """ Initialize the ll,ur values with the paramter or using the layout boundary. """ - - # If didn't specify a gds blockage file, write it out to read the gds - # This isn't efficient, but easy for now - # Load the gds file and read in all the shapes - self.cell.gds_write(self.gds_filename) - self.layout = gdsMill.VlsiLayout(units=GDS["unit"]) - self.reader = gdsMill.Gds2reader(self.layout) - self.reader.loadFromFile(self.gds_filename) - self.top_name = self.layout.rootStructureName - if not bbox: - # The boundary will determine the limits to the size - # of the routing grid - self.boundary = self.layout.measureBoundary(self.top_name) - # These must be un-indexed to get rid of the matrix type - self.ll = vector(self.boundary[0][0], self.boundary[0][1]) - self.ur = vector(self.boundary[1][0], self.boundary[1][1]) + self.bbox = self.cell.get_bbox(margin) else: - self.ll, self.ur = bbox + self.bbox = bbox + + (self.ll, self.ur) = self.bbox - margin_offset = vector(margin, margin) - self.bbox = (self.ll - margin_offset, self.ur + margin_offset) - size = self.ur - self.ll - debug.info(1, "Size: {0} x {1} with perimeter margin {2}".format(size.x, size.y, margin)) - def get_bbox(self): return self.bbox @@ -893,19 +875,21 @@ class router(router_tech): # Clearing the blockage of this pin requires the inflated pins self.clear_blockages(pin_name) - def add_side_supply_pin(self, name, side="left", width=2): + def add_side_supply_pin(self, name, side="left", width=3, space=2): """ Adds a supply pin to the perimeter and resizes the bounding box. """ pg = pin_group(name, [], self) - if name == "gnd": - offset = width + 1 + # Offset two spaces inside and one between the rings + if name == "vdd": + offset = width + 2 * space else: - offset = 1 + offset = space if side in ["left", "right"]: layers = [1] else: layers = [0] + pg.grids = set(self.rg.get_perimeter_list(side=side, width=width, margin=self.margin, @@ -920,39 +904,39 @@ class router(router_tech): self.new_pins[name] = pg.pins - def add_ring_supply_pin(self, name, width=2): + def add_ring_supply_pin(self, name, width=3, space=2): """ Adds a ring supply pin that goes inside the given bbox. """ pg = pin_group(name, [], self) - # Offset the vdd inside one ring width + # Offset two spaces inside and one between the rings # Units are in routing grids - if name == "gnd": - offset = width + 1 + if name == "vdd": + offset = width + 2 * space else: - offset = 1 + offset = space # LEFT - left_grids = set(self.rg.get_perimeter_list(side="left", + left_grids = set(self.rg.get_perimeter_list(side="left_ring", width=width, margin=self.margin, offset=offset, layers=[1])) # RIGHT - right_grids = set(self.rg.get_perimeter_list(side="right", + right_grids = set(self.rg.get_perimeter_list(side="right_ring", width=width, margin=self.margin, offset=offset, layers=[1])) # TOP - top_grids = set(self.rg.get_perimeter_list(side="top", + top_grids = set(self.rg.get_perimeter_list(side="top_ring", width=width, margin=self.margin, offset=offset, layers=[0])) # BOTTOM - bottom_grids = set(self.rg.get_perimeter_list(side="bottom", + bottom_grids = set(self.rg.get_perimeter_list(side="bottom_ring", width=width, margin=self.margin, offset=offset, diff --git a/compiler/router/supply_tree_router.py b/compiler/router/supply_tree_router.py index e95cdee1..282adc4c 100644 --- a/compiler/router/supply_tree_router.py +++ b/compiler/router/supply_tree_router.py @@ -34,7 +34,7 @@ class supply_tree_router(router): # The pin escape router already made the bounding box big enough, # so we can use the regular bbox here. if pin_type: - debug.check(pin_type in ["left", "right", "top", "bottom", "tree", "ring"], + debug.check(pin_type in ["left", "right", "top", "bottom", "single", "ring"], "Invalid pin type {}".format(pin_type)) self.pin_type = pin_type router.__init__(self, diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 327ce209..3bfe3648 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -329,13 +329,21 @@ class sram_1bank(sram_base): # Some technologies have an isolation self.add_dnwell(inflate=2) + # We need the initial bbox for the supply rings later + # because the perimeter pins will change the bbox # Route the pins to the perimeter + pre_bbox = None if OPTS.perimeter_pins: - self.route_escape_pins() + pre_bbox = self.get_bbox(side="ring", + big_margin=self.m3_pitch) + bbox = self.get_bbox(side=OPTS.route_supplies, + big_margin=14 * self.m3_pitch, + little_margin=4 * self.m3_pitch) + self.route_escape_pins(bbox) # Route the supplies first since the MST is not blockage aware # and signals can route to anywhere on sides (it is flexible) - self.route_supplies() + self.route_supplies(pre_bbox) def route_dffs(self, add_routes=True): diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index a7530e0b..5163ef27 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -230,7 +230,7 @@ class sram_base(design, verilog, lef): def create_modules(self): debug.error("Must override pure virtual function.", -1) - def route_supplies(self): + def route_supplies(self, bbox=None): """ Route the supply grid and connect the pins to them. """ # Copy the pins to the top level @@ -252,11 +252,14 @@ class sram_base(design, verilog, lef): return elif OPTS.route_supplies == "grid": from supply_grid_router import supply_grid_router as router - rtr=router(grid_stack, self) + rtr=router(layers=grid_stack, + design=self, + bbox=bbox) else: from supply_tree_router import supply_tree_router as router - rtr=router(grid_stack, - self, + rtr=router(layers=grid_stack, + design=self, + bbox=bbox, pin_type=OPTS.route_supplies) rtr.route() @@ -283,7 +286,7 @@ class sram_base(design, verilog, lef): pin.width(), pin.height()) - elif OPTS.route_supplies: + elif OPTS.route_supplies or OPTS.route_supplies == "single": # Update these as we may have routed outside the region (perimeter pins) lowest_coord = self.find_lowest_coords() @@ -321,7 +324,7 @@ class sram_base(design, verilog, lef): # Grid is left with many top level pins pass - def route_escape_pins(self): + def route_escape_pins(self, bbox): """ Add the top-level pins for a single bank SRAM with control. """ @@ -364,7 +367,7 @@ class sram_base(design, verilog, lef): from signal_escape_router import signal_escape_router as router rtr=router(layers=self.m3_stack, design=self, - margin=8 * self.m3_pitch) + bbox=bbox) rtr.escape_route(pins_to_route) def compute_bus_sizes(self): From 013c5932a07782e7194bdec476cf4e41c14a294e Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 28 May 2021 11:26:41 -0700 Subject: [PATCH 19/34] Valid type is tree not single --- compiler/router/supply_tree_router.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/router/supply_tree_router.py b/compiler/router/supply_tree_router.py index 282adc4c..e95cdee1 100644 --- a/compiler/router/supply_tree_router.py +++ b/compiler/router/supply_tree_router.py @@ -34,7 +34,7 @@ class supply_tree_router(router): # The pin escape router already made the bounding box big enough, # so we can use the regular bbox here. if pin_type: - debug.check(pin_type in ["left", "right", "top", "bottom", "single", "ring"], + debug.check(pin_type in ["left", "right", "top", "bottom", "tree", "ring"], "Invalid pin type {}".format(pin_type)) self.pin_type = pin_type router.__init__(self, From 77f221d8591fa772122f947139c76690f8f44ade Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 28 May 2021 11:55:50 -0700 Subject: [PATCH 20/34] Separate supply pin type from route supplies option --- compiler/base/hierarchy_layout.py | 8 +++---- compiler/options.py | 1 + compiler/router/supply_grid_router.py | 2 +- compiler/router/supply_tree_router.py | 3 ++- compiler/sram/sram_1bank.py | 19 ++++++++++++---- compiler/sram/sram_base.py | 31 ++++++++++++--------------- 6 files changed, 37 insertions(+), 27 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 839c9a4b..e033e387 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -1190,19 +1190,19 @@ class layout(): ll_offset = vector(0, 0) ur_offset = vector(0, 0) - if side in ["ring", "top"]: + if side in ["ring", "top", "all"]: ur_offset += vector(0, big_margin) else: ur_offset += vector(0, little_margin) - if side in ["ring", "bottom"]: + if side in ["ring", "bottom", "all"]: ll_offset += vector(0, big_margin) else: ll_offset += vector(0, little_margin) - if side in ["ring", "left"]: + if side in ["ring", "left", "all"]: ll_offset += vector(big_margin, 0) else: ll_offset += vector(little_margin, 0) - if side in ["ring", "right"]: + if side in ["ring", "right", "all"]: ur_offset += vector(big_margin, 0) else: ur_offset += vector(little_margin, 0) diff --git a/compiler/options.py b/compiler/options.py index 214eecf7..65620c8c 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -99,6 +99,7 @@ class options(optparse.Values): netlist_only = False # Whether we should do the final power routing route_supplies = "tree" + supply_pin_type = "ring" # This determines whether LVS and DRC is checked at all. check_lvsdrc = False # This determines whether LVS and DRC is checked for every submodule. diff --git a/compiler/router/supply_grid_router.py b/compiler/router/supply_grid_router.py index f24498ab..06831299 100644 --- a/compiler/router/supply_grid_router.py +++ b/compiler/router/supply_grid_router.py @@ -21,7 +21,7 @@ class supply_grid_router(router): routes a grid to connect the supply on the two layers. """ - def __init__(self, layers, design, margin=0, bbox=None): + def __init__(self, layers, design, bbox=None, pin_type=None): """ This will route on layers in design. It will get the blockages from either the gds file name or the design itself (by saving to a gds file). diff --git a/compiler/router/supply_tree_router.py b/compiler/router/supply_tree_router.py index e95cdee1..8ed0c596 100644 --- a/compiler/router/supply_tree_router.py +++ b/compiler/router/supply_tree_router.py @@ -34,7 +34,7 @@ class supply_tree_router(router): # The pin escape router already made the bounding box big enough, # so we can use the regular bbox here. if pin_type: - debug.check(pin_type in ["left", "right", "top", "bottom", "tree", "ring"], + debug.check(pin_type in ["left", "right", "top", "bottom", "single", "ring"], "Invalid pin type {}".format(pin_type)) self.pin_type = pin_type router.__init__(self, @@ -75,6 +75,7 @@ class supply_tree_router(router): self.add_ring_supply_pin(self.vdd_name) self.add_ring_supply_pin(self.gnd_name) + self.write_debug_gds("foo.gds", False) # Route the supply pins to the supply rails # Route vdd first since we want it to be shorter start_time = datetime.now() diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 3bfe3648..9c3802be 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -9,6 +9,7 @@ from vector import vector from sram_base import sram_base from contact import m2_via from channel_route import channel_route +from router_tech import router_tech from globals import OPTS @@ -334,11 +335,21 @@ class sram_1bank(sram_base): # Route the pins to the perimeter pre_bbox = None if OPTS.perimeter_pins: + rt = router_tech(self.supply_stack, 1) + + if OPTS.supply_pin_type in ["ring", "left", "right", "top", "bottom"]: + big_margin = 12 * rt.track_width + little_margin = 2 * rt.track_width + else: + big_margin = 6 * rt.track_width + little_margin = 0 + pre_bbox = self.get_bbox(side="ring", - big_margin=self.m3_pitch) - bbox = self.get_bbox(side=OPTS.route_supplies, - big_margin=14 * self.m3_pitch, - little_margin=4 * self.m3_pitch) + big_margin=rt.track_width) + + bbox = self.get_bbox(side=OPTS.supply_pin_type, + big_margin=big_margin, + little_margin=little_margin) self.route_escape_pins(bbox) # Route the supplies first since the MST is not blockage aware diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 5163ef27..98a8b456 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -41,6 +41,14 @@ class sram_base(design, verilog, lef): if not self.num_spare_cols: self.num_spare_cols = 0 + try: + from tech import power_grid + self.supply_stack = power_grid + except ImportError: + # if no power_grid is specified by tech we use sensible defaults + # Route a M3/M4 grid + self.supply_stack = self.m3_stack + def add_pins(self): """ Add pins for entire SRAM. """ @@ -239,32 +247,21 @@ class sram_base(design, verilog, lef): for inst in self.insts: self.copy_power_pins(inst, pin_name, self.ext_supply[pin_name]) - try: - from tech import power_grid - grid_stack = power_grid - except ImportError: - # if no power_grid is specified by tech we use sensible defaults - # Route a M3/M4 grid - grid_stack = self.m3_stack - if not OPTS.route_supplies: # Do not route the power supply (leave as must-connect pins) return elif OPTS.route_supplies == "grid": from supply_grid_router import supply_grid_router as router - rtr=router(layers=grid_stack, - design=self, - bbox=bbox) else: from supply_tree_router import supply_tree_router as router - rtr=router(layers=grid_stack, - design=self, - bbox=bbox, - pin_type=OPTS.route_supplies) + rtr=router(layers=self.supply_stack, + design=self, + bbox=bbox, + pin_type=OPTS.supply_pin_type) rtr.route() - if OPTS.route_supplies in ["left", "right", "top", "bottom", "ring"]: + if OPTS.supply_pin_type in ["left", "right", "top", "bottom", "ring"]: # Find the lowest leftest pin for vdd and gnd for pin_name in ["vdd", "gnd"]: # Copy the pin shape(s) to rectangles @@ -286,7 +283,7 @@ class sram_base(design, verilog, lef): pin.width(), pin.height()) - elif OPTS.route_supplies or OPTS.route_supplies == "single": + elif OPTS.route_supplies and OPTS.supply_pin_type == "single": # Update these as we may have routed outside the region (perimeter pins) lowest_coord = self.find_lowest_coords() From d6d0df97f87bc903f48211dba95b6051931f6beb Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 28 May 2021 13:06:12 -0700 Subject: [PATCH 21/34] Get rid of write_size error when write_size==word_size --- compiler/globals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/globals.py b/compiler/globals.py index 1b272b98..35a27ed9 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -607,7 +607,7 @@ def report_status(): # If a write mask is specified by the user, the mask write size should be the same as # the word size so that an entire word is written at once. - if OPTS.write_size is not None: + if OPTS.write_size is not None and OPTS.write_size != OPTS.word_size: if (OPTS.word_size % OPTS.write_size != 0): debug.error("Write size needs to be an integer multiple of word size.") # If write size is more than half of the word size, From 9e8d39f911fd9e1c709859ad85928ac9568655f1 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 28 May 2021 13:31:19 -0700 Subject: [PATCH 22/34] Remove debug gds dump --- compiler/router/supply_tree_router.py | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/router/supply_tree_router.py b/compiler/router/supply_tree_router.py index 8ed0c596..282adc4c 100644 --- a/compiler/router/supply_tree_router.py +++ b/compiler/router/supply_tree_router.py @@ -75,7 +75,6 @@ class supply_tree_router(router): self.add_ring_supply_pin(self.vdd_name) self.add_ring_supply_pin(self.gnd_name) - self.write_debug_gds("foo.gds", False) # Route the supply pins to the supply rails # Route vdd first since we want it to be shorter start_time = datetime.now() From 1a894a99dd0d8216c9dce56908eddfdddc665289 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Fri, 28 May 2021 13:41:58 -0700 Subject: [PATCH 23/34] push bias pins to top level power routing --- compiler/modules/bank.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index b0e09915..d46dfe31 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -625,9 +625,9 @@ class bank(design.design): self.copy_power_pins(inst, "vdd", add_vias=False) self.copy_power_pins(inst, "gnd", add_vias=False) - #if 'vpb' in self.bitcell_array_inst.mod.pins and 'vnb' in self.bitcell_array_inst.mod.pins: - # for pin_name, supply_name in zip(['vpb','vnb'],['vdd','gnd']): - # self.copy_power_pins(self.bitcell_array_inst, pin_name, new_name=supply_name) + if 'vpb' in self.bitcell_array_inst.mod.pins and 'vnb' in self.bitcell_array_inst.mod.pins: + for pin_name, supply_name in zip(['vpb','vnb'],['vdd','gnd']): + self.copy_power_pins(self.bitcell_array_inst, pin_name, new_name=supply_name) # If we use the pinvbuf as the decoder, we need to add power pins. # Other decoders already have them. From e944a5ec02131227e3b639073b926f571021f224 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 28 May 2021 16:39:48 -0700 Subject: [PATCH 24/34] Use open_pdks setup.tcl if available. Set vdd/gnd/sub in run_ext.sh --- compiler/verify/magic.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index e4f0b428..32a9f7e6 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -89,6 +89,9 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1])) # Do not run DRC for extraction/conversion f.write("drc off\n") + f.write("set VDD vdd\n") + f.write("set GND gnd\n") + f.write("set SUB gnd\n") f.write("gds polygon subcell true\n") f.write("gds warning default\n") # These two options are temporarily disabled until Tim fixes a bug in magic related @@ -244,11 +247,14 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, out if not output_path: output_path = OPTS.openram_temp - setup_file = "setup.tcl" - full_setup_file = OPTS.openram_tech + "tech/" + setup_file - if os.path.exists(full_setup_file): + # Copy .magicrc file into the output directory + setup_file = os.environ.get('OPENRAM_NETGENRC', None) + if not setup_file: + setup_file = OPTS.openram_tech + "tech/setup.tcl" + + if os.path.exists(setup_file): # Copy setup.tcl file into temp dir - shutil.copy(full_setup_file, output_path) + shutil.copy(setup_file, output_path) else: setup_file = 'nosetup' From 97f43e31f0abdb35275063c5e620df31c6bf256d Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Sat, 29 May 2021 16:08:31 -0700 Subject: [PATCH 25/34] remove breakpoint --- compiler/router/pin_group.py | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 4e511511..5e6d6f89 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -149,7 +149,6 @@ class pin_group: pin_list.append(enclosure) if len(pin_list) == 0: - breakpoint() debug.error("Did not find any enclosures for {}".format(self.name)) self.router.write_debug_gds("pin_enclosure_error.gds") From 24b45ca2d4c18dffe6153925baa463c5b7602d9e Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Sat, 29 May 2021 16:54:36 -0700 Subject: [PATCH 26/34] use flat magic files instead of gds flatten subcell --- compiler/verify/magic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 32a9f7e6..b6c34f8a 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -92,7 +92,7 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa f.write("set VDD vdd\n") f.write("set GND gnd\n") f.write("set SUB gnd\n") - f.write("gds polygon subcell true\n") + #f.write("gds polygon subcell true\n") f.write("gds warning default\n") # These two options are temporarily disabled until Tim fixes a bug in magic related # to flattening channel routes and vias (hierarchy with no devices in it). Otherwise, From 1ded978256491b45e350e51ae25f4f3533ea8b84 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 1 Jun 2021 15:10:55 -0700 Subject: [PATCH 27/34] Change nwell from gnd to vdd. dnwell space added. --- compiler/base/hierarchy_layout.py | 10 +++++----- compiler/router/router.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index e033e387..f16658c2 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -1409,7 +1409,7 @@ class layout(): [ll, ur] = bbox # Possibly inflate the bbox - nwell_offset = vector(self.nwell_width, self.nwell_width) + nwell_offset = vector(2 * self.nwell_width, 2 * self.nwell_width) ll -= nwell_offset.scale(inflate, inflate) ur += nwell_offset.scale(inflate, inflate) @@ -1448,7 +1448,7 @@ class layout(): to_layer="m1", offset=loc) else: - self.add_power_pin(name="gnd", + self.add_power_pin(name="vdd", loc=loc, start_layer="li") count += 1 @@ -1468,7 +1468,7 @@ class layout(): to_layer="m1", offset=loc) else: - self.add_power_pin(name="gnd", + self.add_power_pin(name="vdd", loc=loc, start_layer="li") count += 1 @@ -1488,7 +1488,7 @@ class layout(): to_layer="m2", offset=loc) else: - self.add_power_pin(name="gnd", + self.add_power_pin(name="vdd", loc=loc, start_layer="li") count += 1 @@ -1508,7 +1508,7 @@ class layout(): to_layer="m2", offset=loc) else: - self.add_power_pin(name="gnd", + self.add_power_pin(name="vdd", loc=loc, start_layer="li") count += 1 diff --git a/compiler/router/router.py b/compiler/router/router.py index d9903e49..d5bd4738 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -881,7 +881,7 @@ class router(router_tech): """ pg = pin_group(name, [], self) # Offset two spaces inside and one between the rings - if name == "vdd": + if name == "gnd": offset = width + 2 * space else: offset = space @@ -911,7 +911,7 @@ class router(router_tech): pg = pin_group(name, [], self) # Offset two spaces inside and one between the rings # Units are in routing grids - if name == "vdd": + if name == "gnd": offset = width + 2 * space else: offset = space From 537fd6eff9dc0f1980dfebf442d59f1ab8664023 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 1 Jun 2021 16:41:14 -0700 Subject: [PATCH 28/34] Use None instead of empty string for tool names. --- compiler/characterizer/__init__.py | 4 ++-- compiler/characterizer/stimuli.py | 4 ++-- compiler/options.py | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/characterizer/__init__.py b/compiler/characterizer/__init__.py index a092ac1e..1b6ef642 100644 --- a/compiler/characterizer/__init__.py +++ b/compiler/characterizer/__init__.py @@ -24,7 +24,7 @@ debug.info(1, "Initializing characterizer...") OPTS.spice_exe = "" if not OPTS.analytical_delay: - if OPTS.spice_name != "": + if OPTS.spice_name: # Capitalize Xyce if OPTS.spice_name == "xyce": OPTS.spice_name = "Xyce" @@ -45,7 +45,7 @@ if not OPTS.analytical_delay: if OPTS.spice_name == "ngspice": os.environ["NGSPICE_INPUT_DIR"] = "{0}".format(OPTS.openram_temp) - if OPTS.spice_exe == "": + if not OPTS.spice_exe: debug.error("No recognizable spice version found. Unable to perform characterization.", 1) else: debug.info(1, "Finding spice simulator: {} ({})".format(OPTS.spice_name, OPTS.spice_exe)) diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index f5b5967f..80ddf4fc 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -276,8 +276,8 @@ class stimuli(): self.sf.write(".OPTIONS MEASURE MEASFAIL=1\n") self.sf.write(".OPTIONS LINSOL type=klu\n") self.sf.write(".TRAN {0}p {1}n\n".format(timestep, end_time)) - else: - debug.error("Unkown spice simulator {}".format(OPTS.spice_name)) + elif OPTS.spice_name: + debug.error("Unkown spice simulator {}".format(OPTS.spice_name), -1) # create plots for all signals if not OPTS.use_pex: # Don't save all for extracted simulations diff --git a/compiler/options.py b/compiler/options.py index 65620c8c..87a30531 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -120,13 +120,13 @@ class options(optparse.Values): # Tool options ################### # Variable to select the variant of spice - spice_name = "" + spice_name = None # The spice executable being used which is derived from the user PATH. - spice_exe = "" + spice_exe = None # Variable to select the variant of drc, lvs, pex - drc_name = "" - lvs_name = "" - pex_name = "" + drc_name = None + lvs_name = None + pex_name = None # The DRC/LVS/PEX executable being used # which is derived from the user PATH. drc_exe = None From 4107c983e2d421b84c0f4c25911f8890b9b01118 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 4 Jun 2021 07:14:49 -0700 Subject: [PATCH 29/34] Make sure channel route is below s_en --- compiler/sram/sram_1bank.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 9c3802be..0323ffdf 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -385,6 +385,7 @@ class sram_1bank(sram_base): if len(route_map) > 0: + # This layer stack must be different than the data dff layer stack layer_stack = self.m1_stack if port == 0: @@ -394,11 +395,11 @@ class sram_1bank(sram_base): offset=offset, layer_stack=layer_stack, parent=self) - # This causes problem in magic since it sometimes cannot extract connectivity of isntances + # This causes problem in magic since it sometimes cannot extract connectivity of instances # with no active devices. self.add_inst(cr.name, cr) self.connect_inst([]) - #self.add_flat_inst(cr.name, cr) + # self.add_flat_inst(cr.name, cr) else: offset = vector(0, self.bank.height + self.m3_pitch) @@ -406,11 +407,11 @@ class sram_1bank(sram_base): offset=offset, layer_stack=layer_stack, parent=self) - # This causes problem in magic since it sometimes cannot extract connectivity of isntances + # This causes problem in magic since it sometimes cannot extract connectivity of instances # with no active devices. self.add_inst(cr.name, cr) self.connect_inst([]) - #self.add_flat_inst(cr.name, cr) + # self.add_flat_inst(cr.name, cr) def route_data_dffs(self, port, add_routes): route_map = [] @@ -441,40 +442,42 @@ class sram_1bank(sram_base): if len(route_map) > 0: - # The write masks will have blockages on M1 - # if self.num_wmasks > 0 and port in self.write_ports: - # layer_stack = self.m3_stack - # else: - # layer_stack = self.m1_stack + # This layer stack must be different than the column addr dff layer stack layer_stack = self.m3_stack if port == 0: + # This is relative to the bank at 0,0 or the s_en which is routed on M3 also + s_en_bot = self.control_logic_insts[port].get_pin("s_en").by() + y_offset = min(0, s_en_bot) - self.data_bus_size[port] + 2 * self.m3_pitch + offset = vector(self.control_logic_insts[port].rx() + self.dff.width, - - self.data_bus_size[port] + 2 * self.m3_pitch) + y_offset) cr = channel_route(netlist=route_map, offset=offset, layer_stack=layer_stack, parent=self) if add_routes: - # This causes problem in magic since it sometimes cannot extract connectivity of isntances + # This causes problem in magic since it sometimes cannot extract connectivity of instances # with no active devices. self.add_inst(cr.name, cr) self.connect_inst([]) - #self.add_flat_inst(cr.name, cr) + # self.add_flat_inst(cr.name, cr) else: self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap else: + s_en_top = self.control_logic_insts[port].get_pin("s_en").uy() + y_offset = max(self.bank.height, s_en_top) + self.m3_pitch offset = vector(0, - self.bank.height + self.m3_pitch) + y_offset) cr = channel_route(netlist=route_map, offset=offset, layer_stack=layer_stack, parent=self) if add_routes: - # This causes problem in magic since it sometimes cannot extract connectivity of isntances + # This causes problem in magic since it sometimes cannot extract connectivity of instances # with no active devices. self.add_inst(cr.name, cr) self.connect_inst([]) - #self.add_flat_inst(cr.name, cr) + # self.add_flat_inst(cr.name, cr) else: self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap From cc4c6e909b3f406114ada5098aad793b1673da9b Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 4 Jun 2021 07:48:26 -0700 Subject: [PATCH 30/34] Check if s_en exists before using it --- compiler/sram/sram_1bank.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 0323ffdf..828edfdd 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -446,8 +446,12 @@ class sram_1bank(sram_base): layer_stack = self.m3_stack if port == 0: # This is relative to the bank at 0,0 or the s_en which is routed on M3 also - s_en_bot = self.control_logic_insts[port].get_pin("s_en").by() - y_offset = min(0, s_en_bot) - self.data_bus_size[port] + 2 * self.m3_pitch + if "s_en" in self.control_logic_insts[port].mod.pin_map: + y_bottom = min(0, self.control_logic_insts[port].get_pin("s_en").by()) + else: + y_bottom = 0 + + y_offset = y_bottom - self.data_bus_size[port] + 2 * self.m3_pitch offset = vector(self.control_logic_insts[port].rx() + self.dff.width, y_offset) @@ -464,8 +468,11 @@ class sram_1bank(sram_base): else: self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap else: - s_en_top = self.control_logic_insts[port].get_pin("s_en").uy() - y_offset = max(self.bank.height, s_en_top) + self.m3_pitch + if "s_en" in self.control_logic_insts[port].mod.pin_map: + y_top = max(self.bank.height, self.control_logic_insts[port].get_pin("s_en").uy()) + else: + y_top = self.bank.height + y_offset = y_top + self.m3_pitch offset = vector(0, y_offset) cr = channel_route(netlist=route_map, From 53791d79c837ae1364f5dbbd3cfea776d7f71275 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 4 Jun 2021 08:56:06 -0700 Subject: [PATCH 31/34] spacing must be two extensions (one for each cell) --- compiler/modules/dff_buf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/modules/dff_buf.py b/compiler/modules/dff_buf.py index e8474fed..d979c0fe 100644 --- a/compiler/modules/dff_buf.py +++ b/compiler/modules/dff_buf.py @@ -109,7 +109,7 @@ class dff_buf(design.design): except AttributeError: pass - well_spacing += self.well_extend_active + well_spacing += 2 * self.well_extend_active self.inv1_inst.place(vector(self.dff_inst.rx() + well_spacing, 0)) From 66437593459abe2b042e7000f042ad3521c79fe8 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 4 Jun 2021 11:06:39 -0700 Subject: [PATCH 32/34] Add back drc listall with correct output. --- compiler/verify/magic.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 32a9f7e6..03051db4 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -180,7 +180,10 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa f.write('puts "Finished drc check"\n') f.write("drc catchup\n") f.write('puts "Finished drc catchup"\n') - f.write("drc count total\n") + f.write("puts -nonewline \"Total DRC errors found: \"\n") + # This is needed instead of drc count total because it displays + # some errors that are not "DRC" errors. + f.write("puts stdout [drc listall count total]\n") f.write("quit -noprompt\n") f.write("EOF\n") f.write("magic_retcode=$?\n") From 27c6a13923bb5b484aa8aca2b907588c2e202ef0 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 4 Jun 2021 15:51:50 -0700 Subject: [PATCH 33/34] Back out drc listall count for detecting errors --- compiler/verify/magic.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 3e8b2c68..454dc176 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -180,10 +180,11 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa f.write('puts "Finished drc check"\n') f.write("drc catchup\n") f.write('puts "Finished drc catchup"\n') - f.write("puts -nonewline \"Total DRC errors found: \"\n") # This is needed instead of drc count total because it displays # some errors that are not "DRC" errors. - f.write("puts stdout [drc listall count total]\n") + # f.write("puts -nonewline \"Total DRC errors found: \"\n") + # f.write("puts stdout [drc listall count total]\n") + f.write("drc count total\n") f.write("quit -noprompt\n") f.write("EOF\n") f.write("magic_retcode=$?\n") From a1cb20878d74a480fc2fc66bea2d1ac9f32f6dce Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 8 Jun 2021 11:14:27 -0700 Subject: [PATCH 34/34] Swap LH/HL hold times in sky130. --- compiler/tests/21_hspice_setuphold_test.py | 4 ++-- compiler/tests/21_ngspice_setuphold_test.py | 4 ++-- compiler/tests/21_xyce_setuphold_test.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/tests/21_hspice_setuphold_test.py b/compiler/tests/21_hspice_setuphold_test.py index 634b2982..9154502e 100755 --- a/compiler/tests/21_hspice_setuphold_test.py +++ b/compiler/tests/21_hspice_setuphold_test.py @@ -45,8 +45,8 @@ class timing_setup_test(openram_test): 'setup_times_HL': [0.16357419999999998], 'setup_times_LH': [0.1757812]} elif OPTS.tech_name == "sky130": - golden_data = {'hold_times_HL': [-0.05615234], - 'hold_times_LH': [-0.03173828], + golden_data = {'hold_times_HL': [-0.03173828], + 'hold_times_LH': [-0.05615234], 'setup_times_HL': [0.078125], 'setup_times_LH': [0.1025391]} else: diff --git a/compiler/tests/21_ngspice_setuphold_test.py b/compiler/tests/21_ngspice_setuphold_test.py index dab02e7d..9bda2c2c 100755 --- a/compiler/tests/21_ngspice_setuphold_test.py +++ b/compiler/tests/21_ngspice_setuphold_test.py @@ -45,8 +45,8 @@ class timing_setup_test(openram_test): 'setup_times_HL': [0.1757812], 'setup_times_LH': [0.1879883]} elif OPTS.tech_name == "sky130": - golden_data = {'hold_times_HL': [-0.05615234], - 'hold_times_LH': [-0.03173828], + golden_data = {'hold_times_HL': [-0.03173828], + 'hold_times_LH': [-0.05615234], 'setup_times_HL': [0.078125], 'setup_times_LH': [0.1025391]} else: diff --git a/compiler/tests/21_xyce_setuphold_test.py b/compiler/tests/21_xyce_setuphold_test.py index f53212f8..3aabce06 100755 --- a/compiler/tests/21_xyce_setuphold_test.py +++ b/compiler/tests/21_xyce_setuphold_test.py @@ -45,8 +45,8 @@ class timing_setup_test(openram_test): 'setup_times_HL': [0.16357419999999998], 'setup_times_LH': [0.1757812]} elif OPTS.tech_name == "sky130": - golden_data = {'hold_times_HL': [-0.05615234], - 'hold_times_LH': [-0.03173828], + golden_data = {'hold_times_HL': [-0.03173828], + 'hold_times_LH': [-0.05615234], 'setup_times_HL': [0.078125], 'setup_times_LH': [0.1025391]} else: