From dbe8a7f1af7ffcc90a133cf73482ad0e02e1565e Mon Sep 17 00:00:00 2001 From: jcirimel Date: Tue, 9 Feb 2021 20:51:50 -0800 Subject: [PATCH 01/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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 1a894a99dd0d8216c9dce56908eddfdddc665289 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Fri, 28 May 2021 13:41:58 -0700 Subject: [PATCH 18/20] 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 97f43e31f0abdb35275063c5e620df31c6bf256d Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Sat, 29 May 2021 16:08:31 -0700 Subject: [PATCH 19/20] 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 20/20] 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,