From 42f2ff679e6422272d18fc7f012136a82480ce03 Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Thu, 27 Aug 2020 15:40:41 -0700 Subject: [PATCH 01/83] Removed dead code from delay and base module related to characterization --- compiler/base/hierarchy_design.py | 10 ---------- compiler/characterizer/delay.py | 30 ------------------------------ 2 files changed, 40 deletions(-) diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index 79b5a53a..ea6a3f44 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -222,16 +222,6 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): return self == mod and \ child_net.lower() == alias_net.lower() and \ parent_net.lower() == alias_net.lower() - - def get_mod_net(self, parent_net, child_inst, child_conns): - """ - Given an instance and net, returns the internal net in the mod - corresponding to input net. - """ - for conn, pin in zip(child_conns, child_inst.mod.pins): - if parent_net.lower() == conn.lower(): - return pin - return None def translate_nets(self, subinst_ports, port_dict, inst_name): """Converts connection names to their spice hierarchy equivalent""" diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index da1b8147..556e02bb 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -366,36 +366,6 @@ class delay(simulation): # so it makes the search awkward return set(factory.get_mods(OPTS.replica_bitline)) - def get_primary_cell_mod(self, cell_mods): - """ - Distinguish bitcell array mod from replica bitline array. - Assume there are no replica bitcells in the primary array. - """ - if len(cell_mods) == 1: - return cell_mods[0] - rbc_mods = factory.get_mods(OPTS.replica_bitcell) - non_rbc_mods = [] - for bitcell in cell_mods: - has_cell = False - for replica_cell in rbc_mods: - has_cell = has_cell or replica_cell.contains(bitcell, replica_cell.mods) - if not has_cell: - non_rbc_mods.append(bitcell) - if len(non_rbc_mods) != 1: - debug.error('Multiple bitcell mods found. Cannot distinguish for characterization',1) - return non_rbc_mods[0] - - def are_mod_pins_equal(self, mods): - """Determines if there are pins differences in the input mods""" - - if len(mods) == 0: - return True - pins = mods[0].pins - for mod in mods[1:]: - if pins != mod.pins: - return False - return True - def get_alias_in_path(self, paths, int_net, mod, exclusion_set=None): """ Finds a single alias for the int_net in given paths. From 73b2277daa38b35e1469cfdf19f00487f7cb58c7 Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Thu, 27 Aug 2020 17:30:58 -0700 Subject: [PATCH 02/83] Removed dead code related to older characterization scheme --- compiler/custom/dff.py | 6 - compiler/modules/bank.py | 36 --- compiler/modules/bitcell_array.py | 7 - compiler/modules/control_logic.py | 226 ------------------ compiler/modules/delay_chain.py | 22 -- compiler/modules/dff_array.py | 6 - compiler/modules/dff_buf.py | 7 - compiler/modules/dff_buf_array.py | 6 - compiler/modules/dff_inv.py | 4 - compiler/modules/dff_inv_array.py | 8 +- compiler/modules/dummy_array.py | 9 +- compiler/modules/hierarchical_decoder.py | 8 - compiler/modules/precharge_array.py | 10 - compiler/modules/replica_bitcell_array.py | 7 - compiler/modules/sense_amp.py | 7 - compiler/modules/sense_amp_array.py | 15 -- .../modules/single_level_column_mux_array.py | 7 - compiler/modules/wordline_driver_array.py | 21 -- compiler/modules/write_driver_array.py | 4 - compiler/modules/write_mask_and_array.py | 5 - compiler/pgates/pand2.py | 19 +- compiler/pgates/pand3.py | 19 +- compiler/pgates/pbuf.py | 19 +- compiler/pgates/pdriver.py | 22 +- compiler/pgates/pinvbuf.py | 33 --- compiler/pgates/precharge.py | 9 +- compiler/pgates/single_level_column_mux.py | 15 -- compiler/sram/sram_1bank.py | 14 -- compiler/sram/sram_base.py | 48 +--- 29 files changed, 9 insertions(+), 610 deletions(-) diff --git a/compiler/custom/dff.py b/compiler/custom/dff.py index c8fdb4b0..cb703707 100644 --- a/compiler/custom/dff.py +++ b/compiler/custom/dff.py @@ -55,12 +55,6 @@ class dff(design.design): transition_prob = 0.5 return transition_prob*(c_load + c_para) - def get_clk_cin(self): - """Return the total capacitance (in relative units) that the clock is loaded by in the dff""" - #This is a handmade cell so the value must be entered in the tech.py file or estimated. - #Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width. - return parameter["dff_clk_cin"] - def build_graph(self, graph, inst_name, port_nets): """Adds edges based on inputs/outputs. Overrides base class function.""" self.add_graph_edges(graph, port_nets) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 12a3b037..45900370 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -1039,42 +1039,6 @@ class bank(design.design): self.add_via_center(layers=self.m1_stack, offset=control_pos) - def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True): - """Get the all the stage efforts for each stage in the path within the bank clk_buf to a wordline""" - # Decoder is assumed to have settled before the negative edge of the clock. - # Delay model relies on this assumption - stage_effort_list = [] - wordline_cout = self.bitcell_array.get_wordline_cin() + external_cout - stage_effort_list += self.port_address.wordline_driver.determine_wordline_stage_efforts(wordline_cout, - inp_is_rise) - - return stage_effort_list - - def get_wl_en_cin(self): - """Get the relative capacitance of all the clk connections in the bank""" - # wl_en only used in the wordline driver. - return self.port_address.wordline_driver.get_wl_en_cin() - - def get_w_en_cin(self): - """Get the relative capacitance of all the clk connections in the bank""" - # wl_en only used in the wordline driver. - port = self.write_ports[0] - return self.port_data[port].write_driver.get_w_en_cin() - - def get_clk_bar_cin(self): - """Get the relative capacitance of all the clk_bar connections in the bank""" - # Current bank only uses clock bar (clk_buf_bar) as an enable for the precharge array. - - # Precharges are the all the same in Mulitport, one is picked - port = self.read_ports[0] - return self.port_data[port].precharge_array.get_en_cin() - - def get_sen_cin(self): - """Get the relative capacitance of all the sense amp enable connections in the bank""" - # Current bank only uses sen as an enable for the sense amps. - port = self.read_ports[0] - return self.port_data[port].sense_amp_array.get_en_cin() - def graph_exclude_precharge(self): """Precharge adds a loop between bitlines, can be excluded to reduce complexity""" for port in self.read_ports: diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 81f1062f..24af458d 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -97,13 +97,6 @@ class bitcell_array(bitcell_base_array): bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c return bl_wire - def get_wordline_cin(self): - """Get the relative input capacitance from the wordline connections in all the bitcell""" - # A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns - bitcell_wl_cin = self.cell.get_wl_cin() - total_cin = bitcell_wl_cin * self.column_size - return total_cin - def graph_exclude_bits(self, targ_row, targ_col): """Excludes bits in column from being added to graph except target""" # Function is not robust with column mux configurations diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 706888de..e99d7b89 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -156,96 +156,12 @@ class control_logic(design.design): self.nand2 = factory.create(module_type="pnand2", height=dff_height) self.add_mod(self.nand2) - - # if (self.port_type == "rw") or (self.port_type == "r"): - # from importlib import reload - # self.delay_chain_resized = False - # c = reload(__import__(OPTS.replica_bitline)) - # replica_bitline = getattr(c, OPTS.replica_bitline) - # bitcell_loads = int(math.ceil(self.num_rows * OPTS.rbl_delay_percentage)) - # #Use a model to determine the delays with that heuristic - # if OPTS.use_tech_delay_chain_size: #Use tech parameters if set. - # fanout_list = OPTS.delay_chain_stages*[OPTS.delay_chain_fanout_per_stage] - # debug.info(1, "Using tech parameters to size delay chain: fanout_list={}".format(fanout_list)) - # self.replica_bitline = factory.create(module_type="replica_bitline", - # delay_fanout_list=fanout_list, - # bitcell_loads=bitcell_loads) - # if self.sram != None: #Calculate model value even for specified sizes - # self.set_sen_wl_delays() - - # else: #Otherwise, use a heuristic and/or model based sizing. - # #First use a heuristic - # delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size() - # self.replica_bitline = factory.create(module_type="replica_bitline", - # delay_fanout_list=[delay_fanout_heuristic]*delay_stages_heuristic, - # bitcell_loads=bitcell_loads) - # #Resize if necessary, condition depends on resizing method - # if self.sram != None and self.enable_delay_chain_resizing and not self.does_sen_rise_fall_timing_match(): - # #This resizes to match fall and rise delays, can make the delay chain weird sizes. - # stage_list = self.get_dynamic_delay_fanout_list(delay_stages_heuristic, delay_fanout_heuristic) - # self.replica_bitline = factory.create(module_type="replica_bitline", - # delay_fanout_list=stage_list, - # bitcell_loads=bitcell_loads) - - # #This resizes based on total delay. - # # delay_stages, delay_fanout = self.get_dynamic_delay_chain_size(delay_stages_heuristic, delay_fanout_heuristic) - # # self.replica_bitline = factory.create(module_type="replica_bitline", - # # delay_fanout_list=[delay_fanout]*delay_stages, - # # bitcell_loads=bitcell_loads) - - # self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing - # self.delay_chain_resized = True debug.check(OPTS.delay_chain_stages % 2, "Must use odd number of delay chain stages for inverting delay chain.") self.delay_chain=factory.create(module_type="delay_chain", fanout_list = OPTS.delay_chain_stages * [ OPTS.delay_chain_fanout_per_stage ]) self.add_mod(self.delay_chain) - - def get_heuristic_delay_chain_size(self): - """Use a basic heuristic to determine the size of the delay chain used for the Sense Amp Enable """ - # FIXME: The minimum was 2 fanout, now it will not pass DRC unless it is 3. Why? - delay_fanout = 3 # This can be anything >=3 - # Model poorly captures delay of the column mux. Be pessismistic for column mux - if self.words_per_row >= 2: - delay_stages = 8 - else: - delay_stages = 2 - - # Read ports have a shorter s_en delay. The model is not accurate enough to catch this difference - # on certain sram configs. - if self.port_type == "r": - delay_stages+=2 - - return (delay_stages, delay_fanout) - - def set_sen_wl_delays(self): - """Set delays for wordline and sense amp enable""" - self.wl_delay_rise, self.wl_delay_fall = self.get_delays_to_wl() - self.sen_delay_rise, self.sen_delay_fall = self.get_delays_to_sen() - self.wl_delay = self.wl_delay_rise + self.wl_delay_fall - self.sen_delay = self.sen_delay_rise + self.sen_delay_fall - - def does_sen_rise_fall_timing_match(self): - """Compare the relative rise/fall delays of the sense amp enable and wordline""" - self.set_sen_wl_delays() - # This is not necessarily more reliable than total delay in some cases. - if (self.wl_delay_rise * self.wl_timing_tolerance >= self.sen_delay_rise or - self.wl_delay_fall * self.wl_timing_tolerance >= self.sen_delay_fall): - return False - else: - return True - - def does_sen_total_timing_match(self): - """Compare the total delays of the sense amp enable and wordline""" - self.set_sen_wl_delays() - # The sen delay must always be bigger than than the wl - # delay. This decides how much larger the sen delay must be - # before a re-size is warranted. - if self.wl_delay * self.wl_timing_tolerance >= self.sen_delay: - return False - else: - return True def get_dynamic_delay_chain_size(self, previous_stages, previous_fanout): """Determine the size of the delay chain used for the Sense Amp Enable using path delays""" @@ -333,17 +249,6 @@ class control_logic(design.design): delay_per_stage = fanout + 1 + self.inv_parasitic_delay delay_stages = ceil(required_delay / delay_per_stage) return delay_stages - - def calculate_stage_list(self, total_stages, fanout_rise, fanout_fall): - """ - Produces a list of fanouts which determine the size of the delay chain. - List length is the number of stages. - Assumes the first stage is falling. - """ - stage_list = [] - for i in range(total_stages): - if i % 2 == 0: - stage_list.append() def setup_signal_busses(self): """ Setup bus names, determine the size of the busses etc """ @@ -869,137 +774,6 @@ class control_logic(design.design): offset=pin.ll(), height=pin.height(), width=pin.width()) - def get_delays_to_wl(self): - """Get the delay (in delay units) of the clk to a wordline in the bitcell array""" - debug.check(self.sram.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.") - self.wl_stage_efforts = self.get_wordline_stage_efforts() - clk_to_wl_rise, clk_to_wl_fall = logical_effort.calculate_relative_rise_fall_delays(self.wl_stage_efforts) - total_delay = clk_to_wl_rise + clk_to_wl_fall - debug.info(1, - "Clock to wl delay is rise={:.3f}, fall={:.3f}, total={:.3f} in delay units".format(clk_to_wl_rise, - clk_to_wl_fall, - total_delay)) - return clk_to_wl_rise, clk_to_wl_fall - - def get_wordline_stage_efforts(self): - """Follows the gated_clk_bar -> wl_en -> wordline signal for the total path efforts""" - stage_effort_list = [] - - # Initial direction of gated_clk_bar signal for this path - is_clk_bar_rise = True - - # Calculate the load on wl_en within the module and add it to external load - external_cout = self.sram.get_wl_en_cin() - # First stage is the clock buffer - stage_effort_list += self.clk_buf_driver.get_stage_efforts(external_cout, is_clk_bar_rise) - last_stage_is_rise = stage_effort_list[-1].is_rise - - # Then ask the sram for the other path delays (from the bank) - stage_effort_list += self.sram.get_wordline_stage_efforts(last_stage_is_rise) - - return stage_effort_list - - def get_delays_to_sen(self): - """ - Get the delay (in delay units) of the clk to a sense amp enable. - This does not incorporate the delay of the replica bitline. - """ - debug.check(self.sram.all_mods_except_control_done, "Cannot calculate sense amp enable delay unless all module have been added.") - self.sen_stage_efforts = self.get_sa_enable_stage_efforts() - clk_to_sen_rise, clk_to_sen_fall = logical_effort.calculate_relative_rise_fall_delays(self.sen_stage_efforts) - total_delay = clk_to_sen_rise + clk_to_sen_fall - debug.info(1, - "Clock to s_en delay is rise={:.3f}, fall={:.3f}, total={:.3f} in delay units".format(clk_to_sen_rise, - clk_to_sen_fall, - total_delay)) - return clk_to_sen_rise, clk_to_sen_fall - - def get_sa_enable_stage_efforts(self): - """Follows the gated_clk_bar signal to the sense amp enable signal adding each stages stage effort to a list""" - stage_effort_list = [] - - # Initial direction of clock signal for this path - last_stage_rise = True - - # First stage, gated_clk_bar -(and2)-> rbl_in. Only for RW ports. - if self.port_type == "rw": - stage1_cout = self.replica_bitline.get_en_cin() - stage_effort_list += self.and2.get_stage_efforts(stage1_cout, last_stage_rise) - last_stage_rise = stage_effort_list[-1].is_rise - - # Replica bitline stage, rbl_in -(rbl)-> pre_s_en - stage2_cout = self.sen_and2.get_cin() - stage_effort_list += self.replica_bitline.determine_sen_stage_efforts(stage2_cout, last_stage_rise) - last_stage_rise = stage_effort_list[-1].is_rise - - # buffer stage, pre_s_en -(buffer)-> s_en - stage3_cout = self.sram.get_sen_cin() - stage_effort_list += self.s_en_driver.get_stage_efforts(stage3_cout, last_stage_rise) - last_stage_rise = stage_effort_list[-1].is_rise - - return stage_effort_list - - def get_wl_sen_delays(self): - """ Gets a list of the stages and delays in order of their path. """ - - if self.sen_stage_efforts == None or self.wl_stage_efforts == None: - debug.error("Model delays not calculated for SRAM.", 1) - wl_delays = logical_effort.calculate_delays(self.wl_stage_efforts) - sen_delays = logical_effort.calculate_delays(self.sen_stage_efforts) - return wl_delays, sen_delays - - def analytical_delay(self, corner, slew, load): - """ Gets the analytical delay from clk input to wl_en output """ - - stage_effort_list = [] - # Calculate the load on clk_buf_bar - # ext_clk_buf_cout = self.sram.get_clk_bar_cin() - - # Operations logic starts on negative edge - last_stage_rise = False - - # First stage(s), clk -(pdriver)-> clk_buf. - # clk_buf_cout = self.replica_bitline.get_en_cin() - clk_buf_cout = 0 - stage_effort_list += self.clk_buf_driver.get_stage_efforts(clk_buf_cout, last_stage_rise) - last_stage_rise = stage_effort_list[-1].is_rise - - # Second stage, clk_buf -(inv)-> clk_bar - clk_bar_cout = self.and2.get_cin() - stage_effort_list += self.and2.get_stage_efforts(clk_bar_cout, last_stage_rise) - last_stage_rise = stage_effort_list[-1].is_rise - - # Third stage clk_bar -(and)-> gated_clk_bar - gated_clk_bar_cin = self.get_gated_clk_bar_cin() - stage_effort_list.append(self.inv.get_stage_effort(gated_clk_bar_cin, last_stage_rise)) - last_stage_rise = stage_effort_list[-1].is_rise - - # Stages from gated_clk_bar -------> wordline - stage_effort_list += self.get_wordline_stage_efforts() - return stage_effort_list - - def get_clk_buf_cin(self): - """ - Get the loads that are connected to the buffered clock. - Includes all the DFFs and some logic. - """ - - # Control logic internal load - int_clk_buf_cap = self.inv.get_cin() + self.ctrl_dff_array.get_clk_cin() + self.and2.get_cin() - - # Control logic external load (in the other parts of the SRAM) - ext_clk_buf_cap = self.sram.get_clk_bar_cin() - - return int_clk_buf_cap + ext_clk_buf_cap - - def get_gated_clk_bar_cin(self): - """Get intermediates net gated_clk_bar's capacitance""" - - total_cin = 0 - total_cin += self.wl_en_driver.get_cin() - if self.port_type == 'rw': - total_cin += self.and2.get_cin() - return total_cin def graph_exclude_dffs(self): """Exclude dffs from graph as they do not represent critical path""" diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index 246299c1..30126b63 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -210,25 +210,3 @@ class delay_chain(design.design): layer="m2", start=mid_point, end=mid_point.scale(1, 0)) - - def get_cin(self): - """Get the enable input ralative capacitance""" - # Only 1 input to the delay chain which is connected to an inverter. - dc_cin = self.inv.get_cin() - return dc_cin - - def determine_delayed_en_stage_efforts(self, ext_delayed_en_cout, inp_is_rise=True): - """Get the stage efforts from the en to s_en. Does not compute the delay for the bitline load.""" - stage_effort_list = [] - # Add a stage to the list for every stage in delay chain. - # Stages only differ in fanout except the last which has an external cout. - last_stage_is_rise = inp_is_rise - for stage_fanout in self.fanout_list: - stage_cout = self.inv.get_cin() * (stage_fanout + 1) - if len(stage_effort_list) == len(self.fanout_list) - 1: - stage_cout+=ext_delayed_en_cout - stage = self.inv.get_stage_effort(stage_cout, last_stage_is_rise) - stage_effort_list.append(stage) - last_stage_is_rise = stage.is_rise - - return stage_effort_list diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index c4f85a6d..cb82443b 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -155,9 +155,3 @@ class dff_array(design.design): self.add_via_stack_center(from_layer=clk_pin.layer, to_layer="m3", offset=vector(clk_pin.cx(), clk_ypos)) - - def get_clk_cin(self): - """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" - dff_clk_cin = self.dff.get_clk_cin() - total_cin = dff_clk_cin * self.rows * self.columns - return total_cin diff --git a/compiler/modules/dff_buf.py b/compiler/modules/dff_buf.py index 1657d7a8..1290bf12 100644 --- a/compiler/modules/dff_buf.py +++ b/compiler/modules/dff_buf.py @@ -196,10 +196,3 @@ class dff_buf(design.design): self.add_via_stack_center(from_layer=a2_pin.layer, to_layer="m2", offset=qb_pos) - - def get_clk_cin(self): - """Return the total capacitance (in relative units) that the clock is loaded by in the dff""" - # This is a handmade cell so the value must be entered in the tech.py file or estimated. - # Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width. - # FIXME: Dff changed in a past commit. The parameter need to be updated. - return parameter["dff_clk_cin"] diff --git a/compiler/modules/dff_buf_array.py b/compiler/modules/dff_buf_array.py index 88852d45..d6382973 100644 --- a/compiler/modules/dff_buf_array.py +++ b/compiler/modules/dff_buf_array.py @@ -227,9 +227,3 @@ class dff_buf_array(design.design): # Drop a via to the M3 pin self.add_via_center(layers=self.m2_stack, offset=vector(clk_pin.cx(), clk_ypos)) - - def get_clk_cin(self): - """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" - dff_clk_cin = self.dff.get_clk_cin() - total_cin = dff_clk_cin * self.rows * self.columns - return total_cin diff --git a/compiler/modules/dff_inv.py b/compiler/modules/dff_inv.py index 033312ef..8f50f9e8 100644 --- a/compiler/modules/dff_inv.py +++ b/compiler/modules/dff_inv.py @@ -150,7 +150,3 @@ class dff_inv(design.design): offset=dout_pin.center()) self.add_via_center(layers=self.m1_stack, offset=dout_pin.center()) - - def get_clk_cin(self): - """Return the total capacitance (in relative units) that the clock is loaded by in the dff""" - return self.dff.get_clk_cin() diff --git a/compiler/modules/dff_inv_array.py b/compiler/modules/dff_inv_array.py index 6b08bcce..1687e043 100644 --- a/compiler/modules/dff_inv_array.py +++ b/compiler/modules/dff_inv_array.py @@ -188,10 +188,4 @@ class dff_inv_array(design.design): height=self.height) # Drop a via to the M3 pin self.add_via_center(layers=self.m2_stack, - offset=vector(clk_pin.cx(),clk_ypos)) - - def get_clk_cin(self): - """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" - dff_clk_cin = self.dff.get_clk_cin() - total_cin = dff_clk_cin * self.rows * self.columns - return total_cin + offset=vector(clk_pin.cx(),clk_ypos)) diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py index 9004994b..01446d85 100644 --- a/compiler/modules/dummy_array.py +++ b/compiler/modules/dummy_array.py @@ -54,12 +54,7 @@ class dummy_array(bitcell_base_array): self.connect_inst(self.get_bitcell_pins(row, col)) def input_load(self): + # FIXME: This appears to be old code from previous characterization. Needs to be updated. wl_wire = self.gen_wl_wire() return wl_wire.return_input_cap() - - def get_wordline_cin(self): - """Get the relative input capacitance from the wordline connections in all the bitcell""" - # A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns - bitcell_wl_cin = self.cell.get_wl_cin() - total_cin = bitcell_wl_cin * self.column_size - return total_cin + \ No newline at end of file diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index e32fe1c6..ca26993f 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -606,11 +606,3 @@ class hierarchical_decoder(design.design): to_layer=self.output_layer, offset=rail_pos, directions=self.bus_directions) - - def input_load(self): - if self.determine_predecodes(self.num_inputs)[1]==0: - pre = self.pre2_4 - else: - pre = self.pre3_8 - return pre.input_load() - diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index c2d3d986..00fe9885 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -125,13 +125,3 @@ class precharge_array(design.design): offset = vector(tempx, 0) self.local_insts[i].place(offset=offset, mirror=mirror) xoffset = xoffset + self.pc_cell.width - - def get_en_cin(self): - """ - Get the relative capacitance of all the clk connections - in the precharge array - """ - # Assume single port - precharge_en_cin = self.pc_cell.get_en_cin() - return precharge_en_cin * self.columns - diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 14d7c858..64ae404e 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -552,13 +552,6 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell return bl_wire - def get_wordline_cin(self): - """Get the relative input capacitance from the wordline connections in all the bitcell""" - # A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns - bitcell_wl_cin = self.cell.get_wl_cin() - total_cin = bitcell_wl_cin * self.column_size - return total_cin - def graph_exclude_bits(self, targ_row, targ_col): """Excludes bits in column from being added to graph except target""" self.bitcell_array.graph_exclude_bits(targ_row, targ_col) diff --git a/compiler/modules/sense_amp.py b/compiler/modules/sense_amp.py index 67703903..f1d5de92 100644 --- a/compiler/modules/sense_amp.py +++ b/compiler/modules/sense_amp.py @@ -82,13 +82,6 @@ class sense_amp(design.design): # Power in this module currently not defined. Returns 0 nW (leakage and dynamic). total_power = self.return_power() return total_power - - def get_en_cin(self): - """Get the relative capacitance of sense amp enable gate cin""" - pmos_cin = parameter["sa_en_pmos_size"] / drc("minwidth_tx") - nmos_cin = parameter["sa_en_nmos_size"] / drc("minwidth_tx") - # sen is connected to 2 pmos isolation TX and 1 nmos per sense amp. - return 2 * pmos_cin + nmos_cin def get_enable_name(self): """Returns name used for enable net""" diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 20f6e06f..6d0b85d2 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -190,18 +190,3 @@ class sense_amp_array(design.design): self.add_via_stack_center(from_layer=en_pin.layer, to_layer=self.en_layer, offset=inst.get_pin(self.amp.en_name).center()) - - def input_load(self): - return self.amp.input_load() - - def get_en_cin(self): - """Get the relative capacitance of all the sense amp enable connections in the array""" - sense_amp_en_cin = self.amp.get_en_cin() - return sense_amp_en_cin * self.word_size - - def get_drain_cin(self): - """Get the relative capacitance of the drain of the PMOS isolation TX""" - from tech import parameter - # Bitcell drain load being used to estimate PMOS drain load - drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap']) - return drain_load diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index f57bbb20..267b2a6a 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -230,10 +230,3 @@ class single_level_column_mux_array(design.design): to_layer=self.sel_layer, offset=br_out_offset_begin, directions=self.via_directions) - - def get_drain_cin(self): - """Get the relative capacitance of the drain of the NMOS pass TX""" - from tech import parameter - # Bitcell drain load being used to estimate mux NMOS drain load - drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap']) - return drain_load diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index f82938de..ac0a0cb2 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -159,24 +159,3 @@ class wordline_driver_array(design.design): layer=self.route_layer, start=wl_offset, end=wl_offset - vector(self.m1_width, 0)) - - def determine_wordline_stage_efforts(self, external_cout, inp_is_rise=True): - """ - Follows the clk_buf to a wordline signal adding - each stages stage effort to a list. - """ - stage_effort_list = [] - - stage1 = self.wl_driver.get_stage_effort(external_cout, inp_is_rise) - stage_effort_list.append(stage1) - - return stage_effort_list - - def get_wl_en_cin(self): - """ - Get the relative capacitance of all - the enable connections in the bank - """ - # The enable is connected to a and2 for every row. - total_cin = self.wl_driver.get_cin() * self.rows - return total_cin diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 665142ec..b7bcd6b3 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -265,7 +265,3 @@ class write_driver_array(design.design): offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1), width=self.width) - def get_w_en_cin(self): - """Get the relative capacitance of all the enable connections in the bank""" - # The enable is connected to a nand2 for every row. - return self.driver.get_w_en_cin() * len(self.driver_insts) diff --git a/compiler/modules/write_mask_and_array.py b/compiler/modules/write_mask_and_array.py index 9b083512..04563209 100644 --- a/compiler/modules/write_mask_and_array.py +++ b/compiler/modules/write_mask_and_array.py @@ -140,8 +140,3 @@ class write_mask_and_array(design.design): supply_pin_left = self.and2_insts[0].get_pin(supply) supply_pin_right = self.and2_insts[self.num_wmasks - 1].get_pin(supply) self.add_path(supply_pin_left.layer, [supply_pin_left.lc(), supply_pin_right.rc()]) - - def get_cin(self): - """Get the relative capacitance of all the input connections in the bank""" - # The enable is connected to an and2 for every row. - return self.and2.get_cin() * len(self.and2_insts) diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index a46485d0..21241056 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -146,21 +146,4 @@ class pand2(pgate.pgate): offset=pin.center(), width=pin.width(), height=pin.height()) - - def get_stage_efforts(self, external_cout, inp_is_rise=False): - """Get the stage efforts of the A or B -> Z path""" - stage_effort_list = [] - stage1_cout = self.inv.get_cin() - stage1 = self.nand.get_stage_effort(stage1_cout, inp_is_rise) - stage_effort_list.append(stage1) - last_stage_is_rise = stage1.is_rise - - stage2 = self.inv.get_stage_effort(external_cout, last_stage_is_rise) - stage_effort_list.append(stage2) - - return stage_effort_list - - def get_cin(self): - """Return the relative input capacitance of a single input""" - return self.nand.get_cin() - + \ No newline at end of file diff --git a/compiler/pgates/pand3.py b/compiler/pgates/pand3.py index 72a57f74..63d1cd0f 100644 --- a/compiler/pgates/pand3.py +++ b/compiler/pgates/pand3.py @@ -161,21 +161,4 @@ class pand3(pgate.pgate): slew=nand_delay.slew, load=load) return nand_delay + inv_delay - - def get_stage_efforts(self, external_cout, inp_is_rise=False): - """Get the stage efforts of the A or B -> Z path""" - stage_effort_list = [] - stage1_cout = self.inv.get_cin() - stage1 = self.nand.get_stage_effort(stage1_cout, inp_is_rise) - stage_effort_list.append(stage1) - last_stage_is_rise = stage1.is_rise - - stage2 = self.inv.get_stage_effort(external_cout, last_stage_is_rise) - stage_effort_list.append(stage2) - - return stage_effort_list - - def get_cin(self): - """Return the relative input capacitance of a single input""" - return self.nand.get_cin() - + \ No newline at end of file diff --git a/compiler/pgates/pbuf.py b/compiler/pgates/pbuf.py index d82e2091..e504b89e 100644 --- a/compiler/pgates/pbuf.py +++ b/compiler/pgates/pbuf.py @@ -96,21 +96,4 @@ class pbuf(pgate.pgate): offset=a_pin.center(), width=a_pin.width(), height=a_pin.height()) - - def get_stage_efforts(self, external_cout, inp_is_rise=False): - """Get the stage efforts of the A -> Z path""" - stage_effort_list = [] - stage1_cout = self.inv2.get_cin() - stage1 = self.inv1.get_stage_effort(stage1_cout, inp_is_rise) - stage_effort_list.append(stage1) - last_stage_is_rise = stage1.is_rise - - stage2 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise) - stage_effort_list.append(stage2) - - return stage_effort_list - - def get_cin(self): - """Returns the relative capacitance of the input""" - input_cin = self.inv1.get_cin() - return input_cin + \ No newline at end of file diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index 8916f0fa..e48f9f6c 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -168,24 +168,4 @@ class pdriver(pgate.pgate): def get_sizes(self): """ Return the relative sizes of the buffers """ return self.size_list - - def get_stage_efforts(self, external_cout, inp_is_rise=False): - """ Get the stage efforts of the A -> Z path """ - cout_list = [] - for prev_inv, inv in zip(self.inv_list, self.inv_list[1:]): - cout_list.append(inv.get_cin()) - - cout_list.append(external_cout) - - stage_effort_list = [] - last_inp_is_rise = inp_is_rise - for inv, cout in zip(self.inv_list, cout_list): - stage = inv.get_stage_effort(cout, last_inp_is_rise) - stage_effort_list.append(stage) - last_inp_is_rise = stage.is_rise - - return stage_effort_list - - def get_cin(self): - """ Returns the relative capacitance of the input """ - return self.inv_list[0].get_cin() + \ No newline at end of file diff --git a/compiler/pgates/pinvbuf.py b/compiler/pgates/pinvbuf.py index f746736c..497bd3df 100644 --- a/compiler/pgates/pinvbuf.py +++ b/compiler/pgates/pinvbuf.py @@ -184,36 +184,3 @@ class pinvbuf(pgate.pgate): self.add_layout_pin_rect_center(text="A", layer=a_pin.layer, offset=a_pin.center()) - - def determine_clk_buf_stage_efforts(self, external_cout, inp_is_rise=False): - """Get the stage efforts of the clk -> clk_buf path""" - stage_effort_list = [] - stage1_cout = self.inv1.get_cin() + self.inv2.get_cin() - stage1 = self.inv.get_stage_effort(stage1_cout, inp_is_rise) - stage_effort_list.append(stage1) - last_stage_is_rise = stage1.is_rise - - stage2 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise) - stage_effort_list.append(stage2) - - return stage_effort_list - - def determine_clk_buf_bar_stage_efforts(self, external_cout, inp_is_rise=False): - """Get the stage efforts of the clk -> clk_buf path""" - - # After (almost) every stage, the direction of the signal inverts. - stage_effort_list = [] - stage1_cout = self.inv1.get_cin() + self.inv2.get_cin() - stage1 = self.inv.get_stage_effort(stage1_cout, inp_is_rise) - stage_effort_list.append(stage1) - last_stage_is_rise = stage_effort_list[-1].is_rise - - stage2_cout = self.inv2.get_cin() - stage2 = self.inv1.get_stage_effort(stage2_cout, last_stage_is_rise) - stage_effort_list.append(stage2) - last_stage_is_rise = stage_effort_list[-1].is_rise - - stage3 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise) - stage_effort_list.append(stage3) - - return stage_effort_list diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index aefdbb86..4ae48167 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -300,11 +300,4 @@ class precharge(design.design): self.add_path(self.bitline_layer, [left_pos, right_pos], width=pmos_pin.height()) - - def get_en_cin(self): - """Get the relative capacitance of the enable in the precharge cell""" - # The enable connect to three pmos gates - # They all use the same size pmos. - pmos_cin = self.pmos.get_cin() - return 3 * pmos_cin - + \ No newline at end of file diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py index cd9be887..4873e6fc 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/single_level_column_mux.py @@ -241,18 +241,3 @@ class single_level_column_mux(pgate.pgate): offset=vector(0, 0), width=self.bitcell.width, height=self.height) - - def get_stage_effort(self, corner, slew, load): - """ - Returns relative delay that the column mux. - Difficult to convert to LE model. - """ - parasitic_delay = 1 - # This is not CMOS, so using this may be incorrect. - cin = 2 * self.tx_size - return logical_effort.logical_effort("column_mux", - self.tx_size, - cin, - load, - parasitic_delay, - False) diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 3f254b73..c67f7233 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -626,20 +626,6 @@ class sram_1bank(sram_base): # Insts located in control logic, exclusion function called here for inst in self.control_logic_insts: inst.mod.graph_exclude_dffs() - - def get_sen_name(self, sram_name, port=0): - """Returns the s_en spice name.""" - # Naming scheme is hardcoded using this function, should be built into the - # graph in someway. - sen_name = "s_en{}".format(port) - control_conns = self.get_conns(self.control_logic_insts[port]) - # Sanity checks - if sen_name not in control_conns: - debug.error("Signal={} not contained in control logic connections={}".format(sen_name, - control_conns)) - if sen_name in self.pins: - debug.error("Internal signal={} contained in port list. Name defined by the parent.".format(sen_name)) - return "X{}.{}".format(sram_name, sen_name) def get_cell_name(self, inst_name, row, col): """Gets the spice name of the target bitcell.""" diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index ffaca694..c9eb4ea1 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -630,50 +630,4 @@ class sram_base(design, verilog, lef): def lvs_write(self, sp_name): self.sp_write(sp_name, lvs_netlist=True) - - def get_wordline_stage_efforts(self, inp_is_rise=True): - """Get the all the stage efforts for each stage in the path from clk_buf to a wordline""" - stage_effort_list = [] - - # Clk_buf originates from the control logic so only the bank is related to the wordline path - # No loading on the wordline other than in the bank. - external_wordline_cout = 0 - stage_effort_list += self.bank.determine_wordline_stage_efforts(external_wordline_cout, inp_is_rise) - - return stage_effort_list - - def get_wl_en_cin(self): - """Gets the capacitive load the of clock (clk_buf) for the sram""" - # Only the wordline drivers within the bank use this signal - return self.bank.get_wl_en_cin() - - def get_w_en_cin(self): - """Gets the capacitive load the of write enable (w_en) for the sram""" - # Only the write drivers within the bank use this signal - return self.bank.get_w_en_cin() - - def get_p_en_bar_cin(self): - """Gets the capacitive load the of precharge enable (p_en_bar) for the sram""" - # Only the precharges within the bank use this signal - return self.bank.get_p_en_bar_cin() - - def get_clk_bar_cin(self): - """Gets the capacitive load the of clock (clk_buf_bar) for the sram""" - # As clk_buf_bar is an output of the control logic. The cap for that module is not determined here. - # Only the precharge cells use this signal (other than the control logic) - return self.bank.get_clk_bar_cin() - - def get_sen_cin(self): - """Gets the capacitive load the of sense amp enable for the sram""" - # Only the sense_amps use this signal (other than the control logic) - return self.bank.get_sen_cin() - - def get_dff_clk_buf_cin(self): - """Get the relative capacitance of the clk_buf signal. - Does not get the control logic loading but everything else""" - total_cin = 0 - total_cin += self.row_addr_dff.get_clk_cin() - total_cin += self.data_dff.get_clk_cin() - if self.col_addr_size > 0: - total_cin += self.col_addr_dff.get_clk_cin() - return total_cin + \ No newline at end of file From 13b1d4613c41c771930fcde481978506039b32d5 Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Mon, 31 Aug 2020 14:36:13 -0700 Subject: [PATCH 03/83] Moved spice naming checking code from design to the spice base module --- compiler/base/hierarchy_design.py | 46 ------------------------------- compiler/base/hierarchy_spice.py | 45 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 46 deletions(-) diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index ea6a3f44..16d2bb4e 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -177,52 +177,6 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): name_dict[si_port.lower()] = mod_info subinst.mod.build_names(name_dict, subinst_name, subinst_ports) - def find_aliases(self, inst_name, port_nets, path_nets, alias, alias_mod, exclusion_set=None): - """Given a list of nets, will compare the internal alias of a mod to determine - if the nets have a connection to this mod's net (but not inst). - """ - if not exclusion_set: - exclusion_set = set() - try: - self.name_dict - except AttributeError: - self.name_dict = {} - self.build_names(self.name_dict, inst_name, port_nets) - aliases = [] - for net in path_nets: - net = net.lower() - int_net = self.name_dict[net]['int_net'] - int_mod = self.name_dict[net]['mod'] - if int_mod.is_net_alias(int_net, alias, alias_mod, exclusion_set): - aliases.append(net) - return aliases - - def is_net_alias(self, known_net, net_alias, mod, exclusion_set): - """Checks if the alias_net in input mod is the same as the input net for this mod (self).""" - if self in exclusion_set: - return False - # Check ports of this mod - for pin in self.pins: - if self.is_net_alias_name_check(known_net, pin, net_alias, mod): - return True - # Check connections of all other subinsts - mod_set = set() - for subinst, inst_conns in zip(self.insts, self.conns): - for inst_conn, mod_pin in zip(inst_conns, subinst.mod.pins): - if self.is_net_alias_name_check(known_net, inst_conn, net_alias, mod): - return True - elif inst_conn.lower() == known_net.lower() and subinst.mod not in mod_set: - if subinst.mod.is_net_alias(mod_pin, net_alias, mod, exclusion_set): - return True - mod_set.add(subinst.mod) - return False - - def is_net_alias_name_check(self, parent_net, child_net, alias_net, mod): - """Utility function for checking single net alias.""" - return self == mod and \ - child_net.lower() == alias_net.lower() and \ - parent_net.lower() == alias_net.lower() - def translate_nets(self, subinst_ports, port_dict, inst_name): """Converts connection names to their spice hierarchy equivalent""" converted_conns = [] diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 5a15fce5..c436d260 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -490,3 +490,48 @@ class spice(): def return_power(self, dynamic=0.0, leakage=0.0): return power_data(dynamic, leakage) + def find_aliases(self, inst_name, port_nets, path_nets, alias, alias_mod, exclusion_set=None): + """Given a list of nets, will compare the internal alias of a mod to determine + if the nets have a connection to this mod's net (but not inst). + """ + if not exclusion_set: + exclusion_set = set() + try: + self.name_dict + except AttributeError: + self.name_dict = {} + self.build_names(self.name_dict, inst_name, port_nets) + aliases = [] + for net in path_nets: + net = net.lower() + int_net = self.name_dict[net]['int_net'] + int_mod = self.name_dict[net]['mod'] + if int_mod.is_net_alias(int_net, alias, alias_mod, exclusion_set): + aliases.append(net) + return aliases + + def is_net_alias(self, known_net, net_alias, mod, exclusion_set): + """Checks if the alias_net in input mod is the same as the input net for this mod (self).""" + if self in exclusion_set: + return False + # Check ports of this mod + for pin in self.pins: + if self.is_net_alias_name_check(known_net, pin, net_alias, mod): + return True + # Check connections of all other subinsts + mod_set = set() + for subinst, inst_conns in zip(self.insts, self.conns): + for inst_conn, mod_pin in zip(inst_conns, subinst.mod.pins): + if self.is_net_alias_name_check(known_net, inst_conn, net_alias, mod): + return True + elif inst_conn.lower() == known_net.lower() and subinst.mod not in mod_set: + if subinst.mod.is_net_alias(mod_pin, net_alias, mod, exclusion_set): + return True + mod_set.add(subinst.mod) + return False + + def is_net_alias_name_check(self, parent_net, child_net, alias_net, mod): + """Utility function for checking single net alias.""" + return self == mod and \ + child_net.lower() == alias_net.lower() and \ + parent_net.lower() == alias_net.lower() From 7bdce3ca9a9449ba8f403d6fd6e560a886ba5690 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 1 Sep 2020 09:55:23 -0700 Subject: [PATCH 04/83] Don't make dummy bitlines pins for simplicity --- compiler/modules/dummy_array.py | 51 ++++++++++++++++++- compiler/modules/replica_bitcell_array.py | 43 ++++------------ .../15_global_bitcell_array_1rw_1r_test.py | 41 +++++++++++++++ 3 files changed, 100 insertions(+), 35 deletions(-) create mode 100755 compiler/tests/15_global_bitcell_array_1rw_1r_test.py diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py index 9004994b..37ce0ba4 100644 --- a/compiler/modules/dummy_array.py +++ b/compiler/modules/dummy_array.py @@ -53,13 +53,60 @@ class dummy_array(bitcell_base_array): mod=self.dummy_cell) self.connect_inst(self.get_bitcell_pins(row, col)) + def add_pins(self): + # bitline pins are not added because they are floating + for wl_name in self.get_wordline_names(): + self.add_pin(wl_name, "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def add_layout_pins(self): + """ Add the layout pins """ + + # Add the bitline metal, but not as pins since they are going to just be floating + # For some reason, LVS has an issue if we don't add this metal + bitline_names = self.cell.get_all_bitline_names() + for col in range(self.column_size): + for port in self.all_ports: + bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port]) + self.add_rect(layer=bl_pin.layer, + offset=bl_pin.ll().scale(1, 0), + width=bl_pin.width(), + height=self.height) + br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1]) + self.add_rect(layer=br_pin.layer, + offset=br_pin.ll().scale(1, 0), + width=br_pin.width(), + height=self.height) + + wl_names = self.cell.get_all_wl_names() + for row in range(self.row_size): + for port in self.all_ports: + wl_pin = self.cell_inst[row, 0].get_pin(wl_names[port]) + self.add_layout_pin(text="wl_{0}_{1}".format(port, row), + layer=wl_pin.layer, + offset=wl_pin.ll().scale(0, 1), + width=self.width, + height=wl_pin.height()) + + # Copy a vdd/gnd layout pin from every cell + for row in range(self.row_size): + for col in range(self.column_size): + inst = self.cell_inst[row, col] + for pin_name in ["vdd", "gnd"]: + self.copy_layout_pin(inst, pin_name) + def input_load(self): wl_wire = self.gen_wl_wire() return wl_wire.return_input_cap() def get_wordline_cin(self): - """Get the relative input capacitance from the wordline connections in all the bitcell""" - # A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns + """ + Get the relative input capacitance from the + wordline connections in all the bitcell + """ + # A single wordline is connected to all the bitcells + # in a single row meaning the capacitance depends on the # of columns bitcell_wl_cin = self.cell.get_wl_cin() total_cin = bitcell_wl_cin * self.column_size return total_cin diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 299c7421..75fed678 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -187,21 +187,13 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.bitline_names = [] # Replica bitlines by port self.rbl_bitline_names = [] - # Dummy bitlines by left/right - self.dummy_col_bitline_names = [] - for loc in ["left", "right"]: - self.dummy_col_bitline_names.append([]) + for x in range(self.add_left_rbl + self.add_right_rbl): + self.rbl_bitline_names.append([]) for port in self.all_ports: - bitline_names = ["dummy_{0}_{1}".format(x, loc) for x in self.row_cap_left.get_bitline_names(port)] - self.dummy_col_bitline_names[-1].extend(bitline_names) - self.all_dummy_col_bitline_names = [x for sl in self.dummy_col_bitline_names for x in sl] - - for port in range(self.add_left_rbl + self.add_right_rbl): - left_names=["rbl_bl_{0}_{1}".format(x, port) for x in self.all_ports] - right_names=["rbl_br_{0}_{1}".format(x, port) for x in self.all_ports] - bitline_names = [x for t in zip(left_names, right_names) for x in t] - self.rbl_bitline_names.append(bitline_names) + self.rbl_bitline_names[-1].append("rbl_bl_{0}_{1}".format(port, x)) + self.rbl_bitline_names[-1].append("rbl_br_{0}_{1}".format(port, x)) + # Make a flat list too self.all_rbl_bitline_names = [x for sl in self.rbl_bitline_names for x in sl] @@ -211,13 +203,11 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Make a flat list too self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] - self.add_pin_list(self.dummy_col_bitline_names[0], "INOUT") for port in range(self.add_left_rbl): self.add_pin_list(self.rbl_bitline_names[port], "INOUT") self.add_pin_list(self.all_bitline_names, "INOUT") for port in range(self.add_left_rbl, self.add_left_rbl + self.add_right_rbl): self.add_pin_list(self.rbl_bitline_names[port], "INOUT") - self.add_pin_list(self.dummy_col_bitline_names[1], "INOUT") def add_wordline_pins(self): @@ -288,29 +278,25 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): for port in range(self.left_rbl + self.right_rbl): self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port), mod=self.dummy_row)) - self.connect_inst(self.all_bitline_names + self.rbl_wordline_names[port] + supplies) + self.connect_inst(self.rbl_wordline_names[port] + supplies) # Top/bottom dummy rows or col caps self.dummy_row_insts = [] self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot", mod=self.col_cap)) - self.connect_inst(self.all_bitline_names - + self.dummy_row_wordline_names[0] - + supplies) + self.connect_inst(self.dummy_row_wordline_names[0] + supplies) self.dummy_row_insts.append(self.add_inst(name="dummy_row_top", mod=self.col_cap)) - self.connect_inst(self.all_bitline_names - + self.dummy_row_wordline_names[1] - + supplies) + self.connect_inst(self.dummy_row_wordline_names[1] + supplies) # Left/right Dummy columns self.dummy_col_insts = [] self.dummy_col_insts.append(self.add_inst(name="dummy_col_left", mod=self.row_cap_left)) - self.connect_inst(self.dummy_col_bitline_names[0] + self.replica_array_wordline_names + supplies) + self.connect_inst(self.replica_array_wordline_names + supplies) self.dummy_col_insts.append(self.add_inst(name="dummy_col_right", mod=self.row_cap_right)) - self.connect_inst(self.dummy_col_bitline_names[1] + self.replica_array_wordline_names + supplies) + self.connect_inst(self.replica_array_wordline_names + supplies) def create_layout(self): @@ -480,13 +466,11 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def get_all_bitline_names(self): """ Return ALL the bitline names (including dummy and rbl) """ temp = [] - temp.extend(self.get_dummy_bitline_names(0)) if self.add_left_rbl > 0: temp.extend(self.get_rbl_bitline_names(0)) temp.extend(self.get_bitline_names()) if self.add_right_rbl > 0: temp.extend(self.get_rbl_bitline_names(self.add_left_rbl)) - temp.extend(self.get_dummy_bitline_names(1)) return temp def get_wordline_names(self, port=None): @@ -518,13 +502,6 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): return self.all_dummy_row_wordline_names else: return self.dummy_row_wordline_names[port] - - def get_dummy_bitline_names(self, port=None): - """ Return the BL for the given dummy port """ - if port == None: - return self.all_dummy_col_bitline_names - else: - return self.dummy_col_bitline_names[port] def analytical_power(self, corner, load): """Power of Bitcell array and bitline in nW.""" diff --git a/compiler/tests/15_global_bitcell_array_1rw_1r_test.py b/compiler/tests/15_global_bitcell_array_1rw_1r_test.py new file mode 100755 index 00000000..d92e3b2b --- /dev/null +++ b/compiler/tests/15_global_bitcell_array_1rw_1r_test.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from sram_factory import factory +import debug + + +# @unittest.skip("SKIPPING 05_global_bitcell_array_test") +class global_bitcell_array_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + debug.info(2, "Testing 2 x 4x4 global bitcell array for 6t_cell without replica") + a = factory.create(module_type="global_bitcell_array", cols=[4, 4], rows=4, ports=[0]) + self.local_check(a) + + # debug.info(2, "Testing 4x4 local bitcell array for 6t_cell with replica column") + # a = factory.create(module_type="local_bitcell_array", cols=4, left_rbl=1, rows=4, ports=[0]) + # self.local_check(a) + + globals.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From c1c631abe1a96d55531ae3520a4969cb46e2bccf Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 1 Sep 2020 10:57:49 -0700 Subject: [PATCH 05/83] Global bitcell array passes LVS/DRC --- compiler/modules/global_bitcell_array.py | 177 +++++++++++++----- compiler/modules/local_bitcell_array.py | 4 +- .../15_global_bitcell_array_1rw_1r_test.py | 9 +- .../tests/15_global_bitcell_array_test.py | 14 +- 4 files changed, 148 insertions(+), 56 deletions(-) diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index 264a3500..d0b051ff 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -10,6 +10,7 @@ from globals import OPTS from sram_factory import factory from vector import vector import debug +from numpy import cumsum class global_bitcell_array(design.design): @@ -19,20 +20,19 @@ class global_bitcell_array(design.design): Cols is a list of the array widths. add_left_rbl and add_right_ """ - def __init__(self, rows, cols, ports, name=""): + def __init__(self, rows, cols, name=""): # The total of all columns will be the number of columns super().__init__(name=name) self.cols = cols + self.num_cols = sum(cols) + self.col_offsets = [0] + list(cumsum(self.cols)[:-1]) self.rows = rows - self.all_ports = ports - debug.check(len(ports)<=2, "Only support dual port or less in global bitcell array.") + debug.check(len(self.all_ports)<=2, "Only support dual port or less in global bitcell array.") self.rbl = [1, 1 if len(self.all_ports)>1 else 0] self.left_rbl = self.rbl[0] self.right_rbl = self.rbl[1] - # Just used for pin names - self.cell = factory.create(module_type="bitcell") self.create_netlist() if not OPTS.netlist_only: @@ -48,6 +48,8 @@ class global_bitcell_array(design.design): self.place() + self.route() + self.add_layout_pins() self.add_boundary() @@ -58,6 +60,12 @@ class global_bitcell_array(design.design): """ Add the modules used in this design """ self.local_mods = [] + if self.cols == 1: + la = factory.create(module_type="local_bitcell_array", rows=self.rows, cols=self.cols[0], rbl=self.rbl, add_rbl=[self.left_rbl, self.right_rbl]) + self.add_mod(la) + self.local_mods.append(la) + return + for i, cols in enumerate(self.cols): # Always add the left RBLs to the first subarray and the right RBLs to the last subarray if i == 0: @@ -69,10 +77,9 @@ class global_bitcell_array(design.design): self.add_mod(la) self.local_mods.append(la) - def add_pins(self): - return + self.add_bitline_pins() self.add_wordline_pins() @@ -80,60 +87,84 @@ class global_bitcell_array(design.design): self.add_pin("gnd", "GROUND") def add_bitline_pins(self): + self.bitline_names = [] for port in self.all_ports: - self.add_pin_list(self.replica_bitline_names[port], "INOUT") + self.bitline_names.append("rbl_bl_{0}_{1}".format(port, 0)) + self.bitline_names.append("rbl_br_{0}_{1}".format(port, 0)) + + for col in range(self.num_cols): + for port in self.all_ports: + self.bitline_names.append("bl_{0}_{1}".format(port, col)) + self.bitline_names.append("br_{0}_{1}".format(port, col)) + + if len(self.all_ports) > 1: + for port in self.all_ports: + self.bitline_names.append("rbl_bl_{0}_{1}".format(port, 1)) + self.bitline_names.append("rbl_br_{0}_{1}".format(port, 1)) + self.add_pin_list(self.bitline_names, "INOUT") def add_wordline_pins(self): - # All wordline names for all ports - self.wordline_names = [] - # Wordline names for each port - self.wordline_names_by_port = [[] for x in self.all_ports] - # Replica wordlines by port - self.replica_wordline_names = [[] for x in self.all_ports] - - # Regular array wordline names - self.bitcell_array_wordline_names = self.bitcell_array.get_all_wordline_names() - self.wordline_names = [] - # Left port WLs - for port in range(self.left_rbl): - # Make names for all RBLs - wl_names=["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()] - # Keep track of the pin that is the RBL - self.replica_wordline_names[port] = wl_names - self.wordline_names.extend(wl_names) + self.wordline_names.append("rbl_wl_0_0") # Regular WLs - self.wordline_names.extend(self.bitcell_array_wordline_names) - - # Right port WLs - for port in range(self.left_rbl, self.left_rbl + self.right_rbl): - # Make names for all RBLs - wl_names=["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()] - # Keep track of the pin that is the RBL - self.replica_wordline_names[port] = wl_names - self.wordline_names.extend(wl_names) - - # Array of all port wl names - for port in range(self.left_rbl + self.right_rbl): - wl_names = ["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()] - self.replica_wordline_names[port] = wl_names + for row in range(self.rows): + for port in self.all_ports: + self.wordline_names.append("wl_{0}_{1}".format(port, row)) + + if len(self.all_ports) > 1: + self.wordline_names.append("rbl_wl_1_1") self.add_pin_list(self.wordline_names, "INPUT") - def create_instances(self): """ Create the module instances used in this design """ + + self.local_insts = [] - for i, mod in enumerate(self.local_mods): - name = "la_{0}".format(i) + for col, mod in zip(self.col_offsets, self.local_mods): + name = "la_{0}".format(col) self.local_insts.append(self.add_inst(name=name, - mod=mod)) - self.connect_inst(mod.pins) + mod=mod)) + + temp = [] + if col == 0: + temp.append("rbl_bl_0_0") + temp.append("rbl_br_0_0") + if len(self.all_ports) > 1: + temp.append("rbl_bl_1_0") + temp.append("rbl_br_1_0") + + port_inouts = [x for x in mod.get_inouts() if x.startswith("bl") or x.startswith("br")] + for pin_name in port_inouts: + # Offset of the last underscore that defines the bit number + bit_index = pin_name.rindex('_') + # col is the bit offset of the local array, + # while col_value is the offset within this array + col_value = int(pin_name[bit_index + 1:]) + # Name of signal without the bit + base_name = pin_name[:bit_index] + # Strip the bit and add the new one + new_name = "{0}_{1}".format(base_name, col + col_value) + temp.append(new_name) + + if len(self.all_ports) > 1 and mod == self.local_mods[-1]: + temp.append("rbl_bl_0_1") + temp.append("rbl_br_0_1") + temp.append("rbl_bl_1_1") + temp.append("rbl_br_1_1") + + for port in self.all_ports: + port_inputs = [x for x in mod.get_inputs() if "wl_{}".format(port) in x] + temp.extend(port_inputs) + + temp.append("vdd") + temp.append("gnd") + self.connect_inst(temp) def place(self): offset = vector(0, 0) @@ -144,5 +175,61 @@ class global_bitcell_array(design.design): self.height = self.local_mods[0].height self.width = self.local_insts[-1].rx() + def route(self): + + # Route the global wordlines (assumes pins all line up) + for port in self.all_ports: + port_inputs = [x for x in self.local_mods[0].get_inputs() if "wl_{}".format(port) in x] + for i, pin_name in enumerate(port_inputs): + pins = [x.get_pin(pin_name) for x in self.local_insts] + + y_offset = pins[0].cy() + if port == 0: + y_offset -= 1.5 * self.m3_pitch + else: + y_offset += 1.5 * self.m3_pitch + + start_offset = vector(pins[0].lx(), y_offset) + end_offset = vector(pins[-1].rx(), y_offset) + self.add_layout_pin_segment_center(text=pin_name, + layer="m3", + start=start_offset, + end=end_offset) + + for pin in pins: + self.add_via_stack_center(from_layer=pin.layer, + to_layer="m3", + offset=pin.center()) + end_offset = vector(pin.cx(), y_offset) + self.add_path("m3", [pin.center(), end_offset]) + def add_layout_pins(self): - pass + + # Regular bitlines + for col, inst in zip(self.col_offsets, self.local_insts): + for port in self.all_ports: + port_inouts = [x for x in inst.mod.get_inouts() if x.startswith("bl_{}".format(port)) or x.startswith("br_{}".format(port))] + for pin_name in port_inouts: + # Offset of the last underscore that defines the bit number + bit_index = pin_name.rindex('_') + # col is the bit offset of the local array, + # while col_value is the offset within this array + col_value = int(pin_name[bit_index + 1:]) + # Name of signal without the bit + base_name = pin_name[:bit_index] + # Strip the bit and add the new one + new_name = "{0}_{1}".format(base_name, col + col_value) + self.copy_layout_pin(inst, pin_name, new_name) + + + # Replica bitlines + self.copy_layout_pin(self.local_insts[0], "rbl_bl_0_0") + self.copy_layout_pin(self.local_insts[0], "rbl_br_0_0") + + if len(self.all_ports) > 1: + self.copy_layout_pin(self.local_insts[-1], "rbl_bl_1_0") + self.copy_layout_pin(self.local_insts[-1], "rbl_br_1_0") + + for inst in self.insts: + self.copy_power_pins(inst, "vdd") + self.copy_power_pins(inst, "gnd") diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index 7a917390..f82b5cd1 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -110,7 +110,7 @@ class local_bitcell_array(design.design): # word lines (bottom to top) # vdd # gnd - self.add_pin_list([x for x in self.all_array_bitline_names if not x.startswith("dummy")], "INOUT") + self.add_pin_list(self.all_array_bitline_names, "INOUT") for port in self.all_ports: self.add_pin_list(self.wordline_names[port], "INPUT") self.add_pin("vdd", "POWER") @@ -146,7 +146,7 @@ class local_bitcell_array(design.design): mirror="MY") self.height = self.bitcell_array.height - self.width = self.bitcell_array_inst.rx() + self.width = max(self.bitcell_array_inst.rx(), max([x.rx() for x in self.wl_insts])) def route_unused_wordlines(self): """ Connect the unused RBL and dummy wordlines to gnd """ diff --git a/compiler/tests/15_global_bitcell_array_1rw_1r_test.py b/compiler/tests/15_global_bitcell_array_1rw_1r_test.py index d92e3b2b..dd17d82e 100755 --- a/compiler/tests/15_global_bitcell_array_1rw_1r_test.py +++ b/compiler/tests/15_global_bitcell_array_1rw_1r_test.py @@ -22,8 +22,13 @@ class global_bitcell_array_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - debug.info(2, "Testing 2 x 4x4 global bitcell array for 6t_cell without replica") - a = factory.create(module_type="global_bitcell_array", cols=[4, 4], rows=4, ports=[0]) + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + debug.info(2, "Testing 2 x 4x4 global bitcell array for cell_1rw_1r") + a = factory.create(module_type="global_bitcell_array", cols=[4, 4], rows=4) self.local_check(a) # debug.info(2, "Testing 4x4 local bitcell array for 6t_cell with replica column") diff --git a/compiler/tests/15_global_bitcell_array_test.py b/compiler/tests/15_global_bitcell_array_test.py index 18c25c37..ed7e282a 100755 --- a/compiler/tests/15_global_bitcell_array_test.py +++ b/compiler/tests/15_global_bitcell_array_test.py @@ -15,20 +15,20 @@ from sram_factory import factory import debug -@unittest.skip("SKIPPING 05_global_bitcell_array_test") +# @unittest.skip("SKIPPING 05_global_bitcell_array_test") class global_bitcell_array_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - debug.info(2, "Testing 2 x 4x4 global bitcell array for 6t_cell without replica") - a = factory.create(module_type="global_bitcell_array", cols=[4, 4], rows=4, ports=[0]) - self.local_check(a) - - # debug.info(2, "Testing 4x4 local bitcell array for 6t_cell with replica column") - # a = factory.create(module_type="local_bitcell_array", cols=4, left_rbl=1, rows=4, ports=[0]) + # debug.info(2, "Testing 2 x 4x4 global bitcell array for 6t_cell") + # a = factory.create(module_type="global_bitcell_array", cols=[4, 4], rows=4) # self.local_check(a) + + debug.info(2, "Testing 2 x 4x4 global bitcell array for 6t_cell") + a = factory.create(module_type="global_bitcell_array", cols=[10, 6], rows=4) + self.local_check(a) globals.end_openram() From 4ec47d8ee1472fbb8531fbf995181b62f174395d Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 1 Sep 2020 11:59:01 -0700 Subject: [PATCH 06/83] Refactor global and local to be a bitcell_base_array --- compiler/modules/bank.py | 32 ++++++-- compiler/modules/bitcell_base_array.py | 89 ++++++++++++++++++----- compiler/modules/global_bitcell_array.py | 17 +++-- compiler/modules/local_bitcell_array.py | 17 ++++- compiler/modules/replica_bitcell_array.py | 67 +---------------- 5 files changed, 122 insertions(+), 100 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index ba6e4a4e..a0b6c9b5 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -8,7 +8,7 @@ import debug import design from sram_factory import factory -from math import log, ceil +from math import log, ceil, floor from tech import drc, layer from vector import vector from globals import OPTS @@ -371,14 +371,30 @@ class bank(design.design): self.add_mod(self.port_address) self.num_rbl = len(self.all_ports) - - self.bitcell_array = factory.create(module_type="replica_bitcell_array", - cols=self.num_cols + self.num_spare_cols, - rows=self.num_rows, - rbl=[1, 1 if len(self.all_ports)>1 else 0]) + try: + local_bitline_size = OPTS.local_bitline_size + except AttributeError: + local_bitline_size = 0 + + if local_bitline_size > 0: + # Find the even multiple that satisfies the fanout with equal sized local arrays + total_cols = self.num_cols + self.num_spare_cols + num_lb = floor(total_cols / local_bitline_size) + final_size = total_cols - num_lb * local_bitline_size + cols = [local_bitline_size] * (num_lb - 1) + # Add the odd bits to the last local array + cols.append(local_bitline_size + final_size) + self.bitcell_array = factory.create(module_type="global_bitcell_array", + cols=cols, + rows=self.num_rows) + else: + self.bitcell_array = factory.create(module_type="replica_bitcell_array", + cols=self.num_cols + self.num_spare_cols, + rows=self.num_rows, + rbl=[1, 1 if len(self.all_ports)>1 else 0]) self.add_mod(self.bitcell_array) - + if(self.num_banks > 1): self.bank_select = factory.create(module_type="bank_select") self.add_mod(self.bank_select) @@ -392,7 +408,7 @@ class bank(design.design): # bit lines (left to right) # vdd # gnd - + import pdb; pdb.set_trace() temp = self.bitcell_array.get_all_bitline_names() wordline_names = self.bitcell_array.get_all_wordline_names() diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 18e3adec..00ea49b0 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -26,13 +26,12 @@ class bitcell_base_array(design.design): # Bitcell for port names only self.cell = factory.create(module_type="bitcell") - + + # This will create a default set of bitline/wordline names + # They may get over-riden in the super module self.create_all_bitline_names() self.create_all_wordline_names() - - def get_all_bitline_names(self, prefix=""): - return [prefix + x for x in self.all_bitline_names] - + def create_all_bitline_names(self): self.bitline_names = [[] for port in self.all_ports] for col in range(self.column_size): @@ -42,8 +41,8 @@ class bitcell_base_array(design.design): # Make a flat list too self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] - def get_all_wordline_names(self, prefix=""): - return [prefix + x for x in self.all_wordline_names] + # def get_all_wordline_names(self, prefix=""): + # return [prefix + x for x in self.all_wordline_names] def create_all_wordline_names(self): self.wordline_names = [[] for port in self.all_ports] @@ -52,18 +51,6 @@ class bitcell_base_array(design.design): self.wordline_names[port].append("wl_{0}_{1}".format(port, row)) self.all_wordline_names = [x for sl in zip(*self.wordline_names) for x in sl] - def get_bitline_names(self, port=None): - if port == None: - return self.all_bitline_names - else: - return self.bitline_names[port] - - def get_wordline_names(self, port=None): - if port == None: - return self.all_wordline_names - else: - return self.wordline_names[port] - def add_pins(self): for bl_name in self.get_bitline_names(): self.add_pin(bl_name, "INOUT") @@ -84,6 +71,70 @@ class bitcell_base_array(design.design): return bitcell_pins + def get_rbl_wordline_names(self, port=None): + """ + Return the ACTIVE WL for the given RBL port. + Inactive will be set to gnd. + """ + if port == None: + return self.all_rbl_wordline_names + else: + return self.rbl_wordline_names[port] + + def get_rbl_bitline_names(self, port=None): + """ Return the BL for the given RBL port """ + if port == None: + return self.all_rbl_bitline_names + else: + return self.rbl_bitline_names[port] + + def get_bitline_names(self, port=None): + """ Return the regular bitlines for the given port or all""" + if port == None: + return self.all_bitline_names + else: + return self.bitline_names[port] + + def get_all_bitline_names(self): + """ Return ALL the bitline names (including dummy and rbl) """ + temp = [] + if self.add_left_rbl > 0: + temp.extend(self.get_rbl_bitline_names(0)) + temp.extend(self.get_bitline_names()) + if self.add_right_rbl > 0: + temp.extend(self.get_rbl_bitline_names(self.add_left_rbl)) + return temp + + def get_wordline_names(self, port=None): + """ Return the regular wordline names """ + if port == None: + return self.all_wordline_names + else: + return self.wordline_names[port] + + def get_all_wordline_names(self, port=None): + """ Return all the wordline names """ + temp = [] + temp.extend(self.get_dummy_wordline_names(0)) + temp.extend(self.get_rbl_wordline_names(0)) + if port == None: + temp.extend(self.all_wordline_names) + else: + temp.extend(self.wordline_names[port]) + if len(self.all_ports) > 1: + temp.extend(self.get_rbl_wordline_names(1)) + temp.extend(self.get_dummy_wordline_names(1)) + return temp + + def get_dummy_wordline_names(self, port=None): + """ + Return the ACTIVE WL for the given dummy port. + """ + if port == None: + return self.all_dummy_row_wordline_names + else: + return self.dummy_row_wordline_names[port] + def add_layout_pins(self): """ Add the layout pins """ diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index d0b051ff..d5e5678b 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -5,7 +5,7 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design +import bitcell_base_array from globals import OPTS from sram_factory import factory from vector import vector @@ -13,7 +13,7 @@ import debug from numpy import cumsum -class global_bitcell_array(design.design): +class global_bitcell_array(bitcell_base_array.bitcell_base_array): """ Creates a global bitcell array. Rows is an integer number for all local arrays. @@ -22,7 +22,7 @@ class global_bitcell_array(design.design): """ def __init__(self, rows, cols, name=""): # The total of all columns will be the number of columns - super().__init__(name=name) + super().__init__(name=name, rows=rows, cols=cols, column_offset=0) self.cols = cols self.num_cols = sum(cols) self.col_offsets = [0] + list(cumsum(self.cols)[:-1]) @@ -32,7 +32,6 @@ class global_bitcell_array(design.design): self.rbl = [1, 1 if len(self.all_ports)>1 else 0] self.left_rbl = self.rbl[0] self.right_rbl = self.rbl[1] - self.create_netlist() if not OPTS.netlist_only: @@ -77,7 +76,15 @@ class global_bitcell_array(design.design): self.add_mod(la) self.local_mods.append(la) - + + # We make these on our own and don't use the base names + def create_all_wordline_names(self): + pass + + # We make these on our own and don't use the base names + def create_all_bitline_names(self): + pass + def add_pins(self): self.add_bitline_pins() diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index f82b5cd1..b08fc2e5 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -5,20 +5,21 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import design +import bitcell_base_array from globals import OPTS from sram_factory import factory from vector import vector import debug -class local_bitcell_array(design.design): + +class local_bitcell_array(bitcell_base_array.bitcell_base_array): """ A local bitcell array is a bitcell array with a wordline driver. This can either be a single aray on its own if there is no hierarchical WL or it can be combined into a larger array with hierarchical WL. """ def __init__(self, rows, cols, rbl, add_rbl=None, name=""): - super().__init__(name=name) + super().__init__(name=name, rows=rows, cols=cols, column_offset=0) debug.info(2, "create local array of size {} rows x {} cols words".format(rows, cols)) self.rows = rows @@ -74,8 +75,15 @@ class local_bitcell_array(design.design): cols=self.cols) self.add_mod(self.wl_array) - def add_pins(self): + # We make these on our own and don't use the base names + def create_all_wordline_names(self): + pass + # We make these on our own and don't use the base names + def create_all_bitline_names(self): + pass + + def add_pins(self): # Inputs to the wordline driver (by port) self.wordline_names = [] # Outputs from the wordline driver (by port) @@ -105,6 +113,7 @@ class local_bitcell_array(design.design): self.bitline_names = self.bitcell_array.bitline_names self.all_array_bitline_names = self.bitcell_array.get_all_bitline_names() + # Arrays are always: # bit lines (left to right) # word lines (bottom to top) diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 75fed678..0bb95044 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -51,6 +51,9 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Two dummy cols plus replica if we add the column self.extra_cols = 2 + self.add_left_rbl + self.add_right_rbl + self.create_all_bitline_names() + self.create_all_wordline_names() + self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -439,70 +442,6 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): for inst in self.replica_col_insts: self.copy_layout_pin(inst, pin_name) - def get_rbl_wordline_names(self, port=None): - """ - Return the ACTIVE WL for the given RBL port. - Inactive will be set to gnd. - """ - if port == None: - return self.all_rbl_wordline_names - else: - return self.rbl_wordline_names[port] - - def get_rbl_bitline_names(self, port=None): - """ Return the BL for the given RBL port """ - if port == None: - return self.all_rbl_bitline_names - else: - return self.rbl_bitline_names[port] - - def get_bitline_names(self, port=None): - """ Return the regular bitlines for the given port or all""" - if port == None: - return self.all_bitline_names - else: - return self.bitline_names[port] - - def get_all_bitline_names(self): - """ Return ALL the bitline names (including dummy and rbl) """ - temp = [] - if self.add_left_rbl > 0: - temp.extend(self.get_rbl_bitline_names(0)) - temp.extend(self.get_bitline_names()) - if self.add_right_rbl > 0: - temp.extend(self.get_rbl_bitline_names(self.add_left_rbl)) - return temp - - def get_wordline_names(self, port=None): - """ Return the regular wordline names """ - if port == None: - return self.all_wordline_names - else: - return self.wordline_names[port] - - def get_all_wordline_names(self, port=None): - """ Return all the wordline names """ - temp = [] - temp.extend(self.get_dummy_wordline_names(0)) - temp.extend(self.get_rbl_wordline_names(0)) - if port == None: - temp.extend(self.all_wordline_names) - else: - temp.extend(self.wordline_names[port]) - if len(self.all_ports) > 1: - temp.extend(self.get_rbl_wordline_names(1)) - temp.extend(self.get_dummy_wordline_names(1)) - return temp - - def get_dummy_wordline_names(self, port=None): - """ - Return the ACTIVE WL for the given dummy port. - """ - if port == None: - return self.all_dummy_row_wordline_names - else: - return self.dummy_row_wordline_names[port] - def analytical_power(self, corner, load): """Power of Bitcell array and bitline in nW.""" # Dynamic Power from Bitline From d027632bdc7a9164acb6f98688a1fedc2d528e95 Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Wed, 2 Sep 2020 14:22:18 -0700 Subject: [PATCH 07/83] Moved majority of code duplicated between delay and functional to simulation --- compiler/characterizer/delay.py | 97 +--------------------------- compiler/characterizer/functional.py | 63 +----------------- compiler/characterizer/simulation.py | 93 ++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 158 deletions(-) diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 556e02bb..f04965e5 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -252,18 +252,7 @@ class delay(simulation): self.load = load self.slew = slew - - def add_graph_exclusions(self): - """Exclude portions of SRAM from timing graph which are not relevant""" - - # other initializations can only be done during analysis when a bit has been selected - # for testing. - self.sram.bank.graph_exclude_precharge() - self.sram.graph_exclude_addr_dff() - self.sram.graph_exclude_data_dff() - self.sram.graph_exclude_ctrl_dffs() - self.sram.bank.bitcell_array.graph_exclude_replica_col_bits() - + def create_graph(self): """Creates timing graph to generate the timing paths for the SRAM output.""" @@ -275,90 +264,6 @@ class delay(simulation): self.sram_spc_name = "X{}".format(self.sram.name) self.sram.build_graph(self.graph,self.sram_spc_name,self.pins) - def set_internal_spice_names(self): - """Sets important names for characterization such as Sense amp enable and internal bit nets.""" - - port = self.read_ports[0] - if not OPTS.use_pex: - self.graph.get_all_paths('{}{}'.format("clk", port), - '{}{}_{}'.format(self.dout_name, port, self.probe_data)) - - sen_with_port = self.get_sen_name(self.graph.all_paths) - if sen_with_port.endswith(str(port)): - self.sen_name = sen_with_port[:-len(str(port))] - else: - self.sen_name = sen_with_port - debug.warning("Error occurred while determining SEN name. Can cause faults in simulation.") - - debug.info(2,"s_en name = {}".format(self.sen_name)) - - bl_name_port, br_name_port = self.get_bl_name(self.graph.all_paths, port) - port_pos = -1-len(str(self.probe_data))-len(str(port)) - - if bl_name_port.endswith(str(port)+"_"+str(self.probe_data)): - self.bl_name = bl_name_port[:port_pos] +"{}"+ bl_name_port[port_pos+len(str(port)):] - elif not bl_name_port[port_pos].isdigit(): # single port SRAM case, bl will not be numbered eg bl_0 - self.bl_name = bl_name_port - else: - self.bl_name = bl_name_port - debug.warning("Error occurred while determining bitline names. Can cause faults in simulation.") - - if br_name_port.endswith(str(port)+"_"+str(self.probe_data)): - self.br_name = br_name_port[:port_pos] +"{}"+ br_name_port[port_pos+len(str(port)):] - elif not br_name_port[port_pos].isdigit(): # single port SRAM case, bl will not be numbered eg bl_0 - self.br_name = br_name_port - else: - self.br_name = br_name_port - debug.warning("Error occurred while determining bitline names. Can cause faults in simulation.") - debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name)) - else: - self.graph.get_all_paths('{}{}'.format("clk", port), - '{}{}_{}'.format(self.dout_name, port, self.probe_data)) - - self.sen_name = self.get_sen_name(self.graph.all_paths) - debug.info(2,"s_en name = {}".format(self.sen_name)) - - - self.bl_name = "bl{0}_{1}".format(port, OPTS.word_size-1) - self.br_name = "br{0}_{1}".format(port, OPTS.word_size-1) - debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name)) - - - def get_sen_name(self, paths, assumed_port=None): - """ - Gets the signal name associated with the sense amp enable from input paths. - Only expects a single path to contain the sen signal name. - """ - - sa_mods = factory.get_mods(OPTS.sense_amp) - # Any sense amp instantiated should be identical, any change to that - # will require some identification to determine the mod desired. - debug.check(len(sa_mods) == 1, "Only expected one type of Sense Amp. Cannot perform s_en checks.") - enable_name = sa_mods[0].get_enable_name() - sen_name = self.get_alias_in_path(paths, enable_name, sa_mods[0]) - if OPTS.use_pex: - sen_name = sen_name.split('.')[-1] - return sen_name - - def get_bl_name(self, paths, port): - """Gets the signal name associated with the bitlines in the bank.""" - - cell_mod = factory.create(module_type=OPTS.bitcell) - cell_bl = cell_mod.get_bl_name(port) - cell_br = cell_mod.get_br_name(port) - - bl_found = False - # Only a single path should contain a single s_en name. Anything else is an error. - bl_names = [] - exclude_set = self.get_bl_name_search_exclusions() - for int_net in [cell_bl, cell_br]: - bl_names.append(self.get_alias_in_path(paths, int_net, cell_mod, exclude_set)) - if OPTS.use_pex: - for i in range(len(bl_names)): - bl_names[i] = bl_names[i].split('.')[-1] - return bl_names[0], bl_names[1] - - def get_bl_name_search_exclusions(self): """Gets the mods as a set which should be excluded while searching for name.""" diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index 8574c4f6..67e0d224 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -419,18 +419,6 @@ class functional(simulation): self.stim.write_control(self.cycle_times[-1] + self.period) self.sf.close() - - # FIXME: refactor to share with delay.py - def add_graph_exclusions(self): - """Exclude portions of SRAM from timing graph which are not relevant""" - - # other initializations can only be done during analysis when a bit has been selected - # for testing. - self.sram.bank.graph_exclude_precharge() - self.sram.graph_exclude_addr_dff() - self.sram.graph_exclude_data_dff() - self.sram.graph_exclude_ctrl_dffs() - self.sram.bank.bitcell_array.graph_exclude_replica_col_bits() # FIXME: refactor to share with delay.py def create_graph(self): @@ -444,25 +432,7 @@ class functional(simulation): self.graph = graph_util.timing_graph() self.sram_spc_name = "X{}".format(self.sram.name) self.sram.build_graph(self.graph, self.sram_spc_name, self.pins) - - # FIXME: refactor to share with delay.py - def set_internal_spice_names(self): - """Sets important names for characterization such as Sense amp enable and internal bit nets.""" - - # For now, only testing these using first read port. - port = self.read_ports[0] - self.graph.get_all_paths('{}{}'.format("clk", port), - '{}{}_{}'.format(self.dout_name, port, 0).lower()) - - self.sen_name = self.get_sen_name(self.graph.all_paths) - debug.info(2, "s_en name = {}".format(self.sen_name)) - - self.bl_name, self.br_name = self.get_bl_name(self.graph.all_paths, port) - debug.info(2, "bl name={}, br name={}".format(self.bl_name, self.br_name)) - - self.q_name, self.qbar_name = self.get_bit_name() - debug.info(2, "q name={}\nqbar name={}".format(self.q_name, self.qbar_name)) - + def get_bit_name(self): """ Get a bit cell name """ (cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, 0, 0) @@ -473,37 +443,6 @@ class functional(simulation): qbar_name = cell_name + '.' + str(storage_names[1]) return (q_name, qbar_name) - - # FIXME: refactor to share with delay.py - def get_sen_name(self, paths): - """ - Gets the signal name associated with the sense amp enable from input paths. - Only expects a single path to contain the sen signal name. - """ - - sa_mods = factory.get_mods(OPTS.sense_amp) - # Any sense amp instantiated should be identical, any change to that - # will require some identification to determine the mod desired. - debug.check(len(sa_mods) == 1, "Only expected one type of Sense Amp. Cannot perform s_en checks.") - enable_name = sa_mods[0].get_enable_name() - sen_name = self.get_alias_in_path(paths, enable_name, sa_mods[0]) - return sen_name - - # FIXME: refactor to share with delay.py - def get_bl_name(self, paths, port): - """Gets the signal name associated with the bitlines in the bank.""" - - cell_mod = factory.create(module_type=OPTS.bitcell) - cell_bl = cell_mod.get_bl_name(port) - cell_br = cell_mod.get_br_name(port) - - # Only a single path should contain a single s_en name. Anything else is an error. - bl_names = [] - exclude_set = self.get_bl_name_search_exclusions() - for int_net in [cell_bl, cell_br]: - bl_names.append(self.get_alias_in_path(paths, int_net, cell_mod, exclude_set)) - - return bl_names[0], bl_names[1] def get_bl_name_search_exclusions(self): """Gets the mods as a set which should be excluded while searching for name.""" diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index 064eb2c5..9768e241 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -408,3 +408,96 @@ class simulation(): pin_names.append("{0}".format("gnd")) return pin_names + def add_graph_exclusions(self): + """Exclude portions of SRAM from timing graph which are not relevant""" + + # other initializations can only be done during analysis when a bit has been selected + # for testing. + self.sram.bank.graph_exclude_precharge() + self.sram.graph_exclude_addr_dff() + self.sram.graph_exclude_data_dff() + self.sram.graph_exclude_ctrl_dffs() + self.sram.bank.bitcell_array.graph_exclude_replica_col_bits() + + def set_internal_spice_names(self): + """Sets important names for characterization such as Sense amp enable and internal bit nets.""" + + port = self.read_ports[0] + if not OPTS.use_pex: + self.graph.get_all_paths('{}{}'.format("clk", port), + '{}{}_{}'.format(self.dout_name, port, self.probe_data)) + + sen_with_port = self.get_sen_name(self.graph.all_paths) + if sen_with_port.endswith(str(port)): + self.sen_name = sen_with_port[:-len(str(port))] + else: + self.sen_name = sen_with_port + debug.warning("Error occurred while determining SEN name. Can cause faults in simulation.") + + debug.info(2,"s_en name = {}".format(self.sen_name)) + + bl_name_port, br_name_port = self.get_bl_name(self.graph.all_paths, port) + port_pos = -1-len(str(self.probe_data))-len(str(port)) + + if bl_name_port.endswith(str(port)+"_"+str(self.probe_data)): + self.bl_name = bl_name_port[:port_pos] +"{}"+ bl_name_port[port_pos+len(str(port)):] + elif not bl_name_port[port_pos].isdigit(): # single port SRAM case, bl will not be numbered eg bl_0 + self.bl_name = bl_name_port + else: + self.bl_name = bl_name_port + debug.warning("Error occurred while determining bitline names. Can cause faults in simulation.") + + if br_name_port.endswith(str(port)+"_"+str(self.probe_data)): + self.br_name = br_name_port[:port_pos] +"{}"+ br_name_port[port_pos+len(str(port)):] + elif not br_name_port[port_pos].isdigit(): # single port SRAM case, bl will not be numbered eg bl_0 + self.br_name = br_name_port + else: + self.br_name = br_name_port + debug.warning("Error occurred while determining bitline names. Can cause faults in simulation.") + debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name)) + else: + self.graph.get_all_paths('{}{}'.format("clk", port), + '{}{}_{}'.format(self.dout_name, port, self.probe_data)) + + self.sen_name = self.get_sen_name(self.graph.all_paths) + debug.info(2,"s_en name = {}".format(self.sen_name)) + + + self.bl_name = "bl{0}_{1}".format(port, OPTS.word_size-1) + self.br_name = "br{0}_{1}".format(port, OPTS.word_size-1) + debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name)) + + def get_sen_name(self, paths, assumed_port=None): + """ + Gets the signal name associated with the sense amp enable from input paths. + Only expects a single path to contain the sen signal name. + """ + + sa_mods = factory.get_mods(OPTS.sense_amp) + # Any sense amp instantiated should be identical, any change to that + # will require some identification to determine the mod desired. + debug.check(len(sa_mods) == 1, "Only expected one type of Sense Amp. Cannot perform s_en checks.") + enable_name = sa_mods[0].get_enable_name() + sen_name = self.get_alias_in_path(paths, enable_name, sa_mods[0]) + if OPTS.use_pex: + sen_name = sen_name.split('.')[-1] + return sen_name + + + def get_bl_name(self, paths, port): + """Gets the signal name associated with the bitlines in the bank.""" + + cell_mod = factory.create(module_type=OPTS.bitcell) + cell_bl = cell_mod.get_bl_name(port) + cell_br = cell_mod.get_br_name(port) + + bl_found = False + # Only a single path should contain a single s_en name. Anything else is an error. + bl_names = [] + exclude_set = self.get_bl_name_search_exclusions() + for int_net in [cell_bl, cell_br]: + bl_names.append(self.get_alias_in_path(paths, int_net, cell_mod, exclude_set)) + if OPTS.use_pex: + for i in range(len(bl_names)): + bl_names[i] = bl_names[i].split('.')[-1] + return bl_names[0], bl_names[1] \ No newline at end of file From f6f6242d68e0a43b9c65308921db1edf73ed9176 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 3 Sep 2020 10:45:28 -0700 Subject: [PATCH 08/83] Ground dummy lines in replica bitcell array --- compiler/modules/replica_bitcell_array.py | 53 +++++++++++++---------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 0bb95044..894b4460 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -218,14 +218,8 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.wordline_names = [] # Replica wordlines by port self.rbl_wordline_names = [] - # Dummy wordlines by bot/top - self.dummy_row_wordline_names = [] - dummy_row_wordline_names = ["dummy_" + x for x in self.col_cap.get_wordline_names()] - for loc in ["bot", "top"]: - wordline_names = ["{0}_{1}".format(wl_name, loc) for wl_name in dummy_row_wordline_names] - self.dummy_row_wordline_names.append(wordline_names) - self.all_dummy_row_wordline_names = [x for sl in self.dummy_row_wordline_names for x in sl] + self.dummy_row_wordline_names = ["gnd"] * len(self.col_cap.get_wordline_names()) for port in range(self.left_rbl + self.right_rbl): wordline_names=["rbl_wl_{0}_{1}".format(x, port) for x in self.all_ports] @@ -239,21 +233,19 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # All wordlines including dummy and RBL self.replica_array_wordline_names = [] - self.replica_array_wordline_names.extend(self.dummy_row_wordline_names[0]) + self.replica_array_wordline_names.extend(self.dummy_row_wordline_names) for p in range(self.left_rbl): self.replica_array_wordline_names.extend(self.rbl_wordline_names[p]) self.replica_array_wordline_names.extend(self.all_wordline_names) for p in range(self.left_rbl, self.left_rbl + self.right_rbl): self.replica_array_wordline_names.extend(self.rbl_wordline_names[p]) - self.replica_array_wordline_names.extend(self.dummy_row_wordline_names[1]) + self.replica_array_wordline_names.extend(self.dummy_row_wordline_names) - self.add_pin_list(self.dummy_row_wordline_names[0], "INPUT") for port in range(self.left_rbl): self.add_pin_list(self.rbl_wordline_names[port], "INPUT") self.add_pin_list(self.all_wordline_names, "INPUT") for port in range(self.left_rbl, self.left_rbl + self.right_rbl): self.add_pin_list(self.rbl_wordline_names[port], "INPUT") - self.add_pin_list(self.dummy_row_wordline_names[1], "INPUT") def create_instances(self): """ Create the module instances used in this design """ @@ -287,10 +279,10 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.dummy_row_insts = [] self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot", mod=self.col_cap)) - self.connect_inst(self.dummy_row_wordline_names[0] + supplies) + self.connect_inst(self.dummy_row_wordline_names + supplies) self.dummy_row_insts.append(self.add_inst(name="dummy_row_top", mod=self.col_cap)) - self.connect_inst(self.dummy_row_wordline_names[1] + supplies) + self.connect_inst(self.dummy_row_wordline_names + supplies) # Left/right Dummy columns self.dummy_col_insts = [] @@ -316,12 +308,15 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.add_end_caps() + # Array was at (0, 0) but move everything so it is at the lower left # We move DOWN the number of left RBL even if we didn't add the column to this bitcell array self.translate_all(self.bitcell_offset.scale(-1 - self.add_left_rbl, -1 - self.left_rbl)) self.add_layout_pins() + self.route_unused_wordlines() + self.add_boundary() self.DRC_LVS() @@ -395,17 +390,6 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): width=pin.width(), height=self.height) - # Dummy wordlines - for (names, inst) in zip(self.dummy_row_wordline_names, self.dummy_row_insts): - for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()): - # It's always a single row - pin = inst.get_pin(pin_name) - self.add_layout_pin(text=wl_name, - layer=pin.layer, - offset=pin.ll().scale(0, 1), - width=self.width, - height=pin.height()) - # Replica wordlines (go by the row instead of replica column because we may have to add a pin # even though the column is in another local bitcell array) for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): @@ -459,6 +443,27 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): cell_power.leakage * self.column_size * self.row_size) return total_power + def route_unused_wordlines(self): + """ Connect the unused RBL and dummy wordlines to gnd """ + + for inst in self.dummy_row_insts: + for wl_name in self.col_cap.get_wordline_names(): + pin = inst.get_pin(wl_name) + pin_layer = pin.layer + layer_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer)) + left_pin_loc = vector(self.dummy_col_insts[0].lx(), pin.cy()) + right_pin_loc = vector(self.dummy_col_insts[1].rx(), pin.cy()) + + # Place the pins a track outside of the array + left_loc = left_pin_loc - vector(layer_pitch, 0) + right_loc = right_pin_loc + vector(layer_pitch, 0) + self.add_power_pin("gnd", left_loc, directions=("H", "H")) + self.add_power_pin("gnd", right_loc, directions=("H", "H")) + + # Add a path to connect to the array + self.add_path(pin_layer, [left_loc, left_pin_loc]) + self.add_path(pin_layer, [right_loc, right_pin_loc]) + def gen_bl_wire(self): if OPTS.netlist_only: height = 0 From 15342953262fe692af6e499299427ce28f856354 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 3 Sep 2020 14:04:20 -0700 Subject: [PATCH 09/83] Ground dummy lines in replica bitcell array --- compiler/modules/local_bitcell_array.py | 31 +------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index b08fc2e5..b125fb01 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -101,15 +101,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): self.wordline_names.append(wordline_inputs) self.driver_wordline_outputs.append([x + "i" for x in self.wordline_names[-1]]) - self.gnd_wl_names = [] - - # Connect unused RBL WL to gnd - array_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("rbl")]) - dummy_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("dummy")]) - rbl_wl_names = set([x for rbl_port_names in self.wordline_names for x in rbl_port_names if x.startswith("rbl")]) - self.gnd_wl_names = list((array_rbl_names - rbl_wl_names) | dummy_rbl_names) - - self.all_array_wordline_inputs = [x + "i" if x not in self.gnd_wl_names else "gnd" for x in self.bitcell_array.get_all_wordline_names()] + self.all_array_wordline_inputs = [x + "i" for x in self.bitcell_array.get_all_wordline_names() if x != "gnd"] self.bitline_names = self.bitcell_array.bitline_names self.all_array_bitline_names = self.bitcell_array.get_all_bitline_names() @@ -157,26 +149,6 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): self.height = self.bitcell_array.height self.width = max(self.bitcell_array_inst.rx(), max([x.rx() for x in self.wl_insts])) - def route_unused_wordlines(self): - """ Connect the unused RBL and dummy wordlines to gnd """ - - for wl_name in self.gnd_wl_names: - pin = self.bitcell_array_inst.get_pin(wl_name) - pin_layer = pin.layer - layer_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer)) - left_pin_loc = pin.lc() - right_pin_loc = pin.rc() - - # Place the pins a track outside of the array - left_loc = left_pin_loc - vector(layer_pitch, 0) - right_loc = right_pin_loc + vector(layer_pitch, 0) - self.add_power_pin("gnd", left_loc, directions=("H", "H")) - self.add_power_pin("gnd", right_loc, directions=("H", "H")) - - # Add a path to connect to the array - self.add_path(pin_layer, [left_loc, left_pin_loc]) - self.add_path(pin_layer, [right_loc, right_pin_loc]) - def add_layout_pins(self): for x in self.get_inouts(): @@ -212,5 +184,4 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): in_loc = in_pin.rc() self.add_path(out_pin.layer, [out_loc, mid_loc, in_loc]) - self.route_unused_wordlines() From 500327d59ba077d38932699171bd034972315d42 Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Fri, 4 Sep 2020 02:24:18 -0700 Subject: [PATCH 10/83] Fixed import in simulation and fixed names in functional --- compiler/characterizer/functional.py | 4 ++++ compiler/characterizer/simulation.py | 1 + 2 files changed, 5 insertions(+) diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index 67e0d224..395c612b 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -38,6 +38,7 @@ class functional(simulation): if not self.num_spare_cols: self.num_spare_cols = 0 + self.probe_address, self.probe_data = '0'*self.addr_size,0 self.set_corner(corner) self.set_spice_constants() self.set_stimulus_variables() @@ -47,6 +48,8 @@ class functional(simulation): self.add_graph_exclusions() self.create_graph() self.set_internal_spice_names() + self.q_name, self.qbar_name = self.get_bit_name() + debug.info(2, "q name={}\nqbar name={}".format(self.q_name, self.qbar_name)) # Number of checks can be changed self.num_cycles = 15 @@ -433,6 +436,7 @@ class functional(simulation): self.sram_spc_name = "X{}".format(self.sram.name) self.sram.build_graph(self.graph, self.sram_spc_name, self.pins) + #FIXME: Similar function to delay.py, refactor this def get_bit_name(self): """ Get a bit cell name """ (cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, 0, 0) diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index 9768e241..b73af4f6 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -15,6 +15,7 @@ from .trim_spice import * from .charutils import * import utils from globals import OPTS +from sram_factory import factory class simulation(): From 1269bf6e16d7b3639c0a61d1e8a5f66771204749 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 4 Sep 2020 13:06:58 -0700 Subject: [PATCH 11/83] Global bitcell working --- compiler/modules/bank.py | 2 +- compiler/modules/bitcell_base_array.py | 11 +-- compiler/modules/global_bitcell_array.py | 91 ++++++++++++++--------- compiler/modules/local_bitcell_array.py | 4 +- compiler/modules/replica_bitcell_array.py | 62 +++++++++------ 5 files changed, 102 insertions(+), 68 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index a0b6c9b5..fb909465 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -439,7 +439,7 @@ class bank(design.design): for port in self.all_ports: self.port_data_inst[port]=self.add_inst(name="port_data{}".format(port), mod=self.port_data[port]) - + import pdb; pdb.set_trace() temp = [] temp.extend(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)]) temp.extend(self.bitcell_array.get_bitline_names(port)) diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 00ea49b0..9f27f5b4 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -115,7 +115,7 @@ class bitcell_base_array(design.design): def get_all_wordline_names(self, port=None): """ Return all the wordline names """ temp = [] - temp.extend(self.get_dummy_wordline_names(0)) + temp.extend(self.get_dummy_wordline_names()) temp.extend(self.get_rbl_wordline_names(0)) if port == None: temp.extend(self.all_wordline_names) @@ -123,17 +123,14 @@ class bitcell_base_array(design.design): temp.extend(self.wordline_names[port]) if len(self.all_ports) > 1: temp.extend(self.get_rbl_wordline_names(1)) - temp.extend(self.get_dummy_wordline_names(1)) + temp.extend(self.get_dummy_wordline_names()) return temp - def get_dummy_wordline_names(self, port=None): + def get_dummy_wordline_names(self): """ Return the ACTIVE WL for the given dummy port. """ - if port == None: - return self.all_dummy_row_wordline_names - else: - return self.dummy_row_wordline_names[port] + return self.dummy_row_wordline_names def add_layout_pins(self): """ Add the layout pins """ diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index d5e5678b..319a85cc 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -22,16 +22,14 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): """ def __init__(self, rows, cols, name=""): # The total of all columns will be the number of columns - super().__init__(name=name, rows=rows, cols=cols, column_offset=0) - self.cols = cols - self.num_cols = sum(cols) - self.col_offsets = [0] + list(cumsum(self.cols)[:-1]) - self.rows = rows + super().__init__(name=name, rows=rows, cols=sum(cols), column_offset=0) + self.column_sizes = cols + self.col_offsets = [0] + list(cumsum(cols)[:-1]) debug.check(len(self.all_ports)<=2, "Only support dual port or less in global bitcell array.") self.rbl = [1, 1 if len(self.all_ports)>1 else 0] - self.left_rbl = self.rbl[0] - self.right_rbl = self.rbl[1] + self.add_left_rbl = self.rbl[0] + self.add_right_rbl = self.rbl[1] self.create_netlist() if not OPTS.netlist_only: @@ -59,32 +57,24 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): """ Add the modules used in this design """ self.local_mods = [] - if self.cols == 1: - la = factory.create(module_type="local_bitcell_array", rows=self.rows, cols=self.cols[0], rbl=self.rbl, add_rbl=[self.left_rbl, self.right_rbl]) + if len(self.column_sizes) == 1: + la = factory.create(module_type="local_bitcell_array", rows=self.row_size, cols=self.column_sizes[0], rbl=self.rbl, add_rbl=[self.add_left_rbl, self.add_right_rbl]) self.add_mod(la) self.local_mods.append(la) return - for i, cols in enumerate(self.cols): + for i, cols in enumerate(self.column_sizes): # Always add the left RBLs to the first subarray and the right RBLs to the last subarray if i == 0: - la = factory.create(module_type="local_bitcell_array", rows=self.rows, cols=cols, rbl=self.rbl, add_rbl=[self.left_rbl, 0]) - elif i == len(self.cols) - 1: - la = factory.create(module_type="local_bitcell_array", rows=self.rows, cols=cols, rbl=self.rbl, add_rbl=[0, self.right_rbl]) + la = factory.create(module_type="local_bitcell_array", rows=self.row_size, cols=cols, rbl=self.rbl, add_rbl=[self.add_left_rbl, 0]) + elif i == len(self.column_sizes) - 1: + la = factory.create(module_type="local_bitcell_array", rows=self.row_size, cols=cols, rbl=self.rbl, add_rbl=[0, self.add_right_rbl]) else: - la = factory.create(module_type="local_bitcell_array", rows=self.rows, cols=cols, rbl=self.rbl, add_rbl=[0, 0]) + la = factory.create(module_type="local_bitcell_array", rows=self.row_size, cols=cols, rbl=self.rbl, add_rbl=[0, 0]) self.add_mod(la) self.local_mods.append(la) - # We make these on our own and don't use the base names - def create_all_wordline_names(self): - pass - - # We make these on our own and don't use the base names - def create_all_bitline_names(self): - pass - def add_pins(self): self.add_bitline_pins() @@ -94,37 +84,55 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): self.add_pin("gnd", "GROUND") def add_bitline_pins(self): - self.bitline_names = [] + self.bitline_names = [[] for x in self.all_ports] + self.rbl_bitline_names = [[] for x in self.all_ports] for port in self.all_ports: - self.bitline_names.append("rbl_bl_{0}_{1}".format(port, 0)) - self.bitline_names.append("rbl_br_{0}_{1}".format(port, 0)) + self.bitline_names[port].append("rbl_bl_{}_0".format(port)) + self.rbl_bitline_names[port].append("rbl_bl_{}_0".format(port)) + for port in self.all_ports: + self.bitline_names[port].append("rbl_br_{}_0".format(port)) + self.rbl_bitline_names[port].append("rbl_br_{}_0".format(port)) - for col in range(self.num_cols): + for col in range(self.column_size): for port in self.all_ports: - self.bitline_names.append("bl_{0}_{1}".format(port, col)) - self.bitline_names.append("br_{0}_{1}".format(port, col)) + self.bitline_names[port].append("bl_{0}_{1}".format(port, col)) + for port in self.all_ports: + self.bitline_names[port].append("br_{0}_{1}".format(port, col)) if len(self.all_ports) > 1: for port in self.all_ports: - self.bitline_names.append("rbl_bl_{0}_{1}".format(port, 1)) - self.bitline_names.append("rbl_br_{0}_{1}".format(port, 1)) + self.bitline_names[port].append("rbl_bl_{}_1".format(port)) + self.rbl_bitline_names[port].append("rbl_bl_{}_1".format(port)) + for port in self.all_ports: + self.bitline_names[port].append("rbl_br_{}_1".format(port)) + self.rbl_bitline_names[port].append("rbl_br_{}_1".format(port)) - self.add_pin_list(self.bitline_names, "INOUT") + # Make a flat list too + self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] + + self.add_pin_list(self.all_bitline_names, "INOUT") def add_wordline_pins(self): - self.wordline_names = [] + self.dummy_row_wordline_names = [[] for x in self.all_ports] + self.rbl_wordline_names = [] + + self.wordline_names = [] + self.wordline_names.append("rbl_wl_0_0") + # This is to keep it the same as a plain replica_bitline_array + self.rbl_wordline_names.append("rbl_wl_0_0") # Regular WLs - for row in range(self.rows): + for row in range(self.row_size): for port in self.all_ports: self.wordline_names.append("wl_{0}_{1}".format(port, row)) if len(self.all_ports) > 1: self.wordline_names.append("rbl_wl_1_1") + self.rbl_wordline_names.append("rbl_wl_1_1") self.add_pin_list(self.wordline_names, "INPUT") @@ -141,9 +149,10 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): temp = [] if col == 0: temp.append("rbl_bl_0_0") - temp.append("rbl_br_0_0") if len(self.all_ports) > 1: temp.append("rbl_bl_1_0") + temp.append("rbl_br_0_0") + if len(self.all_ports) > 1: temp.append("rbl_br_1_0") port_inouts = [x for x in mod.get_inouts() if x.startswith("bl") or x.startswith("br")] @@ -161,8 +170,8 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): if len(self.all_ports) > 1 and mod == self.local_mods[-1]: temp.append("rbl_bl_0_1") - temp.append("rbl_br_0_1") temp.append("rbl_bl_1_1") + temp.append("rbl_br_0_1") temp.append("rbl_br_1_1") for port in self.all_ports: @@ -228,14 +237,22 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): new_name = "{0}_{1}".format(base_name, col + col_value) self.copy_layout_pin(inst, pin_name, new_name) + # Replica wordlines + self.copy_layout_pin(self.local_insts[0], "rbl_wl_0_0") + if len(self.all_ports) > 1: + self.copy_layout_pin(self.local_insts[-1], "rbl_wl_1_1") # Replica bitlines self.copy_layout_pin(self.local_insts[0], "rbl_bl_0_0") self.copy_layout_pin(self.local_insts[0], "rbl_br_0_0") if len(self.all_ports) > 1: - self.copy_layout_pin(self.local_insts[-1], "rbl_bl_1_0") - self.copy_layout_pin(self.local_insts[-1], "rbl_br_1_0") + self.copy_layout_pin(self.local_insts[0], "rbl_bl_1_0") + self.copy_layout_pin(self.local_insts[0], "rbl_br_1_0") + self.copy_layout_pin(self.local_insts[-1], "rbl_bl_0_0", "rbl_bl_0_1") + self.copy_layout_pin(self.local_insts[-1], "rbl_br_0_0", "rbl_br_0_1") + self.copy_layout_pin(self.local_insts[-1], "rbl_bl_1_0", "rbl_bl_1_1") + self.copy_layout_pin(self.local_insts[-1], "rbl_br_1_0", "rbl_br_1_1") for inst in self.insts: self.copy_power_pins(inst, "vdd") diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index b125fb01..d3881830 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -100,8 +100,8 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): wordline_inputs += [self.bitcell_array.get_rbl_wordline_names(1)[1]] self.wordline_names.append(wordline_inputs) self.driver_wordline_outputs.append([x + "i" for x in self.wordline_names[-1]]) - - self.all_array_wordline_inputs = [x + "i" for x in self.bitcell_array.get_all_wordline_names() if x != "gnd"] + + self.all_array_wordline_inputs = [x + "i" for x in self.bitcell_array.get_inputs() if "wl" in x] self.bitline_names = self.bitcell_array.bitline_names self.all_array_bitline_names = self.bitcell_array.get_all_bitline_names() diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 894b4460..efbc14cf 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -195,6 +195,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.rbl_bitline_names.append([]) for port in self.all_ports: self.rbl_bitline_names[-1].append("rbl_bl_{0}_{1}".format(port, x)) + for port in self.all_ports: self.rbl_bitline_names[-1].append("rbl_br_{0}_{1}".format(port, x)) # Make a flat list too @@ -218,12 +219,18 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.wordline_names = [] # Replica wordlines by port self.rbl_wordline_names = [] + # Wordlines to ground + self.gnd_wordline_names = [] self.dummy_row_wordline_names = ["gnd"] * len(self.col_cap.get_wordline_names()) for port in range(self.left_rbl + self.right_rbl): - wordline_names=["rbl_wl_{0}_{1}".format(x, port) for x in self.all_ports] - self.rbl_wordline_names.append(wordline_names) + self.rbl_wordline_names.append([]) + for x in self.all_ports: + self.rbl_wordline_names[-1].append("rbl_wl_{0}_{1}".format(x, port)) + if x != port: + self.gnd_wordline_names.append("rbl_wl_{0}_{1}".format(x, port)) + self.all_rbl_wordline_names = [x for sl in self.rbl_wordline_names for x in sl] for port in self.all_ports: @@ -235,17 +242,17 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.replica_array_wordline_names = [] self.replica_array_wordline_names.extend(self.dummy_row_wordline_names) for p in range(self.left_rbl): - self.replica_array_wordline_names.extend(self.rbl_wordline_names[p]) + self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[p]]) self.replica_array_wordline_names.extend(self.all_wordline_names) for p in range(self.left_rbl, self.left_rbl + self.right_rbl): - self.replica_array_wordline_names.extend(self.rbl_wordline_names[p]) + self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[p]]) self.replica_array_wordline_names.extend(self.dummy_row_wordline_names) for port in range(self.left_rbl): - self.add_pin_list(self.rbl_wordline_names[port], "INPUT") + self.add_pin(self.rbl_wordline_names[port][0], "INPUT") self.add_pin_list(self.all_wordline_names, "INPUT") for port in range(self.left_rbl, self.left_rbl + self.right_rbl): - self.add_pin_list(self.rbl_wordline_names[port], "INPUT") + self.add_pin(self.rbl_wordline_names[port][1], "INPUT") def create_instances(self): """ Create the module instances used in this design """ @@ -273,7 +280,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): for port in range(self.left_rbl + self.right_rbl): self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port), mod=self.dummy_row)) - self.connect_inst(self.rbl_wordline_names[port] + supplies) + self.connect_inst([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[port]] + supplies) # Top/bottom dummy rows or col caps self.dummy_row_insts = [] @@ -370,7 +377,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def add_layout_pins(self): """ Add the layout pins """ - + # All wordlines # Main array wl and bl/br for pin_name in self.all_wordline_names: @@ -381,6 +388,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): offset=pin.ll().scale(0, 1), width=self.width, height=pin.height()) + for pin_name in self.all_bitline_names: pin_list = self.bitcell_array_inst.get_pins(pin_name) for pin in pin_list: @@ -394,6 +402,8 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # even though the column is in another local bitcell array) for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()): + if wl_name in self.gnd_wordline_names: + continue pin = inst.get_pin(pin_name) self.add_layout_pin(text=wl_name, layer=pin.layer, @@ -446,23 +456,33 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def route_unused_wordlines(self): """ Connect the unused RBL and dummy wordlines to gnd """ + # This grounds all the dummy row word lines for inst in self.dummy_row_insts: for wl_name in self.col_cap.get_wordline_names(): - pin = inst.get_pin(wl_name) - pin_layer = pin.layer - layer_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer)) - left_pin_loc = vector(self.dummy_col_insts[0].lx(), pin.cy()) - right_pin_loc = vector(self.dummy_col_insts[1].rx(), pin.cy()) + self.ground_pin(inst, wl_name) - # Place the pins a track outside of the array - left_loc = left_pin_loc - vector(layer_pitch, 0) - right_loc = right_pin_loc + vector(layer_pitch, 0) - self.add_power_pin("gnd", left_loc, directions=("H", "H")) - self.add_power_pin("gnd", right_loc, directions=("H", "H")) + # Ground the unused replica wordlines + for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): + for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()): + if wl_name in self.gnd_wordline_names: + self.ground_pin(inst, pin_name) - # Add a path to connect to the array - self.add_path(pin_layer, [left_loc, left_pin_loc]) - self.add_path(pin_layer, [right_loc, right_pin_loc]) + def ground_pin(self, inst, name): + pin = inst.get_pin(name) + pin_layer = pin.layer + layer_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer)) + left_pin_loc = vector(self.dummy_col_insts[0].lx(), pin.cy()) + right_pin_loc = vector(self.dummy_col_insts[1].rx(), pin.cy()) + + # Place the pins a track outside of the array + left_loc = left_pin_loc - vector(layer_pitch, 0) + right_loc = right_pin_loc + vector(layer_pitch, 0) + self.add_power_pin("gnd", left_loc, directions=("H", "H")) + self.add_power_pin("gnd", right_loc, directions=("H", "H")) + + # Add a path to connect to the array + self.add_path(pin_layer, [left_loc, left_pin_loc]) + self.add_path(pin_layer, [right_loc, right_pin_loc]) def gen_bl_wire(self): if OPTS.netlist_only: From 8e91ec1770fe8ddcc15465c3b5f0f8b11777393d Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 8 Sep 2020 13:31:50 -0700 Subject: [PATCH 12/83] Add check_pins function --- compiler/base/design.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/base/design.py b/compiler/base/design.py index ee985fec..96e5f26b 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -26,6 +26,12 @@ class design(hierarchy_design): self.setup_layer_constants() self.setup_multiport_constants() + def check_pins(self): + for pin_name in self.pins: + pins = self.get_pins(pin_name) + for pin in pins: + print(pin_name, pin) + def setup_layer_constants(self): """ These are some layer constants used From af22e438f121853d878021a55ff3e810f522198e Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Tue, 8 Sep 2020 18:40:39 -0700 Subject: [PATCH 13/83] Added option to output an extended configuration file that includes defaults. --- compiler/options.py | 2 ++ compiler/sram/sram.py | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/compiler/options.py b/compiler/options.py index d97ea300..8d8e3b42 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -93,6 +93,8 @@ class options(optparse.Values): trim_netlist = False # Run with extracted parasitics use_pex = False + # Output config with all options + output_extended_config = False ################### diff --git a/compiler/sram/sram.py b/compiler/sram/sram.py index 8cf926c6..6b5d117d 100644 --- a/compiler/sram/sram.py +++ b/compiler/sram/sram.py @@ -63,6 +63,18 @@ class sram(): def verilog_write(self, name): self.s.verilog_write(name) + def extended_config_write(self, name): + """Dump config file with all options. + Include defaults and anything changed by input config.""" + f = open(name, "w") + var_dict = dict((name, getattr(OPTS, name)) for name in dir(OPTS) if not name.startswith('__') and not callable(getattr(OPTS, name))) + for var_name, var_value in var_dict.items(): + if isinstance(var_value, str): + f.write(str(var_name) + " = " + "\"" + str(var_value) + "\"\n") + else: + f.write(str(var_name) + " = " + str(var_value)+ "\n") + f.close() + def save(self): """ Save all the output files while reporting time to do it as well. """ @@ -137,3 +149,11 @@ class sram(): debug.print_raw("Verilog: Writing to {0}".format(vname)) self.verilog_write(vname) print_time("Verilog", datetime.datetime.now(), start_time) + + # Write out options if specified + if OPTS.output_extended_config: + start_time = datetime.datetime.now() + oname = OPTS.output_path + OPTS.output_name + "_extended.py" + debug.print_raw("Extended Config: Writing to {0}".format(oname)) + self.extended_config_write(oname) + print_time("Extended Config", datetime.datetime.now(), start_time) \ No newline at end of file From 7bb21fb73f39322826a0e9de5f2bcb83c0c0651c Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 9 Sep 2020 11:54:46 -0700 Subject: [PATCH 14/83] Updates to local and global arrays to make bitline and wordlines consistent. --- compiler/modules/bank.py | 23 +- compiler/modules/bitcell_array.py | 9 +- compiler/modules/bitcell_base_array.py | 44 ++-- compiler/modules/dummy_array.py | 4 + compiler/modules/global_bitcell_array.py | 84 +++---- compiler/modules/local_bitcell_array.py | 143 +++++++---- compiler/modules/replica_bitcell_array.py | 231 +++++++++--------- .../14_replica_bitcell_array_1rw_1r_test.py | 11 +- .../15_local_bitcell_array_1rw_1r_test.py | 15 +- compiler/tests/15_local_bitcell_array_test.py | 4 +- 10 files changed, 304 insertions(+), 264 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index fb909465..57b3f383 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -392,7 +392,9 @@ class bank(design.design): self.bitcell_array = factory.create(module_type="replica_bitcell_array", cols=self.num_cols + self.num_spare_cols, rows=self.num_rows, - rbl=[1, 1 if len(self.all_ports)>1 else 0]) + rbl=[1, 1 if len(self.all_ports)>1 else 0], + left_rbl=[0], + right_rbl=[1] if len(self.all_ports) > 1 else []) self.add_mod(self.bitcell_array) if(self.num_banks > 1): @@ -408,19 +410,14 @@ class bank(design.design): # bit lines (left to right) # vdd # gnd - import pdb; pdb.set_trace() - temp = self.bitcell_array.get_all_bitline_names() + temp = self.bitcell_array.get_inouts() - wordline_names = self.bitcell_array.get_all_wordline_names() + wordline_names = self.bitcell_array.get_inputs() # Rename the RBL WL to the enable name for port in self.all_ports: - rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port) - wordline_names = [x.replace(rbl_wl_name[port], "wl_en{0}".format(port)) for x in wordline_names] - # Connect the other RBL WL to gnd - wordline_names = ["gnd" if x.startswith("rbl_wl") else x for x in wordline_names] - # Connect the dummy WL to gnd - wordline_names = ["gnd" if x.startswith("dummy") else x for x in wordline_names] + rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)[port] + wordline_names = [x.replace(rbl_wl_name, "wl_en{0}".format(port)) for x in wordline_names] temp.extend(wordline_names) temp.append("vdd") @@ -439,7 +436,6 @@ class bank(design.design): for port in self.all_ports: self.port_data_inst[port]=self.add_inst(name="port_data{}".format(port), mod=self.port_data[port]) - import pdb; pdb.set_trace() temp = [] temp.extend(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)]) temp.extend(self.bitcell_array.get_bitline_names(port)) @@ -978,16 +974,15 @@ class bank(design.design): def route_unused_wordlines(self): """ Connect the unused RBL and dummy wordlines to gnd """ gnd_wl_names = [] - + return # Connect unused RBL WL to gnd # All RBL WL names array_rbl_names = set(self.bitcell_array.get_rbl_wordline_names()) - dummy_rbl_names = set(self.bitcell_array.get_dummy_wordline_names()) # List of used RBL WL names rbl_wl_names = set() for port in self.all_ports: rbl_wl_names.add(self.bitcell_array.get_rbl_wordline_names(port)[port]) - gnd_wl_names = list((array_rbl_names - rbl_wl_names) | dummy_rbl_names) + gnd_wl_names = list((array_rbl_names - rbl_wl_names)) for wl_name in gnd_wl_names: pin = self.bitcell_array_inst.get_pin(wl_name) diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 81f1062f..a5d09ab6 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -5,6 +5,7 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # +import debug from bitcell_base_array import bitcell_base_array from tech import drc, spice from globals import OPTS @@ -18,11 +19,17 @@ class bitcell_array(bitcell_base_array): """ def __init__(self, rows, cols, column_offset=0, name=""): super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name) + debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) + self.add_comment("rows: {0} cols: {1}".format(rows, cols)) + # This will create a default set of bitline/wordline names + self.create_all_bitline_names() + self.create_all_wordline_names() + self.create_netlist() if not OPTS.netlist_only: self.create_layout() - + # We don't offset this because we need to align # the replica bitcell in the control logic # self.offset_all_coordinates() diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 9f27f5b4..91363560 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -18,7 +18,6 @@ class bitcell_base_array(design.design): def __init__(self, name, rows, cols, column_offset): super().__init__(name) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) - self.add_comment("rows: {0} cols: {1}".format(rows, cols)) self.column_size = cols self.row_size = rows @@ -27,13 +26,16 @@ class bitcell_base_array(design.design): # Bitcell for port names only self.cell = factory.create(module_type="bitcell") - # This will create a default set of bitline/wordline names - # They may get over-riden in the super module - self.create_all_bitline_names() - self.create_all_wordline_names() + self.wordline_names = [[] for port in self.all_ports] + self.all_wordline_names = [] + self.bitline_names = [[] for port in self.all_ports] + self.all_bitline_names = [] + self.rbl_bitline_names = [[] for port in self.all_ports] + self.all_rbl_bitline_names = [] + self.rbl_wordline_names = [[] for port in self.all_ports] + self.all_rbl_wordline_names = [] def create_all_bitline_names(self): - self.bitline_names = [[] for port in self.all_ports] for col in range(self.column_size): for port in self.all_ports: self.bitline_names[port].extend(["bl_{0}_{1}".format(port, col), @@ -45,7 +47,6 @@ class bitcell_base_array(design.design): # return [prefix + x for x in self.all_wordline_names] def create_all_wordline_names(self): - self.wordline_names = [[] for port in self.all_ports] for row in range(self.row_size): for port in self.all_ports: self.wordline_names[port].append("wl_{0}_{1}".format(port, row)) @@ -73,8 +74,7 @@ class bitcell_base_array(design.design): def get_rbl_wordline_names(self, port=None): """ - Return the ACTIVE WL for the given RBL port. - Inactive will be set to gnd. + Return the WL for the given RBL port. """ if port == None: return self.all_rbl_wordline_names @@ -82,7 +82,7 @@ class bitcell_base_array(design.design): return self.rbl_wordline_names[port] def get_rbl_bitline_names(self, port=None): - """ Return the BL for the given RBL port """ + """ Return all the BL for the given RBL port """ if port == None: return self.all_rbl_bitline_names else: @@ -95,14 +95,16 @@ class bitcell_base_array(design.design): else: return self.bitline_names[port] - def get_all_bitline_names(self): - """ Return ALL the bitline names (including dummy and rbl) """ + def get_all_bitline_names(self, port=None): + """ Return ALL the bitline names (including rbl) """ temp = [] - if self.add_left_rbl > 0: - temp.extend(self.get_rbl_bitline_names(0)) - temp.extend(self.get_bitline_names()) - if self.add_right_rbl > 0: - temp.extend(self.get_rbl_bitline_names(self.add_left_rbl)) + temp.extend(self.get_rbl_bitline_names(0)) + if port == None: + temp.extend(self.all_bitline_names) + else: + temp.extend(self.bitline_names[port]) + if len(self.all_ports) > 1: + temp.extend(self.get_rbl_bitline_names(1)) return temp def get_wordline_names(self, port=None): @@ -115,7 +117,6 @@ class bitcell_base_array(design.design): def get_all_wordline_names(self, port=None): """ Return all the wordline names """ temp = [] - temp.extend(self.get_dummy_wordline_names()) temp.extend(self.get_rbl_wordline_names(0)) if port == None: temp.extend(self.all_wordline_names) @@ -123,15 +124,8 @@ class bitcell_base_array(design.design): temp.extend(self.wordline_names[port]) if len(self.all_ports) > 1: temp.extend(self.get_rbl_wordline_names(1)) - temp.extend(self.get_dummy_wordline_names()) return temp - def get_dummy_wordline_names(self): - """ - Return the ACTIVE WL for the given dummy port. - """ - return self.dummy_row_wordline_names - def add_layout_pins(self): """ Add the layout pins """ diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py index 37ce0ba4..0fd7d648 100644 --- a/compiler/modules/dummy_array.py +++ b/compiler/modules/dummy_array.py @@ -16,6 +16,10 @@ class dummy_array(bitcell_base_array): super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name) self.mirror = mirror + # This will create a default set of bitline/wordline names + self.create_all_bitline_names() + self.create_all_wordline_names() + self.create_netlist() if not OPTS.netlist_only: self.create_layout() diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index 319a85cc..fa2718bc 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -18,7 +18,6 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): Creates a global bitcell array. Rows is an integer number for all local arrays. Cols is a list of the array widths. - add_left_rbl and add_right_ """ def __init__(self, rows, cols, name=""): # The total of all columns will be the number of columns @@ -28,8 +27,6 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): debug.check(len(self.all_ports)<=2, "Only support dual port or less in global bitcell array.") self.rbl = [1, 1 if len(self.all_ports)>1 else 0] - self.add_left_rbl = self.rbl[0] - self.add_right_rbl = self.rbl[1] self.create_netlist() if not OPTS.netlist_only: @@ -58,19 +55,35 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): self.local_mods = [] if len(self.column_sizes) == 1: - la = factory.create(module_type="local_bitcell_array", rows=self.row_size, cols=self.column_sizes[0], rbl=self.rbl, add_rbl=[self.add_left_rbl, self.add_right_rbl]) + la = factory.create(module_type="local_bitcell_array", + rows=self.row_size, + cols=self.column_sizes[0], + rbl=self.rbl, + left_rbl=[0], + right_rbl=[1]) self.add_mod(la) self.local_mods.append(la) return - + for i, cols in enumerate(self.column_sizes): # Always add the left RBLs to the first subarray and the right RBLs to the last subarray if i == 0: - la = factory.create(module_type="local_bitcell_array", rows=self.row_size, cols=cols, rbl=self.rbl, add_rbl=[self.add_left_rbl, 0]) - elif i == len(self.column_sizes) - 1: - la = factory.create(module_type="local_bitcell_array", rows=self.row_size, cols=cols, rbl=self.rbl, add_rbl=[0, self.add_right_rbl]) + la = factory.create(module_type="local_bitcell_array", + rows=self.row_size, + cols=cols, + rbl=self.rbl, + left_rbl=[0]) + elif i == len(self.column_sizes) - 1 and len(self.all_ports) > 1: + la = factory.create(module_type="local_bitcell_array", + rows=self.row_size, + cols=cols, + rbl=self.rbl, + right_rbl=[1]) else: - la = factory.create(module_type="local_bitcell_array", rows=self.row_size, cols=cols, rbl=self.rbl, add_rbl=[0, 0]) + la = factory.create(module_type="local_bitcell_array", + rows=self.row_size, + cols=cols, + rbl=self.rbl) self.add_mod(la) self.local_mods.append(la) @@ -88,10 +101,8 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): self.rbl_bitline_names = [[] for x in self.all_ports] for port in self.all_ports: - self.bitline_names[port].append("rbl_bl_{}_0".format(port)) self.rbl_bitline_names[port].append("rbl_bl_{}_0".format(port)) for port in self.all_ports: - self.bitline_names[port].append("rbl_br_{}_0".format(port)) self.rbl_bitline_names[port].append("rbl_br_{}_0".format(port)) for col in range(self.column_size): @@ -102,10 +113,8 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): if len(self.all_ports) > 1: for port in self.all_ports: - self.bitline_names[port].append("rbl_bl_{}_1".format(port)) self.rbl_bitline_names[port].append("rbl_bl_{}_1".format(port)) for port in self.all_ports: - self.bitline_names[port].append("rbl_br_{}_1".format(port)) self.rbl_bitline_names[port].append("rbl_br_{}_1".format(port)) # Make a flat list too @@ -138,8 +147,6 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): def create_instances(self): """ Create the module instances used in this design """ - - self.local_insts = [] for col, mod in zip(self.col_offsets, self.local_mods): name = "la_{0}".format(col) @@ -193,32 +200,8 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): def route(self): - # Route the global wordlines (assumes pins all line up) - for port in self.all_ports: - port_inputs = [x for x in self.local_mods[0].get_inputs() if "wl_{}".format(port) in x] - for i, pin_name in enumerate(port_inputs): - pins = [x.get_pin(pin_name) for x in self.local_insts] - - y_offset = pins[0].cy() - if port == 0: - y_offset -= 1.5 * self.m3_pitch - else: - y_offset += 1.5 * self.m3_pitch - - start_offset = vector(pins[0].lx(), y_offset) - end_offset = vector(pins[-1].rx(), y_offset) - self.add_layout_pin_segment_center(text=pin_name, - layer="m3", - start=start_offset, - end=end_offset) - - for pin in pins: - self.add_via_stack_center(from_layer=pin.layer, - to_layer="m3", - offset=pin.center()) - end_offset = vector(pin.cx(), y_offset) - self.add_path("m3", [pin.center(), end_offset]) - + pass + def add_layout_pins(self): # Regular bitlines @@ -237,10 +220,13 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): new_name = "{0}_{1}".format(base_name, col + col_value) self.copy_layout_pin(inst, pin_name, new_name) - # Replica wordlines - self.copy_layout_pin(self.local_insts[0], "rbl_wl_0_0") - if len(self.all_ports) > 1: - self.copy_layout_pin(self.local_insts[-1], "rbl_wl_1_1") + for wl_name in self.local_mods[0].get_inputs(): + left_pin = self.local_insts[0].get_pin(wl_name) + right_pin = self.local_insts[-1].get_pin(wl_name) + self.add_layout_pin_segment_center(text=wl_name, + layer=left_pin.layer, + start=left_pin.lc(), + end=right_pin.rc()) # Replica bitlines self.copy_layout_pin(self.local_insts[0], "rbl_bl_0_0") @@ -249,10 +235,10 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): if len(self.all_ports) > 1: self.copy_layout_pin(self.local_insts[0], "rbl_bl_1_0") self.copy_layout_pin(self.local_insts[0], "rbl_br_1_0") - self.copy_layout_pin(self.local_insts[-1], "rbl_bl_0_0", "rbl_bl_0_1") - self.copy_layout_pin(self.local_insts[-1], "rbl_br_0_0", "rbl_br_0_1") - self.copy_layout_pin(self.local_insts[-1], "rbl_bl_1_0", "rbl_bl_1_1") - self.copy_layout_pin(self.local_insts[-1], "rbl_br_1_0", "rbl_br_1_1") + self.copy_layout_pin(self.local_insts[-1], "rbl_bl_0_1") + self.copy_layout_pin(self.local_insts[-1], "rbl_br_0_1") + self.copy_layout_pin(self.local_insts[-1], "rbl_bl_1_1") + self.copy_layout_pin(self.local_insts[-1], "rbl_br_1_1") for inst in self.insts: self.copy_power_pins(inst, "vdd") diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index d3881830..c805b9e4 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -18,18 +18,21 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): This can either be a single aray on its own if there is no hierarchical WL or it can be combined into a larger array with hierarchical WL. """ - def __init__(self, rows, cols, rbl, add_rbl=None, name=""): + def __init__(self, rows, cols, rbl, left_rbl=[], right_rbl=[], name=""): super().__init__(name=name, rows=rows, cols=cols, column_offset=0) - debug.info(2, "create local array of size {} rows x {} cols words".format(rows, cols)) + debug.info(2, "Creating {0} {1}x{2} rbl: {3} left_rbl: {4} right_rbl: {5}".format(name, + rows, + cols, + rbl, + left_rbl, + right_rbl)) self.rows = rows self.cols = cols self.rbl = rbl - if add_rbl == None: - self.add_rbl = rbl - else: - self.add_rbl = add_rbl - + self.left_rbl = left_rbl + self.right_rbl = right_rbl + debug.check(len(self.all_ports) < 3, "Local bitcell array only supports dual port or less.") self.create_netlist() @@ -39,7 +42,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): # We don't offset this because we need to align # the replica bitcell in the control logic # self.offset_all_coordinates() - + def create_netlist(self): """ Create and connect the netlist """ self.add_modules() @@ -67,53 +70,51 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): cols=self.cols, rows=self.rows, rbl=self.rbl, - add_rbl=self.add_rbl) + left_rbl=self.left_rbl, + right_rbl=self.right_rbl) self.add_mod(self.bitcell_array) self.wl_array = factory.create(module_type="wordline_buffer_array", rows=self.rows + 1, cols=self.cols) self.add_mod(self.wl_array) - - # We make these on our own and don't use the base names - def create_all_wordline_names(self): - pass - - # We make these on our own and don't use the base names - def create_all_bitline_names(self): - pass def add_pins(self): - # Inputs to the wordline driver (by port) - self.wordline_names = [] # Outputs from the wordline driver (by port) self.driver_wordline_outputs = [] # Inputs to the bitcell array (by port) self.array_wordline_inputs = [] - for port in self.all_ports: - wordline_inputs = [] - if port == 0: - wordline_inputs += [self.bitcell_array.get_rbl_wordline_names(0)[0]] - wordline_inputs += self.bitcell_array.get_wordline_names(port) - if port == 1: - wordline_inputs += [self.bitcell_array.get_rbl_wordline_names(1)[1]] - self.wordline_names.append(wordline_inputs) - self.driver_wordline_outputs.append([x + "i" for x in self.wordline_names[-1]]) - - self.all_array_wordline_inputs = [x + "i" for x in self.bitcell_array.get_inputs() if "wl" in x] - + self.wordline_names = self.bitcell_array.wordline_names + self.all_wordline_names = self.bitcell_array.all_wordline_names + self.bitline_names = self.bitcell_array.bitline_names - self.all_array_bitline_names = self.bitcell_array.get_all_bitline_names() + self.all_bitline_names = self.bitcell_array.all_bitline_names + self.rbl_wordline_names = self.bitcell_array.rbl_wordline_names + self.all_rbl_wordline_names = self.bitcell_array.all_rbl_wordline_names + + self.rbl_bitline_names = self.bitcell_array.rbl_bitline_names + self.all_rbl_bitline_names = self.bitcell_array.all_rbl_bitline_names + + self.all_array_wordline_inputs = [x + "i" for x in self.bitcell_array.get_all_wordline_names()] + # Arrays are always: # bit lines (left to right) # word lines (bottom to top) # vdd # gnd - self.add_pin_list(self.all_array_bitline_names, "INOUT") + for port in self.left_rbl: + self.add_pin_list(self.rbl_bitline_names[port], "INOUT") + self.add_pin_list(self.all_bitline_names, "INOUT") + for port in self.right_rbl: + self.add_pin_list(self.rbl_bitline_names[port], "INOUT") + for port in range(self.rbl[0]): + self.add_pin(self.rbl_wordline_names[port][port], "INPUT") for port in self.all_ports: self.add_pin_list(self.wordline_names[port], "INPUT") + for port in range(self.rbl[0], self.rbl[0] + self.rbl[1]): + self.add_pin(self.rbl_wordline_names[port][port], "INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") @@ -121,15 +122,41 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): """ Create the module instances used in this design """ self.wl_insts = [] + self.driver_wordline_outputs = [] for port in self.all_ports: self.wl_insts.append(self.add_inst(name="wl_driver", mod=self.wl_array)) - self.connect_inst(self.wordline_names[port] + self.driver_wordline_outputs[port] + ["vdd", "gnd"]) + temp = [] + temp += [self.get_rbl_wordline_names(port)[port]] + if port == 0: + temp += self.get_wordline_names(port) + else: + temp += self.get_wordline_names(port)[::-1] + self.driver_wordline_outputs.append([x + "i" for x in temp]) + + temp += self.driver_wordline_outputs[-1] + temp += ["vdd", "gnd"] + + self.connect_inst(temp) self.bitcell_array_inst = self.add_inst(name="array", mod=self.bitcell_array) + temp = [] + for port in self.left_rbl: + temp += self.get_rbl_bitline_names(port) + temp += self.all_bitline_names + for port in self.right_rbl: + temp += self.get_rbl_bitline_names(port) - self.connect_inst(self.all_array_bitline_names + self.all_array_wordline_inputs + ["vdd", "gnd"]) + wl_temp = [] + for port in range(self.rbl[0]): + wl_temp += [self.get_rbl_wordline_names(port)[port]] + wl_temp += self.get_wordline_names() + for port in range(self.rbl[0], sum(self.rbl)): + wl_temp += [self.get_rbl_wordline_names(port)[port]] + temp += [x + "i" for x in wl_temp] + temp += ["vdd", "gnd"] + self.connect_inst(temp) def place(self): """ Place the bitcelll array to the right of the wl driver. """ @@ -143,8 +170,8 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): if len(self.all_ports) > 1: self.wl_insts[1].place(vector(self.bitcell_array_inst.rx() + self.wl_array.width + driver_to_array_spacing, - 2 * self.cell.height), - mirror="MY") + 2 * self.cell.height + self.wl_array.height), + mirror="XY") self.height = self.bitcell_array.height self.width = max(self.bitcell_array_inst.rx(), max([x.rx() for x in self.wl_insts])) @@ -154,10 +181,6 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): for x in self.get_inouts(): self.copy_layout_pin(self.bitcell_array_inst, x) - for port in self.all_ports: - for (x, y) in zip(self.wordline_names[port], self.wl_array.get_inputs()): - self.copy_layout_pin(self.wl_insts[port], y, x) - supply_insts = [*self.wl_insts, self.bitcell_array_inst] for pin_name in ["vdd", "gnd"]: for inst in supply_insts: @@ -169,8 +192,44 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): def route(self): + # Route the global wordlines for port in self.all_ports: - for (driver_name, net_name) in zip(self.wl_insts[port].mod.get_outputs(), self.driver_wordline_outputs[port]): + if port == 0: + wordline_names = [self.get_rbl_wordline_names(port)[port]] + self.get_wordline_names(port) + else: + wordline_names = [self.get_rbl_wordline_names(port)[port]] + self.get_wordline_names(port)[::-1] + + wordline_pins = self.wl_array.get_inputs() + + for (wl_name, in_pin_name) in zip(wordline_names, wordline_pins): + # wl_pin = self.bitcell_array_inst.get_pin(wl_name) + in_pin = self.wl_insts[port].get_pin(in_pin_name) + + y_offset = in_pin.cy() + if port == 0: + y_offset -= 1.5 * self.m3_pitch + else: + y_offset += 1.5 * self.m3_pitch + + self.add_layout_pin_segment_center(text=wl_name, + layer="m3", + start=vector(0, y_offset), + end=vector(self.width, y_offset)) + + mid = vector(in_pin.cx(), y_offset) + self.add_path("m2", [in_pin.center(), mid]) + + self.add_via_stack_center(from_layer=in_pin.layer, + to_layer="m2", + offset=in_pin.center()) + self.add_via_center(self.m2_stack, + offset=mid) + + # Route the buffers + for port in self.all_ports: + driver_outputs = self.driver_wordline_outputs[port] + + for (driver_name, net_name) in zip(self.wl_insts[port].mod.get_outputs(), driver_outputs): array_name = net_name[:-1] out_pin = self.wl_insts[port].get_pin(driver_name) in_pin = self.bitcell_array_inst.get_pin(array_name) diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index efbc14cf..0091c20b 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -21,39 +21,37 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): Requires a regular bitcell array, replica bitcell, and dummy bitcell (Bl/BR disconnected). """ - def __init__(self, rows, cols, rbl, name, add_rbl=None): + def __init__(self, rows, cols, rbl, name, left_rbl=[], right_rbl=[]): super().__init__(name, rows, cols, column_offset=0) - debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) + debug.info(1, "Creating {0} {1} x {2} rbls: {3} left_rbl: {4} right_rbl: {5}".format(self.name, + rows, + cols, + rbl, + left_rbl, + right_rbl)) self.add_comment("rows: {0} cols: {1}".format(rows, cols)) + self.add_comment("rbl: {0} left_rbl: {1} right_rbl: {2}".format(rbl, left_rbl, right_rbl)) self.column_size = cols self.row_size = rows # This is how many RBLs are in all the arrays self.rbl = rbl - self.left_rbl = rbl[0] - self.right_rbl = rbl[1] - # This is how many RBLs are added to THIS array - if add_rbl == None: - self.add_left_rbl = rbl[0] - self.add_right_rbl = rbl[1] - else: - self.add_left_rbl = add_rbl[0] - self.add_right_rbl = add_rbl[1] - for a, b in zip(add_rbl, rbl): - debug.check(a <= b, - "Invalid number of RBLs for port configuration.") - - debug.check(sum(rbl) <= len(self.all_ports), + # This specifies which RBL to put on the left or right + # by port number + self.left_rbl = left_rbl + self.right_rbl = right_rbl + self.rbls = self.left_rbl + self.right_rbl + + debug.check(sum(rbl) == len(self.all_ports), + "Invalid number of RBLs for port configuration.") + debug.check(sum(rbl) >= len(self.left_rbl) + len(self.right_rbl), "Invalid number of RBLs for port configuration.") # Two dummy rows plus replica even if we don't add the column self.extra_rows = 2 + sum(rbl) # Two dummy cols plus replica if we add the column - self.extra_cols = 2 + self.add_left_rbl + self.add_right_rbl + self.extra_cols = 2 + len(self.left_rbl) + len(self.right_rbl) - self.create_all_bitline_names() - self.create_all_wordline_names() - self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -94,37 +92,45 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Bitcell array self.bitcell_array = factory.create(module_type="bitcell_array", - column_offset=1 + self.add_left_rbl, + column_offset=1 + len(self.left_rbl), cols=self.column_size, rows=self.row_size) self.add_mod(self.bitcell_array) # Replica bitlines self.replica_columns = {} - for bit in range(self.add_left_rbl + self.add_right_rbl): - # Creating left_rbl - if bit < self.add_left_rbl: + + for port in self.all_ports: + if port in self.left_rbl: + # We will always have self.rbl[0] rows of replica wordlines below + # the array. # These go from the top (where the bitcell array starts ) down - replica_bit = self.left_rbl - bit - # Creating right_rbl - else: + replica_bit = self.rbl[0] - port + elif port in self.right_rbl: + + # We will always have self.rbl[0] rows of replica wordlines below + # the array. # These go from the bottom up - replica_bit = self.left_rbl + self.row_size + 1 + bit + replica_bit = self.rbl[0] + self.row_size + 1 + port + else: + continue + # If we have an odd numer on the bottom - column_offset = self.left_rbl + 1 - self.replica_columns[bit] = factory.create(module_type="replica_column", - rows=self.row_size, - rbl=self.rbl, - column_offset=column_offset, - replica_bit=replica_bit) - self.add_mod(self.replica_columns[bit]) + column_offset = self.rbl[0] + 1 + + self.replica_columns[port] = factory.create(module_type="replica_column", + rows=self.row_size, + rbl=self.rbl, + column_offset=column_offset, + replica_bit=replica_bit) + self.add_mod(self.replica_columns[port]) # Dummy row self.dummy_row = factory.create(module_type="dummy_array", cols=self.column_size, rows=1, # dummy column + left replica column - column_offset=1 + self.add_left_rbl, + column_offset=1 + len(self.left_rbl), mirror=0) self.add_mod(self.dummy_row) @@ -140,7 +146,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): cols=self.column_size, rows=1, # dummy column + left replica column(s) - column_offset=1 + self.add_left_rbl, + column_offset=1 + len(self.left_rbl), mirror=0) self.add_mod(self.col_cap) @@ -151,7 +157,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): cols=1, column_offset=0, rows=self.row_size + self.extra_rows, - mirror=(self.left_rbl + 1) % 2) + mirror=(self.rbl[0] + 1) % 2) self.add_mod(self.row_cap_left) self.row_cap_right = factory.create(module_type=row_cap_module_type, @@ -160,9 +166,9 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # + left replica column(s) # + bitcell columns # + right replica column(s) - column_offset = 1 + self.add_left_rbl + self.column_size + self.add_right_rbl, + column_offset = 1 + len(self.left_rbl) + self.column_size + len(self.right_rbl), rows=self.row_size + self.extra_rows, - mirror=(self.left_rbl + 1) %2) + mirror=(self.rbl[0] + 1) %2) self.add_mod(self.row_cap_right) def add_pins(self): @@ -186,73 +192,55 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.add_pin("gnd", "GROUND") def add_bitline_pins(self): - # Regular bitline names by port - self.bitline_names = [] - # Replica bitlines by port - self.rbl_bitline_names = [] - - for x in range(self.add_left_rbl + self.add_right_rbl): - self.rbl_bitline_names.append([]) + # The bit is which port the RBL is for + for bit in self.rbls: for port in self.all_ports: - self.rbl_bitline_names[-1].append("rbl_bl_{0}_{1}".format(port, x)) - for port in self.all_ports: - self.rbl_bitline_names[-1].append("rbl_br_{0}_{1}".format(port, x)) - + self.rbl_bitline_names[bit].append("rbl_bl_{0}_{1}".format(port, bit)) + self.rbl_bitline_names[bit].append("rbl_br_{0}_{1}".format(port, bit)) # Make a flat list too self.all_rbl_bitline_names = [x for sl in self.rbl_bitline_names for x in sl] - for port in self.all_ports: - bitline_names = self.bitcell_array.get_bitline_names(port) - self.bitline_names.append(bitline_names) + self.bitline_names = self.bitcell_array.bitline_names # Make a flat list too self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] - for port in range(self.add_left_rbl): + for port in self.left_rbl: self.add_pin_list(self.rbl_bitline_names[port], "INOUT") self.add_pin_list(self.all_bitline_names, "INOUT") - for port in range(self.add_left_rbl, self.add_left_rbl + self.add_right_rbl): + for port in self.right_rbl: self.add_pin_list(self.rbl_bitline_names[port], "INOUT") def add_wordline_pins(self): - # Regular wordlines by port - self.wordline_names = [] - # Replica wordlines by port - self.rbl_wordline_names = [] # Wordlines to ground self.gnd_wordline_names = [] - self.dummy_row_wordline_names = ["gnd"] * len(self.col_cap.get_wordline_names()) - - for port in range(self.left_rbl + self.right_rbl): - self.rbl_wordline_names.append([]) - for x in self.all_ports: - self.rbl_wordline_names[-1].append("rbl_wl_{0}_{1}".format(x, port)) - if x != port: - self.gnd_wordline_names.append("rbl_wl_{0}_{1}".format(x, port)) + for port in self.all_ports: + for bit in self.all_ports: + self.rbl_wordline_names[port].append("rbl_wl_{0}_{1}".format(port, bit)) + if bit != port: + self.gnd_wordline_names.append("rbl_wl_{0}_{1}".format(port, bit)) self.all_rbl_wordline_names = [x for sl in self.rbl_wordline_names for x in sl] - for port in self.all_ports: - wordline_names = self.bitcell_array.get_wordline_names(port) - self.wordline_names.append(wordline_names) - self.all_wordline_names = [x for sl in zip(*self.wordline_names) for x in sl] + self.wordline_names = self.bitcell_array.wordline_names + self.all_wordline_names = self.bitcell_array.all_wordline_names # All wordlines including dummy and RBL self.replica_array_wordline_names = [] - self.replica_array_wordline_names.extend(self.dummy_row_wordline_names) - for p in range(self.left_rbl): - self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[p]]) + self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap.get_wordline_names())) + for bit in range(self.rbl[0]): + self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[bit]]) self.replica_array_wordline_names.extend(self.all_wordline_names) - for p in range(self.left_rbl, self.left_rbl + self.right_rbl): - self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[p]]) - self.replica_array_wordline_names.extend(self.dummy_row_wordline_names) + for bit in range(self.rbl[1]): + self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[self.rbl[0] + bit]]) + self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap.get_wordline_names())) - for port in range(self.left_rbl): - self.add_pin(self.rbl_wordline_names[port][0], "INPUT") + for port in range(self.rbl[0]): + self.add_pin(self.rbl_wordline_names[port][port], "INPUT") self.add_pin_list(self.all_wordline_names, "INPUT") - for port in range(self.left_rbl, self.left_rbl + self.right_rbl): - self.add_pin(self.rbl_wordline_names[port][1], "INPUT") + for port in range(self.rbl[0], self.rbl[0] + self.rbl[1]): + self.add_pin(self.rbl_wordline_names[port][port], "INPUT") def create_instances(self): """ Create the module instances used in this design """ @@ -269,27 +257,30 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Replica columns self.replica_col_insts = [] - for port in range(self.add_left_rbl + self.add_right_rbl): - self.replica_col_insts.append(self.add_inst(name="replica_col_{}".format(port), - mod=self.replica_columns[port])) - self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + supplies) + for port in self.all_ports: + if port in self.rbls: + self.replica_col_insts.append(self.add_inst(name="replica_col_{}".format(port), + mod=self.replica_columns[port])) + self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + supplies) + else: + self.replica_col_insts.append(None) # Dummy rows under the bitcell array (connected with with the replica cell wl) self.dummy_row_replica_insts = [] # Note, this is the number of left and right even if we aren't adding the columns to this bitcell array! - for port in range(self.left_rbl + self.right_rbl): + for port in self.all_ports: self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port), - mod=self.dummy_row)) + mod=self.dummy_row)) self.connect_inst([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[port]] + supplies) # Top/bottom dummy rows or col caps self.dummy_row_insts = [] self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot", - mod=self.col_cap)) - self.connect_inst(self.dummy_row_wordline_names + supplies) + mod=self.col_cap)) + self.connect_inst(["gnd"] * len(self.col_cap.get_wordline_names()) + supplies) self.dummy_row_insts.append(self.add_inst(name="dummy_row_top", mod=self.col_cap)) - self.connect_inst(self.dummy_row_wordline_names + supplies) + self.connect_inst(["gnd"] * len(self.col_cap.get_wordline_names()) + supplies) # Left/right Dummy columns self.dummy_col_insts = [] @@ -318,7 +309,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Array was at (0, 0) but move everything so it is at the lower left # We move DOWN the number of left RBL even if we didn't add the column to this bitcell array - self.translate_all(self.bitcell_offset.scale(-1 - self.add_left_rbl, -1 - self.left_rbl)) + self.translate_all(self.bitcell_offset.scale(-1 - len(self.left_rbl), -1 - self.rbl[0])) self.add_layout_pins() @@ -332,47 +323,47 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): """ Add replica columns on left and right of array """ # Grow from left to right, toward the array - for bit in range(self.add_left_rbl): - offset = self.bitcell_offset.scale(-self.add_left_rbl + bit, -self.left_rbl - 1) - self.replica_col_insts[bit].place(offset) + for bit, port in enumerate(self.left_rbl): + offset = self.bitcell_offset.scale(-len(self.left_rbl) + bit, -self.rbl[0] - 1) + self.replica_col_insts[port].place(offset) # Grow to the right of the bitcell array, array outward - for bit in range(self.add_right_rbl): - offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.left_rbl - 1) - self.replica_col_insts[self.add_left_rbl + bit].place(offset) + for bit, port in enumerate(self.right_rbl): + offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.rbl[0] - 1) + self.replica_col_insts[port].place(offset) # Replica dummy rows # Add the dummy rows even if we aren't adding the replica column to this bitcell array # These grow up, toward the array - for bit in range(self.left_rbl): - self.dummy_row_replica_insts[bit].place(offset=self.bitcell_offset.scale(0, -self.left_rbl + bit + (-self.left_rbl + bit) % 2), - mirror="MX" if (-self.left_rbl + bit) % 2 else "R0") + for bit in range(self.rbl[0]): + self.dummy_row_replica_insts[bit].place(offset=self.bitcell_offset.scale(0, -self.rbl[0] + bit + (-self.rbl[0] + bit) % 2), + mirror="MX" if (-self.rbl[0] + bit) % 2 else "R0") # These grow up, away from the array - for bit in range(self.right_rbl): - self.dummy_row_replica_insts[self.left_rbl + bit].place(offset=self.bitcell_offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul(), - mirror="MX" if bit % 2 else "R0") + for bit in range(self.rbl[1]): + self.dummy_row_replica_insts[self.rbl[0] + bit].place(offset=self.bitcell_offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul(), + mirror="MX" if bit % 2 else "R0") def add_end_caps(self): """ Add dummy cells or end caps around the array """ # FIXME: These depend on the array size itself # Far top dummy row (first row above array is NOT flipped) - flip_dummy = self.right_rbl % 2 - dummy_row_offset = self.bitcell_offset.scale(0, self.right_rbl + flip_dummy) + self.bitcell_array_inst.ul() + flip_dummy = self.rbl[1] % 2 + dummy_row_offset = self.bitcell_offset.scale(0, self.rbl[1] + flip_dummy) + self.bitcell_array_inst.ul() self.dummy_row_insts[1].place(offset=dummy_row_offset, mirror="MX" if flip_dummy else "R0") # FIXME: These depend on the array size itself # Far bottom dummy row (first row below array IS flipped) - flip_dummy = (self.left_rbl + 1) % 2 - dummy_row_offset = self.bitcell_offset.scale(0, -self.left_rbl - 1 + flip_dummy) + flip_dummy = (self.rbl[0] + 1) % 2 + dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - 1 + flip_dummy) self.dummy_row_insts[0].place(offset=dummy_row_offset, mirror="MX" if flip_dummy else "R0") # Far left dummy col # Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array - dummy_col_offset = self.bitcell_offset.scale(-self.add_left_rbl - 1, -self.left_rbl - 1) + dummy_col_offset = self.bitcell_offset.scale(-len(self.left_rbl) - 1, -self.rbl[0] - 1) self.dummy_col_insts[0].place(offset=dummy_col_offset) # Far right dummy col # Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array - dummy_col_offset = self.bitcell_offset.scale(self.add_right_rbl, -self.left_rbl - 1) + self.bitcell_array_inst.lr() + dummy_col_offset = self.bitcell_offset.scale(len(self.right_rbl), -self.rbl[0] - 1) + self.bitcell_array_inst.lr() self.dummy_col_insts[1].place(offset=dummy_col_offset) def add_layout_pins(self): @@ -412,14 +403,15 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): height=pin.height()) # Replica bitlines - for (names, inst) in zip(self.rbl_bitline_names, self.replica_col_insts): - for (bl_name, pin_name) in zip(names, self.replica_columns[0].all_bitline_names): - pin = inst.get_pin(pin_name) - self.add_layout_pin(text=bl_name, - layer=pin.layer, - offset=pin.ll().scale(1, 0), - width=pin.width(), - height=self.height) + if len(self.rbls) > 0: + for (names, inst) in zip(self.rbl_bitline_names, self.replica_col_insts): + for (bl_name, pin_name) in zip(names, self.replica_columns[self.rbls[0]].all_bitline_names): + pin = inst.get_pin(pin_name) + self.add_layout_pin(text=bl_name, + layer=pin.layer, + offset=pin.ll().scale(1, 0), + width=pin.width(), + height=self.height) # vdd/gnd are only connected in the perimeter cells # replica column should only have a vdd/gnd in the dummy cell on top/bottom @@ -434,7 +426,8 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): start_layer=pin.layer) for inst in self.replica_col_insts: - self.copy_layout_pin(inst, pin_name) + if inst: + self.copy_layout_pin(inst, pin_name) def analytical_power(self, corner, load): """Power of Bitcell array and bitline in nW.""" diff --git a/compiler/tests/14_replica_bitcell_array_1rw_1r_test.py b/compiler/tests/14_replica_bitcell_array_1rw_1r_test.py index b57d65a7..65bc7848 100755 --- a/compiler/tests/14_replica_bitcell_array_1rw_1r_test.py +++ b/compiler/tests/14_replica_bitcell_array_1rw_1r_test.py @@ -28,8 +28,7 @@ class replica_bitcell_array_1rw_1r_test(openram_test): a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, - rbl=[1, 1], - add_rbl=[0, 0]) + rbl=[1, 1]) self.local_check(a) debug.info(2, "Testing 4x4 left replica array for cell_1rw_1r") @@ -37,14 +36,16 @@ class replica_bitcell_array_1rw_1r_test(openram_test): cols=4, rows=4, rbl=[1, 1], - add_rbl=[1, 0]) + left_rbl=[0]) self.local_check(a) debug.info(2, "Testing 4x4 array left and right replica for cell_1rw_1r") a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, - rbl=[1, 1]) + rbl=[1, 1], + left_rbl=[0], + right_rbl=[1]) self.local_check(a) @@ -55,7 +56,7 @@ class replica_bitcell_array_1rw_1r_test(openram_test): cols=4, rows=4, rbl=[1, 1], - add_rbl=[0, 1]) + right_rbl=[1]) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/15_local_bitcell_array_1rw_1r_test.py b/compiler/tests/15_local_bitcell_array_1rw_1r_test.py index 778d4b5f..01a5c8ee 100755 --- a/compiler/tests/15_local_bitcell_array_1rw_1r_test.py +++ b/compiler/tests/15_local_bitcell_array_1rw_1r_test.py @@ -28,20 +28,21 @@ class local_bitcell_array_1rw_1r_test(openram_test): globals.setup_bitcell() debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r without replica") - a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], add_rbl=[0, 0]) + a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1]) self.local_check(a) debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r with replica column") - a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], add_rbl=[1, 0]) - self.local_check(a) - - debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r with replica column") - a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], add_rbl=[0, 1]) + a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], right_rbl=[1]) self.local_check(a) debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r with replica column") - a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], add_rbl=[1, 1]) + a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0]) self.local_check(a) + + debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r with replica column") + a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0], right_rbl=[1]) + self.local_check(a) + globals.end_openram() diff --git a/compiler/tests/15_local_bitcell_array_test.py b/compiler/tests/15_local_bitcell_array_test.py index 591b0607..45dae1a4 100755 --- a/compiler/tests/15_local_bitcell_array_test.py +++ b/compiler/tests/15_local_bitcell_array_test.py @@ -23,11 +23,11 @@ class local_bitcell_array_test(openram_test): globals.init_openram(config_file) debug.info(2, "Testing 4x4 local bitcell array for 6t_cell without replica") - a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 0], add_rbl=[0, 0]) + a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 0]) self.local_check(a) debug.info(2, "Testing 4x4 local bitcell array for 6t_cell with replica column") - a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 0], add_rbl=[1, 0]) + a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 0], left_rbl=[0]) self.local_check(a) globals.end_openram() From 12fd60e8c3101b7ffb1b52674c695c94d73e8491 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 9 Sep 2020 12:02:09 -0700 Subject: [PATCH 15/83] Fix pbitcell array test --- compiler/tests/14_replica_pbitcell_array_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/tests/14_replica_pbitcell_array_test.py b/compiler/tests/14_replica_pbitcell_array_test.py index 8376241c..1cd2d9fc 100755 --- a/compiler/tests/14_replica_pbitcell_array_test.py +++ b/compiler/tests/14_replica_pbitcell_array_test.py @@ -27,7 +27,7 @@ class replica_pbitcell_array_test(openram_test): OPTS.num_w_ports = 0 debug.info(2, "Testing 4x4 array for pbitcell") - a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], add_rbl=[1, 1]) + a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0], right_rbl=[1]) self.local_check(a) OPTS.bitcell = "pbitcell" @@ -39,7 +39,7 @@ class replica_pbitcell_array_test(openram_test): factory.reset() debug.info(2, "Testing 4x4 array for pbitcell") - a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 0], add_rbl=[1, 0]) + a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 0], left_rbl=[0]) self.local_check(a) globals.end_openram() From 138cbfac1558fc0d89b85f18d001a5665550aecb Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 9 Sep 2020 12:58:22 -0700 Subject: [PATCH 16/83] Flatten dummy pbitcell too --- technology/scn4m_subm/tech/setup.tcl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/technology/scn4m_subm/tech/setup.tcl b/technology/scn4m_subm/tech/setup.tcl index 09bbea27..40de5ac1 100644 --- a/technology/scn4m_subm/tech/setup.tcl +++ b/technology/scn4m_subm/tech/setup.tcl @@ -6,6 +6,9 @@ equate class {-circuit1 pfet} {-circuit2 p} flatten class {-circuit1 dummy_cell_6t} flatten class {-circuit1 dummy_cell_1rw_1r} flatten class {-circuit1 dummy_cell_1w_1r} +flatten class {-circuit1 dummy_pbitcell} +flatten class {-circuit1 dummy_pbitcell_0} +flatten class {-circuit1 dummy_pbitcell_1} flatten class {-circuit1 pbitcell} flatten class {-circuit1 pbitcell_0} flatten class {-circuit1 pbitcell_1} From 3062aba214a44a834c80a55a80056ecd2dd78659 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 9 Sep 2020 13:03:05 -0700 Subject: [PATCH 17/83] Fix update to exclude bits with RBLs --- compiler/modules/replica_bitcell_array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 0091c20b..7d4814fe 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -501,7 +501,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def graph_exclude_replica_col_bits(self): """Exclude all replica/dummy cells in the replica columns except the replica bit.""" - for port in range(self.left_rbl + self.right_rbl): + for port in self.left_rbl + self.right_rbl: self.replica_columns[port].exclude_all_but_replica() def get_cell_name(self, inst_name, row, col): From 3c0707e5d1aacc5fdecff702cb8f13f868272f1d Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 9 Sep 2020 13:38:13 -0700 Subject: [PATCH 18/83] Consistents of bl x port then br x port --- compiler/modules/global_bitcell_array.py | 25 +++++++++-------------- compiler/modules/replica_bitcell_array.py | 1 + 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index fa2718bc..2a6c2285 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -101,9 +101,9 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): self.rbl_bitline_names = [[] for x in self.all_ports] for port in self.all_ports: - self.rbl_bitline_names[port].append("rbl_bl_{}_0".format(port)) + self.rbl_bitline_names[0].append("rbl_bl_{}_0".format(port)) for port in self.all_ports: - self.rbl_bitline_names[port].append("rbl_br_{}_0".format(port)) + self.rbl_bitline_names[0].append("rbl_br_{}_0".format(port)) for col in range(self.column_size): for port in self.all_ports: @@ -113,14 +113,17 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): if len(self.all_ports) > 1: for port in self.all_ports: - self.rbl_bitline_names[port].append("rbl_bl_{}_1".format(port)) + self.rbl_bitline_names[1].append("rbl_bl_{}_1".format(port)) for port in self.all_ports: - self.rbl_bitline_names[port].append("rbl_br_{}_1".format(port)) + self.rbl_bitline_names[1].append("rbl_br_{}_1".format(port)) # Make a flat list too self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] - + + self.add_pin_list(self.rbl_bitline_names[0], "INPUT") self.add_pin_list(self.all_bitline_names, "INOUT") + if len(self.all_ports) > 1: + self.add_pin_list(self.rbl_bitline_names[1], "INPUT") def add_wordline_pins(self): @@ -155,12 +158,7 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): temp = [] if col == 0: - temp.append("rbl_bl_0_0") - if len(self.all_ports) > 1: - temp.append("rbl_bl_1_0") - temp.append("rbl_br_0_0") - if len(self.all_ports) > 1: - temp.append("rbl_br_1_0") + temp.extend(self.get_rbl_bitline_names(0)) port_inouts = [x for x in mod.get_inouts() if x.startswith("bl") or x.startswith("br")] for pin_name in port_inouts: @@ -176,10 +174,7 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): temp.append(new_name) if len(self.all_ports) > 1 and mod == self.local_mods[-1]: - temp.append("rbl_bl_0_1") - temp.append("rbl_bl_1_1") - temp.append("rbl_br_0_1") - temp.append("rbl_br_1_1") + temp.extend(self.get_rbl_bitline_names(1)) for port in self.all_ports: port_inputs = [x for x in mod.get_inputs() if "wl_{}".format(port) in x] diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 7d4814fe..f2095530 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -196,6 +196,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): for bit in self.rbls: for port in self.all_ports: self.rbl_bitline_names[bit].append("rbl_bl_{0}_{1}".format(port, bit)) + for port in self.all_ports: self.rbl_bitline_names[bit].append("rbl_br_{0}_{1}".format(port, bit)) # Make a flat list too self.all_rbl_bitline_names = [x for sl in self.rbl_bitline_names for x in sl] From f2313d0c739e058d4888ccef3009976b7007f913 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 10 Sep 2020 12:04:46 -0700 Subject: [PATCH 19/83] Use default names for replica_column too --- compiler/modules/bank.py | 4 +--- compiler/modules/replica_bitcell_array.py | 5 +++-- compiler/modules/replica_column.py | 20 +++++--------------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 57b3f383..545f394b 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -703,7 +703,6 @@ class bank(design.design): inst1 = self.bitcell_array_inst inst1_bl_name = [x for x in self.bitcell_array.get_bitline_names(port) if "bl" in x] inst1_br_name = [x for x in self.bitcell_array.get_bitline_names(port) if "br" in x] - inst2_bl_name = [] inst2_br_name = [] for col in range(self.num_cols): @@ -722,8 +721,7 @@ class bank(design.design): # Connect the replica bitlines - rbl_bl_names = self.bitcell_array.get_rbl_bitline_names(port)[2 * port: 2 * port + 2] - for (array_name, data_name) in zip(rbl_bl_names, ["rbl_bl", "rbl_br"]): + for (array_name, data_name) in zip(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)], ["rbl_bl", "rbl_br"]): self.connect_bitline(inst1, inst2, array_name, data_name) def route_port_data_out(self, port): diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index f2095530..40341639 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -111,7 +111,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # We will always have self.rbl[0] rows of replica wordlines below # the array. # These go from the bottom up - replica_bit = self.rbl[0] + self.row_size + 1 + port + replica_bit = self.rbl[0] + self.row_size + port else: continue @@ -406,7 +406,8 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Replica bitlines if len(self.rbls) > 0: for (names, inst) in zip(self.rbl_bitline_names, self.replica_col_insts): - for (bl_name, pin_name) in zip(names, self.replica_columns[self.rbls[0]].all_bitline_names): + pin_names = self.replica_columns[self.rbls[0]].all_bitline_names + for (bl_name, pin_name) in zip(names, pin_names): pin = inst.get_pin(pin_name) self.add_layout_pin(text=bl_name, layer=pin.layer, diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index 26a21455..e7b938e7 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -4,14 +4,14 @@ # All rights reserved. # import debug -import design +from bitcell_base_array import bitcell_base_array from tech import cell_properties from sram_factory import factory from vector import vector from globals import OPTS -class replica_column(design.design): +class replica_column(bitcell_base_array): """ Generate a replica bitline column for the replica array. Rows is the total number of rows i the main array. @@ -21,7 +21,7 @@ class replica_column(design.design): """ def __init__(self, name, rows, rbl, replica_bit, column_offset=0): - super().__init__(name) + super().__init__(rows=sum(rbl) + rows + 2, cols=1, column_offset=column_offset, name=name) self.rows = rows self.left_rbl = rbl[0] @@ -60,19 +60,9 @@ class replica_column(design.design): def add_pins(self): - self.bitline_names = [[] for port in self.all_ports] - col = 0 - for port in self.all_ports: - self.bitline_names[port].append("bl_{0}_{1}".format(port, col)) - self.bitline_names[port].append("br_{0}_{1}".format(port, col)) - self.all_bitline_names = [x for sl in self.bitline_names for x in sl] + self.create_all_bitline_names() + self.create_all_wordline_names() self.add_pin_list(self.all_bitline_names, "OUTPUT") - - self.wordline_names = [[] for port in self.all_ports] - for row in range(self.total_size): - for port in self.all_ports: - self.wordline_names[port].append("wl_{0}_{1}".format(port, row)) - self.all_wordline_names = [x for sl in zip(*self.wordline_names) for x in sl] self.add_pin_list(self.all_wordline_names, "INPUT") self.add_pin("vdd", "POWER") From 9c762634a54b90954bbb494f55cd3df3348596f1 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 10 Sep 2020 15:11:48 -0700 Subject: [PATCH 20/83] Change default options for replica_bitcell_array --- compiler/modules/bank.py | 5 +---- compiler/modules/replica_bitcell_array.py | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index aa117446..337430ae 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -390,10 +390,7 @@ class bank(design.design): else: self.bitcell_array = factory.create(module_type="replica_bitcell_array", cols=self.num_cols + self.num_spare_cols, - rows=self.num_rows, - rbl=[1, 1 if len(self.all_ports)>1 else 0], - left_rbl=[0], - right_rbl=[1] if len(self.all_ports) > 1 else []) + rows=self.num_rows) self.add_mod(self.bitcell_array) if(self.num_banks > 1): diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index f1bca739..0642157d 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -21,7 +21,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): Requires a regular bitcell array, replica bitcell, and dummy bitcell (Bl/BR disconnected). """ - def __init__(self, rows, cols, rbl, name, left_rbl=[], right_rbl=[]): + def __init__(self, rows, cols, name, rbl=None, left_rbl=[0], right_rbl=[]): super().__init__(name, rows, cols, column_offset=0) debug.info(1, "Creating {0} {1} x {2} rbls: {3} left_rbl: {4} right_rbl: {5}".format(self.name, rows, @@ -35,20 +35,26 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.column_size = cols self.row_size = rows # This is how many RBLs are in all the arrays - self.rbl = rbl + if rbl: + self.rbl = rbl + else: + self.rbl=[1, 1 if len(self.all_ports)>1 else 0] # This specifies which RBL to put on the left or right # by port number self.left_rbl = left_rbl - self.right_rbl = right_rbl + if right_rbl: + self.right_rbl = right_rbl + else: + self.right_rbl=[1] if len(self.all_ports) > 1 else [] self.rbls = self.left_rbl + self.right_rbl - debug.check(sum(rbl) == len(self.all_ports), + debug.check(sum(self.rbl) == len(self.all_ports), "Invalid number of RBLs for port configuration.") - debug.check(sum(rbl) >= len(self.left_rbl) + len(self.right_rbl), + debug.check(sum(self.rbl) >= len(self.left_rbl) + len(self.right_rbl), "Invalid number of RBLs for port configuration.") # Two dummy rows plus replica even if we don't add the column - self.extra_rows = 2 + sum(rbl) + self.extra_rows = 2 + sum(self.rbl) # Two dummy cols plus replica if we add the column self.extra_cols = 2 + len(self.left_rbl) + len(self.right_rbl) From c58741c44f8b7d5bef63115a5fc88b4422244073 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 10 Sep 2020 16:44:54 -0700 Subject: [PATCH 21/83] Updates to global array. Standardize bitcell array main array offsets. Duplicate replica interface pins in global interface pins. --- compiler/modules/bank.py | 6 ++-- compiler/modules/global_bitcell_array.py | 40 ++++++++++++++++------- compiler/modules/local_bitcell_array.py | 11 +++++++ compiler/modules/replica_bitcell_array.py | 23 +++++++++++-- 4 files changed, 62 insertions(+), 18 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 337430ae..1a16eed1 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -186,11 +186,11 @@ class bank(design.design): self.bitcell_array_right = self.bitcell_array.width # These are the offsets of the main array (excluding dummy and replica rows/cols) - self.main_bitcell_array_top = self.bitcell_array.bitcell_array_inst.uy() + self.main_bitcell_array_top = self.bitcell_array.get_main_array_top() # Just past the dummy column - self.main_bitcell_array_left = self.bitcell_array.bitcell_array_inst.lx() + self.main_bitcell_array_left = self.bitcell_array.get_main_array_left() # Just past the dummy row and replica row - self.main_bitcell_array_bottom = self.bitcell_array.bitcell_array_inst.by() + self.main_bitcell_array_bottom = self.bitcell_array.get_main_array_bottom() self.compute_instance_port0_offsets() if len(self.all_ports)==2: diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index 2a6c2285..219f30ac 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -119,6 +119,8 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): # Make a flat list too self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] + # Make a flat list too + self.all_rbl_bitline_names = [x for sl in zip(*self.rbl_bitline_names) for x in sl] self.add_pin_list(self.rbl_bitline_names[0], "INPUT") self.add_pin_list(self.all_bitline_names, "INOUT") @@ -127,26 +129,27 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): def add_wordline_pins(self): - self.dummy_row_wordline_names = [[] for x in self.all_ports] + self.rbl_wordline_names = [[] for x in self.all_ports] - self.rbl_wordline_names = [] - - self.wordline_names = [] + self.wordline_names = [[] for x in self.all_ports] - self.wordline_names.append("rbl_wl_0_0") - # This is to keep it the same as a plain replica_bitline_array - self.rbl_wordline_names.append("rbl_wl_0_0") + for bit in self.all_ports: + for port in self.all_ports: + self.rbl_wordline_names[port].append("rbl_wl_{0}_{1}".format(port, bit)) + self.all_rbl_wordline_names = [x for sl in zip(*self.rbl_wordline_names) for x in sl] + # Regular WLs for row in range(self.row_size): for port in self.all_ports: - self.wordline_names.append("wl_{0}_{1}".format(port, row)) + self.wordline_names[port].append("wl_{0}_{1}".format(port, row)) + self.all_wordline_names = [x for sl in zip(*self.wordline_names) for x in sl] + + self.add_pin_list(self.rbl_wordline_names[0], "INPUT") + self.add_pin_list(self.all_wordline_names, "INPUT") if len(self.all_ports) > 1: - self.wordline_names.append("rbl_wl_1_1") - self.rbl_wordline_names.append("rbl_wl_1_1") - - self.add_pin_list(self.wordline_names, "INPUT") + self.add_pin_list(self.rbl_wordline_names[1], "INPUT") def create_instances(self): """ Create the module instances used in this design """ @@ -238,3 +241,16 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): for inst in self.insts: self.copy_power_pins(inst, "vdd") self.copy_power_pins(inst, "gnd") + + def get_main_array_top(self): + return self.local_insts[0].offset.y + self.local_mods[0].get_main_array_top() + + def get_main_array_bottom(self): + return self.local_insts[0].offset.y + self.local_mods[0].get_main_array_bottom() + + def get_main_array_left(self): + return self.local_insts[0].offset.x + self.local_mods[0].get_main_array_left() + + def get_main_array_right(self): + return self.local_insts[-1].offset.x + self.local_mods[-1].get_main_array_right() + diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index c805b9e4..a2c32e81 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -243,4 +243,15 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): in_loc = in_pin.rc() self.add_path(out_pin.layer, [out_loc, mid_loc, in_loc]) + def get_main_array_top(self): + return self.bitcell_array_inst.offset.y + self.bitcell_array.get_main_array_top() + + def get_main_array_bottom(self): + return self.bitcell_array_inst.offset.y + self.bitcell_array.get_main_array_bottom() + + def get_main_array_left(self): + return self.bitcell_array_inst.offset.x + self.bitcell_array.get_main_array_left() + + def get_main_array_right(self): + return self.bitcell_array_inst.offset.x + self.bitcell_array.get_main_array_right() diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 0642157d..404819c3 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -21,7 +21,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): Requires a regular bitcell array, replica bitcell, and dummy bitcell (Bl/BR disconnected). """ - def __init__(self, rows, cols, name, rbl=None, left_rbl=[0], right_rbl=[]): + def __init__(self, rows, cols, rbl=None, left_rbl=None, right_rbl=None, name=""): super().__init__(name, rows, cols, column_offset=0) debug.info(1, "Creating {0} {1} x {2} rbls: {3} left_rbl: {4} right_rbl: {5}".format(self.name, rows, @@ -41,8 +41,13 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.rbl=[1, 1 if len(self.all_ports)>1 else 0] # This specifies which RBL to put on the left or right # by port number - self.left_rbl = left_rbl - if right_rbl: + # This could be an empty list + if left_rbl != None: + self.left_rbl = left_rbl + else: + self.left_rbl = [0] + # This could be an empty list + if right_rbl != None: self.right_rbl = right_rbl else: self.right_rbl=[1] if len(self.all_ports) > 1 else [] @@ -326,6 +331,18 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.DRC_LVS() + def get_main_array_top(self): + return self.bitcell_array_inst.uy() + + def get_main_array_bottom(self): + return self.bitcell_array_inst.by() + + def get_main_array_left(self): + return self.bitcell_array_inst.lx() + + def get_main_array_right(self): + return self.bitcell_array_inst.rx() + def add_replica_columns(self): """ Add replica columns on left and right of array """ From 8909ad71652527418b31bf1a6430709fd3bd15ec Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 11 Sep 2020 15:36:22 -0700 Subject: [PATCH 22/83] Update modules to use variable bit offsets. Bitcell arrays can return the bit offsets. Port data and submodules can use offsets for spacing. Default spacing for port data if no offsets given. --- compiler/modules/bank.py | 28 ++++++++++++------- compiler/modules/bitcell_base_array.py | 6 ++++ compiler/modules/global_bitcell_array.py | 10 ++++++- compiler/modules/local_bitcell_array.py | 17 +++++++---- compiler/modules/port_data.py | 14 +++++++++- compiler/modules/precharge_array.py | 23 +++++++++------ compiler/modules/replica_bitcell_array.py | 9 +++++- compiler/modules/sense_amp_array.py | 3 +- .../modules/single_level_column_mux_array.py | 13 ++++++--- compiler/modules/write_driver_array.py | 26 +++++++++-------- compiler/modules/write_mask_and_array.py | 14 +++++++--- 11 files changed, 116 insertions(+), 47 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 1a16eed1..fa03a807 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -191,11 +191,17 @@ class bank(design.design): self.main_bitcell_array_left = self.bitcell_array.get_main_array_left() # Just past the dummy row and replica row self.main_bitcell_array_bottom = self.bitcell_array.get_main_array_bottom() - + self.compute_instance_port0_offsets() if len(self.all_ports)==2: self.compute_instance_port1_offsets() - + + def get_column_offsets(self): + """ + Return an array of the x offsets of all the regular bits + """ + return self.bitcell_array.get_column_offsets() + def compute_instance_port0_offsets(self): """ Compute the instance offsets for port0 on the left/bottom of the bank. @@ -355,14 +361,6 @@ class bank(design.design): def add_modules(self): """ Add all the modules using the class loader """ - - self.port_data = [] - for port in self.all_ports: - temp_pre = factory.create(module_type="port_data", - sram_config=self.sram_config, - port=port) - self.port_data.append(temp_pre) - self.add_mod(self.port_data[port]) self.port_address = factory.create(module_type="port_address", cols=self.num_cols + self.num_spare_cols, @@ -392,6 +390,15 @@ class bank(design.design): cols=self.num_cols + self.num_spare_cols, rows=self.num_rows) self.add_mod(self.bitcell_array) + + self.port_data = [] + for port in self.all_ports: + temp_pre = factory.create(module_type="port_data", + sram_config=self.sram_config, + port=port, + bit_offsets=self.bitcell_array.get_column_offsets()) + self.port_data.append(temp_pre) + self.add_mod(self.port_data[port]) if(self.num_banks > 1): self.bank_select = factory.create(module_type="bank_select") @@ -432,6 +439,7 @@ class bank(design.design): for port in self.all_ports: self.port_data_inst[port]=self.add_inst(name="port_data{}".format(port), mod=self.port_data[port]) + temp = [] temp.extend(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)]) temp.extend(self.bitcell_array.get_bitline_names(port)) diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 91363560..0fe03494 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -206,3 +206,9 @@ class bitcell_base_array(design.design): mirror=dir_key) yoffset += self.cell.height xoffset += self.cell.width + + def get_column_offsets(self): + """ + Return an array of the x offsets of all the regular bits + """ + return [self.cell_inst[0, col].lx() for col in range(self.column_size)] diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index 219f30ac..c65de052 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -253,4 +253,12 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): def get_main_array_right(self): return self.local_insts[-1].offset.x + self.local_mods[-1].get_main_array_right() - + + def get_column_offsets(self): + """ + Return an array of the x offsets of all the regular bits + """ + offsets = [] + for inst in self.local_insts: + offsets.extend(inst.lx() + inst.mod.get_column_offsets()) + return offsets diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index a2c32e81..792e4f8b 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -244,14 +244,21 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): self.add_path(out_pin.layer, [out_loc, mid_loc, in_loc]) def get_main_array_top(self): - return self.bitcell_array_inst.offset.y + self.bitcell_array.get_main_array_top() + return self.bitcell_array_inst.by() + self.bitcell_array.get_main_array_top() def get_main_array_bottom(self): - return self.bitcell_array_inst.offset.y + self.bitcell_array.get_main_array_bottom() + return self.bitcell_array_inst.by() + self.bitcell_array.get_main_array_bottom() def get_main_array_left(self): - return self.bitcell_array_inst.offset.x + self.bitcell_array.get_main_array_left() + return self.bitcell_array_inst.lx() + self.bitcell_array.get_main_array_left() def get_main_array_right(self): - return self.bitcell_array_inst.offset.x + self.bitcell_array.get_main_array_right() - + return self.bitcell_array_inst.lx() + self.bitcell_array.get_main_array_right() + + def get_column_offsets(self): + """ + Return an array of the x offsets of all the regular bits + """ + # must add the offset of the instance + return [self.bitcell_array_inst.lx() + x for x in self.bitcell_array.get_column_offsets()] + diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index a8e4bdb2..2f5cf541 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -18,7 +18,7 @@ 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, name=""): + def __init__(self, sram_config, port, bit_offsets=None, name=""): sram_config.set_local_config(self) self.port = port @@ -30,6 +30,14 @@ class port_data(design.design): if self.num_spare_cols is None: self.num_spare_cols = 0 + if not bit_offsets: + bitcell = factory.create(module_type="bitcell") + self.bit_offsets = [] + for i in range(self.num_cols + self.num_spare_cols): + self.bit_offsets.append(i * bitcell.width) + else: + self.bit_offsets = bit_offsets + if name == "": name = "port_data_{0}".format(self.port) super().__init__(name) @@ -181,6 +189,7 @@ class port_data(design.design): # and mirroring happens correctly self.precharge_array = factory.create(module_type="precharge_array", columns=self.num_cols + self.num_spare_cols + 1, + offsets=self.bit_offsets, bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port], column_offset=self.port - 1) @@ -190,6 +199,7 @@ class port_data(design.design): # RBLs don't get a sense amp self.sense_amp_array = factory.create(module_type="sense_amp_array", word_size=self.word_size, + offsets=self.bit_offsets, words_per_row=self.words_per_row, num_spare_cols=self.num_spare_cols) self.add_mod(self.sense_amp_array) @@ -201,6 +211,7 @@ class port_data(design.design): self.column_mux_array = factory.create(module_type="column_mux_array", columns=self.num_cols, word_size=self.word_size, + offsets=self.bit_offsets, bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port]) self.add_mod(self.column_mux_array) @@ -212,6 +223,7 @@ class port_data(design.design): self.write_driver_array = factory.create(module_type="write_driver_array", columns=self.num_cols, word_size=self.word_size, + offsets=self.bit_offsets, write_size=self.write_size, num_spare_cols=self.num_spare_cols) self.add_mod(self.write_driver_array) diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index 00fe9885..10b9bba9 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -10,7 +10,7 @@ import debug from vector import vector from sram_factory import factory from globals import OPTS -from tech import layer +from tech import cell_properties class precharge_array(design.design): @@ -19,12 +19,13 @@ class precharge_array(design.design): of bit line columns, height is the height of the bit-cell array. """ - def __init__(self, name, columns, size=1, bitcell_bl="bl", bitcell_br="br", column_offset=0): + def __init__(self, name, columns, offsets=None, size=1, bitcell_bl="bl", bitcell_br="br", column_offset=0): super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("cols: {0} size: {1} bl: {2} br: {3}".format(columns, size, bitcell_bl, bitcell_br)) self.columns = columns + self.offsets = offsets self.size = size self.bitcell_bl = bitcell_bl self.bitcell_br = bitcell_br @@ -62,10 +63,11 @@ class precharge_array(design.design): self.create_insts() def create_layout(self): - self.width = self.columns * self.pc_cell.width + self.place_insts() + + self.width = self.offsets[-1] + self.pc_cell.width self.height = self.pc_cell.height - self.place_insts() self.add_layout_pins() self.add_boundary() self.DRC_LVS() @@ -112,15 +114,18 @@ class precharge_array(design.design): def place_insts(self): """ Places precharge array by horizontally tiling the precharge cell""" - from tech import cell_properties - xoffset = 0 - for i in range(self.columns): - tempx = xoffset + + # Default to single spaced columns + if not self.offsets: + self.offsets = [n * self.pc_cell.width for n in range(self.columns)] + + for i, xoffset in enumerate(self.offsets): if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2: mirror = "MY" - tempx = tempx + self.pc_cell.width + tempx = xoffset + self.pc_cell.width else: mirror = "" + tempx = xoffset offset = vector(tempx, 0) self.local_insts[i].place(offset=offset, mirror=mirror) diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 404819c3..0702522c 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -342,7 +342,14 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def get_main_array_right(self): return self.bitcell_array_inst.rx() - + + def get_column_offsets(self): + """ + Return an array of the x offsets of all the regular bits + """ + # This works because the instance of the module is placed at 0,0 + return self.bitcell_array.get_column_offsets() + def add_replica_columns(self): """ Add replica columns on left and right of array """ diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 6d0b85d2..e088df1d 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -20,7 +20,7 @@ class sense_amp_array(design.design): Dynamically generated sense amp array for all bitlines. """ - def __init__(self, name, word_size, words_per_row, num_spare_cols=None, column_offset=0): + def __init__(self, name, word_size, words_per_row, offsets=None, num_spare_cols=None, column_offset=0): super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) @@ -29,6 +29,7 @@ class sense_amp_array(design.design): self.word_size = word_size self.words_per_row = words_per_row + self.offsets = offsets if not num_spare_cols: self.num_spare_cols = 0 else: diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 267b2a6a..8a75ebea 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -11,7 +11,7 @@ from tech import layer, preferred_directions from vector import vector from sram_factory import factory from globals import OPTS -import logical_effort +from tech import cell_properties class single_level_column_mux_array(design.design): @@ -20,13 +20,14 @@ class single_level_column_mux_array(design.design): Array of column mux to read the bitlines through the 6T. """ - def __init__(self, name, columns, word_size, bitcell_bl="bl", bitcell_br="br", column_offset=0): + def __init__(self, name, columns, word_size, offsets=None, bitcell_bl="bl", bitcell_br="br", column_offset=0): super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("cols: {0} word_size: {1} bl: {2} br: {3}".format(columns, word_size, bitcell_bl, bitcell_br)) self.columns = columns self.word_size = word_size + self.offsets = offsets self.words_per_row = int(self.columns / self.word_size) self.bitcell_bl = bitcell_bl self.bitcell_br = bitcell_br @@ -116,9 +117,13 @@ class single_level_column_mux_array(design.design): "gnd"]) def place_array(self): - from tech import cell_properties + + # Default to single spaced columns + if not self.offsets: + self.offsets = [n * self.mux.width for n in range(self.columns)] + # For every column, add a pass gate - for col_num in range(self.columns): + for col_num, xoffset in enumerate(self.offsets): xoffset = col_num * self.mux.width if cell_properties.bitcell.mirror.y and (col_num + self.column_offset) % 2: mirror = "MY" diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index b7bcd6b3..b8d6a13d 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -11,6 +11,7 @@ from tech import drc from sram_factory import factory from vector import vector from globals import OPTS +from tech import cell_properties class write_driver_array(design.design): @@ -19,7 +20,7 @@ class write_driver_array(design.design): Dynamically generated write driver array of all bitlines. """ - def __init__(self, name, columns, word_size, num_spare_cols=None, write_size=None, column_offset=0): + def __init__(self, name, columns, word_size, offsets=None, num_spare_cols=None, write_size=None, column_offset=0): super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) @@ -29,6 +30,7 @@ class write_driver_array(design.design): self.columns = columns self.word_size = word_size self.write_size = write_size + self.offsets = offsets self.column_offset = column_offset self.words_per_row = int(columns / word_size) if not num_spare_cols: @@ -155,30 +157,32 @@ class write_driver_array(design.design): self.en_name + "_{0}".format(i + offset), "vdd", "gnd"]) def place_write_array(self): - from tech import cell_properties if self.bitcell.width > self.driver.width: self.driver_spacing = self.bitcell.width else: self.driver_spacing = self.driver.width - for i in range(0, self.columns, self.words_per_row): - index = int(i / self.words_per_row) - xoffset = i * self.driver_spacing - if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2: + if not self.offsets: + self.offsets = [] + for i in range(self.columns + self.num_spare_cols): + self.offsets.append(i * self.driver_spacing) + + for i, xoffset in enumerate(self.offsets[0:self.columns:self.words_per_row]): + if cell_properties.bitcell.mirror.y and (i * self.words_per_row + self.column_offset) % 2: mirror = "MY" xoffset = xoffset + self.driver.width else: mirror = "" base = vector(xoffset, 0) - self.driver_insts[index].place(offset=base, mirror=mirror) + self.driver_insts[i].place(offset=base, mirror=mirror) # place spare write drivers (if spare columns are specified) - for i in range(self.num_spare_cols): + + for i, xoffset in enumerate(self.offsets[self.columns:]): index = self.word_size + i - xoffset = (self.columns + i) * self.driver_spacing - - if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2: + + if cell_properties.bitcell.mirror.y and (index + self.column_offset) % 2: mirror = "MY" xoffset = xoffset + self.driver.width else: diff --git a/compiler/modules/write_mask_and_array.py b/compiler/modules/write_mask_and_array.py index 04563209..e2048d3d 100644 --- a/compiler/modules/write_mask_and_array.py +++ b/compiler/modules/write_mask_and_array.py @@ -18,7 +18,7 @@ class write_mask_and_array(design.design): The write mask AND array goes between the write driver array and the sense amp array. """ - def __init__(self, name, columns, word_size, write_size, column_offset=0): + def __init__(self, name, columns, word_size, write_size, offsets=None, column_offset=0): super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("columns: {0}".format(columns)) @@ -28,6 +28,7 @@ class write_mask_and_array(design.design): self.columns = columns self.word_size = word_size self.write_size = write_size + self.offsets = offsets self.column_offset = column_offset self.words_per_row = int(columns / word_size) self.num_wmasks = int(word_size / write_size) @@ -90,12 +91,17 @@ class write_mask_and_array(design.design): debug.check(self.wmask_en_len >= self.and2.width, "Write mask AND is wider than the corresponding write drivers {0} vs {1}.".format(self.and2.width, self.wmask_en_len)) - - self.width = self.bitcell.width * self.columns + if not self.offsets: + self.offsets = [] + for i in range(self.columns): + self.offsets.append(i * self.driver_spacing) + + self.width = self.offsets[-1] + self.driver_spacing self.height = self.and2.height + write_bits = self.columns / self.num_wmasks for i in range(self.num_wmasks): - base = vector(i * self.wmask_en_len, 0) + base = vector(self.offsets[int(i * write_bits)], 0) self.and2_insts[i].place(base) def add_layout_pins(self): From 4482c63d6f0c2ce29780261dcac270095db54217 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 11 Sep 2020 17:12:29 -0700 Subject: [PATCH 23/83] Fix sense amp offset index error --- compiler/modules/single_level_column_mux_array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 8a75ebea..ea1dae36 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -123,7 +123,7 @@ class single_level_column_mux_array(design.design): self.offsets = [n * self.mux.width for n in range(self.columns)] # For every column, add a pass gate - for col_num, xoffset in enumerate(self.offsets): + for col_num, xoffset in enumerate(self.offsets[0:self.columns]): xoffset = col_num * self.mux.width if cell_properties.bitcell.mirror.y and (col_num + self.column_offset) % 2: mirror = "MY" From e95ab6691658c36f1f12cb9fcdf8cab04c8a24cd Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 14 Sep 2020 12:05:45 -0700 Subject: [PATCH 24/83] Update to space according to the bitcell array. --- compiler/modules/bank.py | 23 ++++++---- compiler/modules/bitcell_base_array.py | 3 +- compiler/modules/global_bitcell_array.py | 2 +- compiler/modules/local_bitcell_array.py | 3 +- compiler/modules/port_data.py | 28 ++++++------ compiler/modules/precharge_array.py | 5 ++- compiler/modules/replica_bitcell_array.py | 7 +-- compiler/modules/sense_amp_array.py | 44 ++++++++++--------- .../modules/single_level_column_mux_array.py | 4 +- compiler/modules/write_driver_array.py | 24 ++++------ 10 files changed, 74 insertions(+), 69 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index fa03a807..d091896e 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -189,6 +189,8 @@ class bank(design.design): self.main_bitcell_array_top = self.bitcell_array.get_main_array_top() # Just past the dummy column self.main_bitcell_array_left = self.bitcell_array.get_main_array_left() + # Just past the dummy column + self.main_bitcell_array_right = self.bitcell_array.get_main_array_right() # Just past the dummy row and replica row self.main_bitcell_array_bottom = self.bitcell_array.get_main_array_bottom() @@ -200,8 +202,10 @@ class bank(design.design): """ Return an array of the x offsets of all the regular bits """ - return self.bitcell_array.get_column_offsets() - + # Assumes bitcell_array is at 0,0 + offsets = self.bitcell_array.get_column_offsets() + return offsets + def compute_instance_port0_offsets(self): """ Compute the instance offsets for port0 on the left/bottom of the bank. @@ -215,7 +219,7 @@ class bank(design.design): # LOWER RIGHT QUADRANT # Below the bitcell array - self.port_data_offsets[port] = vector(self.main_bitcell_array_left - self.bitcell_array.cell.width, 0) + self.port_data_offsets[port] = vector(0, 0) # UPPER LEFT QUADRANT # To the left of the bitcell array above the predecoders and control logic @@ -259,7 +263,7 @@ class bank(design.design): # UPPER LEFT QUADRANT # Above the bitcell array - self.port_data_offsets[port] = vector(self.main_bitcell_array_left, self.bitcell_array_top) + self.port_data_offsets[port] = vector(0, self.bitcell_array_top) # LOWER RIGHT QUADRANT # To the right of the bitcell array @@ -392,11 +396,12 @@ class bank(design.design): self.add_mod(self.bitcell_array) 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, port=port, - bit_offsets=self.bitcell_array.get_column_offsets()) + bit_offsets=self.bit_offsets) self.port_data.append(temp_pre) self.add_mod(self.port_data[port]) @@ -916,7 +921,7 @@ class bank(design.design): offset = self.column_decoder_inst[port].lr() + vector(pitch, 0) decode_pins = [self.column_decoder_inst[port].get_pin(x) for x in decode_names] - + sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)] column_mux_pins = [self.port_data_inst[port].get_pin(x) for x in sel_names] @@ -1043,10 +1048,12 @@ class bank(design.design): control_signal = self.prefix + "wl_en{}".format(port) if port % 2: pin_pos = self.port_address_inst[port].get_pin("wl_en").uc() - mid_pos = pin_pos + vector(0, 2 * self.m2_gap) # to route down to the top of the bus + control_y_offset = self.bus_pins[port][control_signal].by() + mid_pos = vector(pin_pos.x, control_y_offset + self.m1_pitch) else: pin_pos = self.port_address_inst[port].get_pin("wl_en").bc() - mid_pos = pin_pos - vector(0, 2 * self.m2_gap) # to route down to the top of the bus + control_y_offset = self.bus_pins[port][control_signal].uy() + mid_pos = vector(pin_pos.x, control_y_offset - self.m1_pitch) control_x_offset = self.bus_pins[port][control_signal].cx() control_pos = vector(control_x_offset, mid_pos.y) self.add_wire(self.m1_stack, [pin_pos, mid_pos, control_pos]) diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 0fe03494..992a5c3c 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -211,4 +211,5 @@ class bitcell_base_array(design.design): """ Return an array of the x offsets of all the regular bits """ - return [self.cell_inst[0, col].lx() for col in range(self.column_size)] + offsets = [self.cell_inst[0, col].lx() for col in range(self.column_size)] + return offsets diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index c65de052..ad3421e5 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -260,5 +260,5 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): """ offsets = [] for inst in self.local_insts: - offsets.extend(inst.lx() + inst.mod.get_column_offsets()) + offsets.extend(inst.lx() + x for x in inst.mod.get_column_offsets()) return offsets diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index 792e4f8b..71e274b2 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -260,5 +260,6 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): Return an array of the x offsets of all the regular bits """ # must add the offset of the instance - return [self.bitcell_array_inst.lx() + x for x in self.bitcell_array.get_column_offsets()] + offsets = [self.bitcell_array_inst.lx() + x for x in self.bitcell_array.get_column_offsets()] + return offsets diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 2f5cf541..0571201d 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -37,7 +37,7 @@ class port_data(design.design): self.bit_offsets.append(i * bitcell.width) else: self.bit_offsets = bit_offsets - + if name == "": name = "port_data_{0}".format(self.port) super().__init__(name) @@ -187,9 +187,19 @@ class port_data(design.design): # Precharge will be shifted left if needed # Column offset is set to port so extra column can be on left or right # and mirroring happens correctly + + # Used for names/dimensions only + self.cell = factory.create(module_type="bitcell") + + if self.port == 0: + # Append an offset on the left + precharge_bit_offsets = [self.bit_offsets[0] - self.cell.width] + self.bit_offsets + else: + # Append an offset on the right + precharge_bit_offsets = self.bit_offsets + [self.bit_offsets[-1] + self.cell.width] self.precharge_array = factory.create(module_type="precharge_array", columns=self.num_cols + self.num_spare_cols + 1, - offsets=self.bit_offsets, + offsets=precharge_bit_offsets, bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port], column_offset=self.port - 1) @@ -231,6 +241,7 @@ class port_data(design.design): # RBLs don't get a write mask self.write_mask_and_array = factory.create(module_type="write_mask_and_array", columns=self.num_cols, + offsets=self.bit_offsets, word_size=self.word_size, write_size=self.write_size) self.add_mod(self.write_mask_and_array) @@ -423,21 +434,15 @@ class port_data(design.design): vertical_port_order.append(self.write_driver_array_inst) vertical_port_order.append(self.write_mask_and_array_inst) - # Add one column for the the RBL - if self.port==0: - x_offset = self.bitcell.width - else: - x_offset = 0 - vertical_port_offsets = 5 * [None] - self.width = x_offset + self.width = 0 self.height = 0 for i, p in enumerate(vertical_port_order): if p == None: continue self.height += (p.height + self.m2_gap) self.width = max(self.width, p.width) - vertical_port_offsets[i] = vector(x_offset, self.height) + vertical_port_offsets[i] = vector(0, self.height) # Reversed order self.write_mask_and_offset = vertical_port_offsets[4] @@ -445,9 +450,6 @@ class port_data(design.design): self.sense_amp_offset = vertical_port_offsets[2] self.column_mux_offset = vertical_port_offsets[1] self.precharge_offset = vertical_port_offsets[0] - # Shift the precharge left if port 0 - if self.precharge_offset and self.port == 0: - self.precharge_offset -= vector(x_offset, 0) def place_instances(self): """ Place the instances. """ diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index 10b9bba9..7f101ac9 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -118,7 +118,7 @@ class precharge_array(design.design): # Default to single spaced columns if not self.offsets: self.offsets = [n * self.pc_cell.width for n in range(self.columns)] - + for i, xoffset in enumerate(self.offsets): if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2: mirror = "MY" @@ -129,4 +129,5 @@ class precharge_array(design.design): offset = vector(tempx, 0) self.local_insts[i].place(offset=offset, mirror=mirror) - xoffset = xoffset + self.pc_cell.width + + diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 0702522c..f6b50f0c 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -321,7 +321,8 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Array was at (0, 0) but move everything so it is at the lower left # We move DOWN the number of left RBL even if we didn't add the column to this bitcell array - self.translate_all(self.bitcell_offset.scale(-1 - len(self.left_rbl), -1 - self.rbl[0])) + array_offset = self.bitcell_offset.scale(1 + len(self.left_rbl), 1 + self.rbl[0]) + self.translate_all(array_offset.scale(-1, -1)) self.add_layout_pins() @@ -347,8 +348,8 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): """ Return an array of the x offsets of all the regular bits """ - # This works because the instance of the module is placed at 0,0 - return self.bitcell_array.get_column_offsets() + offsets = [x + self.bitcell_array_inst.lx() for x in self.bitcell_array.get_column_offsets()] + return offsets def add_replica_columns(self): """ Add replica columns on left and right of array """ diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index e088df1d..932306da 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -6,12 +6,11 @@ # All rights reserved. # import design -from tech import drc from vector import vector from sram_factory import factory import debug from globals import OPTS -import logical_effort +from tech import cell_properties class sense_amp_array(design.design): @@ -29,6 +28,7 @@ class sense_amp_array(design.design): self.word_size = word_size self.words_per_row = words_per_row + self.columns = word_size * words_per_row self.offsets = offsets if not num_spare_cols: self.num_spare_cols = 0 @@ -69,16 +69,15 @@ class sense_amp_array(design.design): self.create_sense_amp_array() def create_layout(self): - self.height = self.amp.height - - if self.bitcell.width > self.amp.width: - self.width = self.bitcell.width * (self.word_size * self.words_per_row + self.num_spare_cols) - else: - self.width = self.amp.width * (self.word_size * self.words_per_row + self.num_spare_cols) self.place_sense_amp_array() + + self.height = self.amp.height + self.width = self.local_insts[-1].rx() + self.add_layout_pins() self.route_rails() + self.add_boundary() self.DRC_LVS() @@ -112,29 +111,32 @@ class sense_amp_array(design.design): self.en_name, "vdd", "gnd"]) def place_sense_amp_array(self): - from tech import cell_properties + if self.bitcell.width > self.amp.width: + self.amp_spacing = self.bitcell.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) - for i in range(0, self.row_size, self.words_per_row): - index = int(i / self.words_per_row) - xoffset = i * self.bitcell.width - - if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2: + for i, xoffset in enumerate(self.offsets[0:self.columns:self.words_per_row]): + if cell_properties.bitcell.mirror.y and (i * self.words_per_row + self.column_offset) % 2: mirror = "MY" - xoffset = xoffset + self.amp.width + xoffset = xoffset + self.amp_spacing else: mirror = "" amp_position = vector(xoffset, 0) - self.local_insts[index].place(offset=amp_position, mirror=mirror) + 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 in range(0, self.num_spare_cols): + for i, xoffset in enumerate(self.offsets[self.columns:]): index = self.word_size + i - xoffset = ((self.word_size * self.words_per_row) + i) * self.bitcell.width - - if cell_properties.bitcell.mirror.y and (i + self.column_offset) % 2: + if cell_properties.bitcell.mirror.y and (index + self.column_offset) % 2: mirror = "MY" - xoffset = xoffset + self.amp.width + xoffset = xoffset + self.amp_width else: mirror = "" diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index ea1dae36..1be0b378 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -117,14 +117,12 @@ class single_level_column_mux_array(design.design): "gnd"]) def place_array(self): - # Default to single spaced columns if not self.offsets: self.offsets = [n * self.mux.width for n in range(self.columns)] # For every column, add a pass gate for col_num, xoffset in enumerate(self.offsets[0:self.columns]): - xoffset = col_num * self.mux.width if cell_properties.bitcell.mirror.y and (col_num + self.column_offset) % 2: mirror = "MY" xoffset = xoffset + self.mux.width @@ -168,7 +166,7 @@ class single_level_column_mux_array(design.design): self.add_layout_pin(text="sel_{}".format(j), layer=self.sel_layer, offset=offset, - width=self.mux.width * self.columns) + width=self.mux_inst[-1].rx()) def add_vertical_poly_rail(self): """ Connect the poly to the address rails """ diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index b8d6a13d..3de81888 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -68,17 +68,10 @@ class write_driver_array(design.design): def create_layout(self): - if self.bitcell.width > self.driver.width: - self.width = (self.columns + self.num_spare_cols) * self.bitcell.width - self.width_regular_cols = self.columns * self.bitcell.width - self.single_col_width = self.bitcell.width - else: - self.width = (self.columns + self.num_spare_cols) * self.driver.width - self.width_regular_cols = self.columns * self.driver.width - self.single_col_width = self.driver.width - self.height = self.driver.height - self.place_write_array() + self.width = self.driver_insts[-1].rx() + self.width_regular_cols = self.driver_insts[-self.num_spare_cols].rx() + self.height = self.driver.height self.add_layout_pins() self.add_boundary() self.DRC_LVS() @@ -109,14 +102,14 @@ class write_driver_array(design.design): self.bitcell = factory.create(module_type="bitcell") def create_write_array(self): - self.driver_insts = {} + self.driver_insts = [] w = 0 windex=0 for i in range(0, self.columns, self.words_per_row): name = "write_driver{}".format(i) index = int(i / self.words_per_row) - self.driver_insts[index]=self.add_inst(name=name, - mod=self.driver) + self.driver_insts.append(self.add_inst(name=name, + mod=self.driver)) if self.write_size: self.connect_inst([self.data_name + "_{0}".format(index), @@ -148,8 +141,8 @@ class write_driver_array(design.design): else: offset = 1 name = "write_driver{}".format(self.columns + i) - self.driver_insts[index]=self.add_inst(name=name, - mod=self.driver) + self.driver_insts.append(self.add_inst(name=name, + mod=self.driver)) self.connect_inst([self.data_name + "_{0}".format(index), self.get_bl_name() + "_{0}".format(index), @@ -178,7 +171,6 @@ class write_driver_array(design.design): self.driver_insts[i].place(offset=base, mirror=mirror) # place spare write drivers (if spare columns are specified) - for i, xoffset in enumerate(self.offsets[self.columns:]): index = self.word_size + i From c12720a93fe2ba11443f771797f8bfcb0f048d46 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 14 Sep 2020 12:53:59 -0700 Subject: [PATCH 25/83] Extend pin correct length in new array. --- compiler/modules/sense_amp_array.py | 6 +++--- compiler/modules/write_driver_array.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 932306da..a46ccebf 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -28,7 +28,7 @@ class sense_amp_array(design.design): self.word_size = word_size self.words_per_row = words_per_row - self.columns = word_size * words_per_row + self.num_cols = word_size * words_per_row self.offsets = offsets if not num_spare_cols: self.num_spare_cols = 0 @@ -121,7 +121,7 @@ class sense_amp_array(design.design): for i in range(self.num_cols + self.num_spare_cols): self.offsets.append(i * self.bitcell.width) - for i, xoffset in enumerate(self.offsets[0:self.columns:self.words_per_row]): + for i, xoffset in enumerate(self.offsets[0:self.num_cols:self.words_per_row]): if cell_properties.bitcell.mirror.y and (i * self.words_per_row + self.column_offset) % 2: mirror = "MY" xoffset = xoffset + self.amp_spacing @@ -132,7 +132,7 @@ class sense_amp_array(design.design): 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.columns:]): + for i, xoffset in enumerate(self.offsets[self.num_cols:]): index = self.word_size + i if cell_properties.bitcell.mirror.y and (index + self.column_offset) % 2: mirror = "MY" diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 3de81888..d505fbc2 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -70,7 +70,7 @@ class write_driver_array(design.design): self.place_write_array() self.width = self.driver_insts[-1].rx() - self.width_regular_cols = self.driver_insts[-self.num_spare_cols].rx() + self.width_regular_cols = self.driver_insts[-self.num_spare_cols].lx() self.height = self.driver.height self.add_layout_pins() self.add_boundary() @@ -252,7 +252,7 @@ class write_driver_array(design.design): en_pin = inst.get_pin(inst.mod.en_name) self.add_layout_pin(text=self.en_name + "_{0}".format(i + 1), layer="m1", - offset=en_pin.lr() + vector(-drc("minwidth_m1"),0)) + offset=en_pin.lr() + vector(-drc("minwidth_m1"), 0)) else: inst = self.driver_insts[0] From deaaec1ede994a3a7b51eaef3d671d1e516e8df6 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 14 Sep 2020 13:09:45 -0700 Subject: [PATCH 26/83] Fix width of write enable with spare columns --- compiler/modules/write_driver_array.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index d505fbc2..4672f715 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -70,7 +70,7 @@ class write_driver_array(design.design): self.place_write_array() self.width = self.driver_insts[-1].rx() - self.width_regular_cols = self.driver_insts[-self.num_spare_cols].lx() + self.width_regular_cols = self.driver_insts[-self.num_spare_cols - 1].rx() self.height = self.driver.height self.add_layout_pins() self.add_boundary() @@ -244,7 +244,7 @@ class write_driver_array(design.design): self.add_layout_pin(text=self.en_name + "_{0}".format(0), layer="m1", offset=en_pin.ll(), - width=self.width_regular_cols - self.words_per_row * en_pin.width()) + width=self.width_regular_cols - en_pin.lx()) # individual enables for every spare write driver for i in range(self.num_spare_cols): From 55dd4d0c47217c313da4efda838ed0e3e500f40c Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 14 Sep 2020 14:35:52 -0700 Subject: [PATCH 27/83] Global bitcell array working --- compiler/modules/bank.py | 14 ++-- compiler/modules/global_bitcell_array.py | 15 ++-- compiler/tests/19_single_bank_1rw_1r_test.py | 3 +- .../tests/19_single_bank_global_bitline.py | 74 +++++++++++++++++++ 4 files changed, 91 insertions(+), 15 deletions(-) create mode 100755 compiler/tests/19_single_bank_global_bitline.py diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index d091896e..57890a45 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -374,18 +374,18 @@ class bank(design.design): self.num_rbl = len(self.all_ports) try: - local_bitline_size = OPTS.local_bitline_size + local_array_size = OPTS.local_array_size except AttributeError: - local_bitline_size = 0 + local_array_size = 0 - if local_bitline_size > 0: + if local_array_size > 0: # Find the even multiple that satisfies the fanout with equal sized local arrays total_cols = self.num_cols + self.num_spare_cols - num_lb = floor(total_cols / local_bitline_size) - final_size = total_cols - num_lb * local_bitline_size - cols = [local_bitline_size] * (num_lb - 1) + num_lb = floor(total_cols / local_array_size) + final_size = total_cols - num_lb * local_array_size + cols = [local_array_size] * (num_lb - 1) # Add the odd bits to the last local array - cols.append(local_bitline_size + final_size) + cols.append(local_array_size + final_size) self.bitcell_array = factory.create(module_type="global_bitcell_array", cols=cols, rows=self.num_rows) diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index ad3421e5..c26e62f1 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -60,7 +60,7 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): cols=self.column_sizes[0], rbl=self.rbl, left_rbl=[0], - right_rbl=[1]) + right_rbl=[1] if len(self.all_ports) > 1 else []) self.add_mod(la) self.local_mods.append(la) return @@ -122,10 +122,10 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): # Make a flat list too self.all_rbl_bitline_names = [x for sl in zip(*self.rbl_bitline_names) for x in sl] - self.add_pin_list(self.rbl_bitline_names[0], "INPUT") + self.add_pin_list(self.rbl_bitline_names[0], "INOUT") self.add_pin_list(self.all_bitline_names, "INOUT") if len(self.all_ports) > 1: - self.add_pin_list(self.rbl_bitline_names[1], "INPUT") + self.add_pin_list(self.rbl_bitline_names[1], "INOUT") def add_wordline_pins(self): @@ -145,11 +145,12 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): self.wordline_names[port].append("wl_{0}_{1}".format(port, row)) self.all_wordline_names = [x for sl in zip(*self.wordline_names) for x in sl] - - self.add_pin_list(self.rbl_wordline_names[0], "INPUT") + + for port in range(self.rbl[0]): + self.add_pin(self.rbl_wordline_names[port][port], "INPUT") self.add_pin_list(self.all_wordline_names, "INPUT") - if len(self.all_ports) > 1: - self.add_pin_list(self.rbl_wordline_names[1], "INPUT") + for port in range(self.rbl[0], self.rbl[0] + self.rbl[1]): + self.add_pin(self.rbl_wordline_names[port][port], "INPUT") def create_instances(self): """ Create the module instances used in this design """ diff --git a/compiler/tests/19_single_bank_1rw_1r_test.py b/compiler/tests/19_single_bank_1rw_1r_test.py index 22f83f29..b60e7c98 100755 --- a/compiler/tests/19_single_bank_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_1rw_1r_test.py @@ -8,13 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + class single_bank_1rw_1r_test(openram_test): def runTest(self): diff --git a/compiler/tests/19_single_bank_global_bitline.py b/compiler/tests/19_single_bank_global_bitline.py new file mode 100755 index 00000000..ffaea6e6 --- /dev/null +++ b/compiler/tests/19_single_bank_global_bitline.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class single_bank_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + globals.setup_bitcell() + + OPTS.local_array_size = 2 + 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(module_type="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(module_type="bank", sram_config=c) + self.local_check(a) + + c.num_words=64 + c.words_per_row=4 + factory.reset() + c.recompute_sizes() + debug.info(1, "Four way column mux") + a = factory.create(module_type="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(module_type="bank", sram_config=c) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From 7b24d1f012c7ed1f20598c0a08c028147efe3ac7 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 14 Sep 2020 14:42:28 -0700 Subject: [PATCH 28/83] Use pins for write_driver dimensions --- compiler/modules/write_driver_array.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 4672f715..568b192d 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -70,7 +70,6 @@ class write_driver_array(design.design): self.place_write_array() self.width = self.driver_insts[-1].rx() - self.width_regular_cols = self.driver_insts[-self.num_spare_cols - 1].rx() self.height = self.driver.height self.add_layout_pins() self.add_boundary() @@ -239,12 +238,14 @@ class write_driver_array(design.design): elif self.num_spare_cols and not self.write_size: # shorten enable rail to accomodate those for spare write drivers - inst = self.driver_insts[0] - en_pin = inst.get_pin(inst.mod.en_name) + left_inst = self.driver_insts[0] + left_en_pin = left_inst.get_pin(inst.mod.en_name) + right_inst = self.driver_insts[-self.num_spare_cols - 1] + right_en_pin = right_inst.get_pin(inst.mod.en_name) self.add_layout_pin(text=self.en_name + "_{0}".format(0), layer="m1", - offset=en_pin.ll(), - width=self.width_regular_cols - en_pin.lx()) + offset=left_en_pin.ll(), + width=right_en_pin.rx() - left_en_pin.lx()) # individual enables for every spare write driver for i in range(self.num_spare_cols): From f25b6ffa61c3e53106da3316bd83bc9ce2df6719 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 14 Sep 2020 15:42:17 -0700 Subject: [PATCH 29/83] Make control bus height of port data --- compiler/modules/bank.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 57890a45..7634c36b 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -680,7 +680,7 @@ class bank(design.design): # 2 pitches on the right for vias/jogs to access the inputs control_bus_offset = vector(-self.m3_pitch * self.num_control_lines[0] - 2 * self.m3_pitch, self.min_y_offset) # The control bus is routed up to two pitches below the bitcell array - control_bus_length = self.main_bitcell_array_bottom - self.min_y_offset - 2 * self.m1_pitch + control_bus_length = self.port_data[0].height self.bus_pins[0] = self.create_bus(layer="m2", offset=control_bus_offset, names=self.control_signals[0], @@ -692,7 +692,7 @@ class bank(design.design): # Port 1 if len(self.all_ports)==2: # The other control bus is routed up to two pitches above the bitcell array - control_bus_length = self.max_y_offset - self.main_bitcell_array_top - 2 * self.m1_pitch + control_bus_length = self.port_data[1].height control_bus_offset = vector(self.bitcell_array_right + 2.5 * self.m3_pitch, self.max_y_offset - control_bus_length) # The bus for the right port is reversed so that the rbl_wl is closest to the array From aff3cd2aabaa9149d48a7268fcc3171e2bbdfc54 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 15 Sep 2020 09:49:00 -0700 Subject: [PATCH 30/83] Update length of control bus --- compiler/modules/bank.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 7634c36b..c7b019d7 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -680,7 +680,7 @@ class bank(design.design): # 2 pitches on the right for vias/jogs to access the inputs control_bus_offset = vector(-self.m3_pitch * self.num_control_lines[0] - 2 * self.m3_pitch, self.min_y_offset) # The control bus is routed up to two pitches below the bitcell array - control_bus_length = self.port_data[0].height + control_bus_length = self.port_data_inst[0].uy() - self.min_y_offset self.bus_pins[0] = self.create_bus(layer="m2", offset=control_bus_offset, names=self.control_signals[0], @@ -692,7 +692,7 @@ class bank(design.design): # Port 1 if len(self.all_ports)==2: # The other control bus is routed up to two pitches above the bitcell array - control_bus_length = self.port_data[1].height + control_bus_length = self.max_y_offset - self.port_data_inst[1].by() control_bus_offset = vector(self.bitcell_array_right + 2.5 * self.m3_pitch, self.max_y_offset - control_bus_length) # The bus for the right port is reversed so that the rbl_wl is closest to the array From 5e94d76127da12aa1b4391e1a0b58991b931b822 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 15 Sep 2020 13:24:38 -0700 Subject: [PATCH 31/83] Make global bitline only as wide as needed rather than whole array --- compiler/modules/local_bitcell_array.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index 71e274b2..d552d77a 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -213,8 +213,8 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): self.add_layout_pin_segment_center(text=wl_name, layer="m3", - start=vector(0, y_offset), - end=vector(self.width, y_offset)) + start=vector(self.wl_insts[port].lx(), y_offset), + end=vector(self.wl_insts[port].lx() + self.wl_array.width, y_offset)) mid = vector(in_pin.cx(), y_offset) self.add_path("m2", [in_pin.center(), mid]) From e7ad22ff69b8603af8769cd3b847d2261d5c7c6a Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 15 Sep 2020 13:38:28 -0700 Subject: [PATCH 32/83] Separate WL via from bitell array to avoid grounded WLs --- compiler/modules/bank.py | 14 ++++++++------ compiler/modules/replica_bitcell_array.py | 1 - 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index c7b019d7..51f6c19b 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -861,11 +861,13 @@ class bank(design.design): bitcell_wl_pos = bitcell_wl_pin.lc() mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * self.port_address_inst[port].rx() + 0.5 * self.bitcell_array_inst.lx(), 0) mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0.5, 1) - self.add_path(driver_wl_pin.layer, [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) + self.add_path(driver_wl_pin.layer, [driver_wl_pos, mid1, mid2]) + # Via is non-preferred direction because mid1->mid2 is non-preferred direction self.add_via_stack_center(from_layer=driver_wl_pin.layer, to_layer=bitcell_wl_pin.layer, - offset=bitcell_wl_pos, - directions=("H", "H")) + offset=mid2, + directions="nonpref") + self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos]) def route_port_address_right(self, port): """ Connecting Wordline driver output to Bitcell WL connection """ @@ -879,11 +881,11 @@ class bank(design.design): bitcell_wl_pos = bitcell_wl_pin.rc() mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * self.port_address_inst[port].lx() + 0.5 * self.bitcell_array_inst.rx(), 0) mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0, 1) - self.add_path(driver_wl_pin.layer, [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) + self.add_path(driver_wl_pin.layer, [driver_wl_pos, mid1, mid2]) self.add_via_stack_center(from_layer=driver_wl_pin.layer, to_layer=bitcell_wl_pin.layer, - offset=bitcell_wl_pos, - directions=("H", "H")) + offset=mid2) + self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos]) def route_column_address_lines(self, port): """ Connecting the select lines of column mux to the address bus """ diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index f6b50f0c..6c2d54a7 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -455,7 +455,6 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): for pin in pin_list: self.add_power_pin(name=pin_name, loc=pin.center(), - directions=("V", "V"), start_layer=pin.layer) for inst in self.replica_col_insts: From 11f2b6b8096bb9908159e6ea50b57f0aff7a8614 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 15 Sep 2020 13:39:00 -0700 Subject: [PATCH 33/83] Do not do final verification if supplies were not routed --- compiler/verify/calibre.py | 2 +- compiler/verify/magic.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 965e3557..d51e71b6 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -101,7 +101,7 @@ def write_calibre_lvs_script(cell_name, final_verification, gds_name, sp_name): # FIXME: Remove when vdd/gnd connected #'lvsAbortOnSupplyError' : 0 - if not final_verification: + if not final_verification or not OPTS.route_supplies: lvs_runset['cmnVConnectReport']=1 lvs_runset['cmnVConnectNamesState']='SOME' lvs_runset['cmnVConnectNames']='vdd gnd' diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 930316ff..2343da26 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -100,7 +100,7 @@ def write_magic_script(cell_name, extract=False, final_verification=False): pre = "#" else: pre = "" - if final_verification: + if final_verification and OPTS.route_supplies: f.write(pre + "extract unique all\n".format(cell_name)) # Hack to work around unit scales in SkyWater if OPTS.tech_name=="sky130": From 392afd4d4b0bca548ab1dce679dbf5614b0eb4ee Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 15 Sep 2020 13:46:21 -0700 Subject: [PATCH 34/83] Add unit test for hierarchical wordline. --- .../tests/20_sram_1bank_2mux_global_test.py | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100755 compiler/tests/20_sram_1bank_2mux_global_test.py diff --git a/compiler/tests/20_sram_1bank_2mux_global_test.py b/compiler/tests/20_sram_1bank_2mux_global_test.py new file mode 100755 index 00000000..4020dff9 --- /dev/null +++ b/compiler/tests/20_sram_1bank_2mux_global_test.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +#@unittest.skip("SKIPPING 20_sram_1bank_4mux_test") +class sram_1bank_2mux_global_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + OPTS.local_array_size = 8 + OPTS.route_supplies = False + c = sram_config(word_size=8, + num_words=32, + num_banks=1) + + c.words_per_row=2 + c.recompute_sizes() + debug.info(1, "Layout test for {}rw,{}r,{}w sram " + "with {} bit words, {} words, {} words per " + "row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) + a = factory.create(module_type="sram", sram_config=c) + self.local_check(a, final_verification=True) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From c7d32089f3e7dfd142b1d31267f4e86a23f80859 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 17 Sep 2020 14:45:49 -0700 Subject: [PATCH 35/83] Create RBL wordline buffer with correct polarity. --- compiler/base/hierarchy_layout.py | 10 +++ compiler/modules/bank.py | 49 ++++++------ compiler/modules/global_bitcell_array.py | 6 +- compiler/modules/hierarchical_decoder.py | 4 +- compiler/modules/port_address.py | 98 +++++++++++++++++++---- compiler/modules/wordline_buffer_array.py | 7 +- compiler/modules/wordline_driver_array.py | 6 +- compiler/options.py | 1 + compiler/pgates/pbuf.py | 2 +- compiler/pgates/wordline_driver.py | 29 +++++-- 10 files changed, 156 insertions(+), 56 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index d350c156..0cbe6e8c 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -63,6 +63,16 @@ class layout(): self.translate_all(offset) return offset + def offset_x_coordinates(self): + """ + This function is called after everything is placed to + shift the origin to the furthest left point. + Y offset is unchanged. + """ + offset = self.find_lowest_coords() + self.translate_all(offset.scale(1, 0)) + return offset + def get_gate_offset(self, x_offset, height, inv_num): """ Gets the base offset and y orientation of stacked rows of gates diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 51f6c19b..e4ac72bc 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -223,10 +223,10 @@ class bank(design.design): # UPPER LEFT QUADRANT # To the left of the bitcell array above the predecoders and control logic - x_offset = self.m2_gap + self.port_address.width + x_offset = self.m2_gap + self.port_address[port].width self.port_address_offsets[port] = vector(-x_offset, self.main_bitcell_array_bottom) - self.predecoder_height = self.port_address.predecoder_height + self.port_address_offsets[port].y + self.predecoder_height = self.port_address[port].predecoder_height + self.port_address_offsets[port].y # LOWER LEFT QUADRANT # Place the col decoder left aligned with wordline driver @@ -234,7 +234,7 @@ class bank(design.design): # control logic to allow control signals to easily pass over in M3 # by placing 1 1/4 a cell pitch down because both power connections and inputs/outputs # may be routed in M3 or M4 - x_offset = self.central_bus_width[port] + self.port_address.wordline_driver.width + x_offset = self.central_bus_width[port] + self.port_address[port].wordline_driver_array.width if self.col_addr_size > 0: x_offset += self.column_decoder.width + self.col_addr_bus_width y_offset = 1.25 * self.dff.height + self.column_decoder.height @@ -267,7 +267,7 @@ class bank(design.design): # LOWER RIGHT QUADRANT # To the right of the bitcell array - x_offset = self.bitcell_array_right + self.port_address.width + self.m2_gap + x_offset = self.bitcell_array_right + self.port_address[port].width + self.m2_gap self.port_address_offsets[port] = vector(x_offset, self.main_bitcell_array_bottom) @@ -278,7 +278,7 @@ class bank(design.design): # control logic to allow control signals to easily pass over in M3 # by placing 1 1/4 a cell pitch down because both power connections and inputs/outputs # may be routed in M3 or M4 - x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.port_address.wordline_driver.width + x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.port_address[port].wordline_driver_array.width if self.col_addr_size > 0: x_offset += self.column_decoder.width + self.col_addr_bus_width y_offset = self.bitcell_array_top + 1.25 * self.dff.height + self.column_decoder.height @@ -366,10 +366,13 @@ class bank(design.design): def add_modules(self): """ Add all the modules using the class loader """ - self.port_address = factory.create(module_type="port_address", - cols=self.num_cols + self.num_spare_cols, - rows=self.num_rows) - self.add_mod(self.port_address) + 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]) self.num_rbl = len(self.all_ports) @@ -420,13 +423,10 @@ class bank(design.design): # gnd temp = self.bitcell_array.get_inouts() - wordline_names = self.bitcell_array.get_inputs() - - # Rename the RBL WL to the enable name - for port in self.all_ports: - rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)[port] - wordline_names = [x.replace(rbl_wl_name, "wl_en{0}".format(port)) for x in wordline_names] - temp.extend(wordline_names) + temp.append("rbl_wl0") + temp.extend(self.bitcell_array.get_wordline_names()) + if len(self.all_ports) > 1: + temp.append("rbl_wl1") temp.append("vdd") temp.append("gnd") @@ -486,13 +486,15 @@ class bank(design.design): self.port_address_inst = [None] * len(self.all_ports) for port in self.all_ports: self.port_address_inst[port] = self.add_inst(name="port_address{}".format(port), - mod=self.port_address) + mod=self.port_address[port]) temp = [] for bit in range(self.row_addr_size): temp.append("addr{0}_{1}".format(port, bit + self.col_addr_size)) temp.append("wl_en{}".format(port)) - temp.extend(self.bitcell_array.get_wordline_names(port)) + wordline_names = self.bitcell_array.get_wordline_names(port) + temp.extend(wordline_names) + temp.append("rbl_wl{}".format(port)) temp.extend(["vdd", "gnd"]) self.connect_inst(temp) @@ -852,8 +854,9 @@ class bank(design.design): def route_port_address_left(self, port): """ Connecting Wordline driver output to Bitcell WL connection """ - driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] - for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port)): + driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] + ["rbl_wl"] + rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)[port] + for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port) + [rbl_wl_name]): # The mid guarantees we exit the input cell to the right. driver_wl_pin = self.port_address_inst[port].get_pin(driver_name) driver_wl_pos = driver_wl_pin.rc() @@ -1021,10 +1024,6 @@ class bank(design.design): connection.append((self.prefix + "p_en_bar{}".format(port), self.port_data_inst[port].get_pin("p_en_bar"))) - rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port) - connection.append((self.prefix + "wl_en{}".format(port), - self.bitcell_array_inst.get_pin(rbl_wl_name[port]))) - if port in self.write_ports: connection.append((self.prefix + "w_en{}".format(port), self.port_data_inst[port].get_pin("w_en"))) @@ -1045,7 +1044,7 @@ class bank(design.design): self.add_via_stack_center(from_layer=pin.layer, to_layer="m2", offset=control_pos) - + # clk to wordline_driver control_signal = self.prefix + "wl_en{}".format(port) if port % 2: diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index c26e62f1..57f4d716 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -54,6 +54,8 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): """ Add the modules used in this design """ self.local_mods = [] + # Special case of a single local array + # so it should contain the left and possibly right RBL if len(self.column_sizes) == 1: la = factory.create(module_type="local_bitcell_array", rows=self.row_size, @@ -66,19 +68,21 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): return for i, cols in enumerate(self.column_sizes): - # Always add the left RBLs to the first subarray and the right RBLs to the last subarray + # Always add the left RBLs to the first subarray if i == 0: la = factory.create(module_type="local_bitcell_array", rows=self.row_size, cols=cols, rbl=self.rbl, left_rbl=[0]) + # Add the right RBL to the last subarray elif i == len(self.column_sizes) - 1 and len(self.all_ports) > 1: la = factory.create(module_type="local_bitcell_array", rows=self.row_size, cols=cols, rbl=self.rbl, right_rbl=[1]) + # Middle subarrays do not have any RBLs else: la = factory.create(module_type="local_bitcell_array", rows=self.row_size, diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index ca26993f..21aa1c89 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -55,9 +55,9 @@ class hierarchical_decoder(design.design): self.route_decoder_bus() self.route_vdd_gnd() - self.offset_all_coordinates() + self.offset_x_coordinates() - self.width = self.and_inst[0].rx() + self.m1_space + self.width = self.and_inst[0].rx() + 0.5 * self.m1_width self.add_boundary() self.DRC_LVS() diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 532463a7..3f925851 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -17,10 +17,11 @@ class port_address(design.design): Create the address port (row decoder and wordline driver).. """ - def __init__(self, cols, rows, name=""): + def __init__(self, cols, rows, port, name=""): self.num_cols = cols self.num_rows = rows + self.port = port self.addr_size = ceil(log(self.num_rows, 2)) if name == "": @@ -39,6 +40,7 @@ class port_address(design.design): self.add_modules() self.create_row_decoder() self.create_wordline_driver() + self.create_rbl_driver() def create_layout(self): if "li" in layer: @@ -59,6 +61,8 @@ class port_address(design.design): for bit in range(self.num_rows): self.add_pin("wl_{0}".format(bit), "OUTPUT") + + self.add_pin("rbl_wl", "OUTPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") @@ -71,10 +75,12 @@ class port_address(design.design): def route_supplies(self): """ Propagate all vdd/gnd pins up to this level for all modules """ - for inst in self.insts: + for inst in [self.wordline_driver_array_inst, self.row_decoder_inst]: self.copy_power_pins(inst, "vdd") self.copy_power_pins(inst, "gnd") + self.copy_power_pins(self.rbl_driver_inst, "vdd") + def route_pins(self): for row in range(self.addr_size): decoder_name = "addr_{}".format(row) @@ -82,16 +88,16 @@ class port_address(design.design): for row in range(self.num_rows): driver_name = "wl_{}".format(row) - self.copy_layout_pin(self.wordline_driver_inst, driver_name) + self.copy_layout_pin(self.wordline_driver_array_inst, driver_name) - self.copy_layout_pin(self.wordline_driver_inst, "en", "wl_en") + self.copy_layout_pin(self.rbl_driver_inst, "Z", "rbl_wl") def route_internal(self): for row in range(self.num_rows): # The pre/post is to access the pin from "outside" the cell to avoid DRCs decoder_out_pin = self.row_decoder_inst.get_pin("decode_{}".format(row)) decoder_out_pos = decoder_out_pin.rc() - driver_in_pin = self.wordline_driver_inst.get_pin("in_{}".format(row)) + driver_in_pin = self.wordline_driver_array_inst.get_pin("in_{}".format(row)) driver_in_pos = driver_in_pin.lc() self.add_zjog(self.route_layer, decoder_out_pos, driver_in_pos, var_offset=0.3) @@ -102,6 +108,20 @@ class port_address(design.design): self.add_via_stack_center(from_layer=driver_in_pin.layer, to_layer=self.route_layer, offset=driver_in_pos) + + # Route the RBL from the enable input + en_pin = self.wordline_driver_array_inst.get_pin("en") + rbl_in_pin = self.rbl_driver_inst.get_pin("A") + rbl_in_pos = rbl_in_pin.center() + mid_pos = vector(en_pin.cx(), rbl_in_pin.cy()) + self.add_path(rbl_in_pin.layer, [rbl_in_pos, mid_pos]) + self.add_via_stack_center(from_layer=rbl_in_pin.layer, + to_layer=en_pin.layer, + offset=mid_pos) + self.add_layout_pin_segment_center(text="wl_en", + layer=en_pin.layer, + start=mid_pos, + end=en_pin.center()) def add_modules(self): @@ -109,10 +129,33 @@ class port_address(design.design): num_outputs=self.num_rows) self.add_mod(self.row_decoder) - self.wordline_driver = factory.create(module_type="wordline_driver_array", - rows=self.num_rows, - cols=self.num_cols) - self.add_mod(self.wordline_driver) + self.wordline_driver_array = factory.create(module_type="wordline_driver_array", + rows=self.num_rows, + cols=self.num_cols) + self.add_mod(self.wordline_driver_array) + + try: + local_array_size = OPTS.local_array_size + driver_size = int(self.num_cols / local_array_size) + except AttributeError: + local_array_size = 0 + # Defautl to FO4 + driver_size = int(self.num_cols / 4) + + # The polarity must be switched if we have a hierarchical wordline + # to compensate for the local array inverters + b = factory.create(module_type="bitcell") + + if local_array_size > 0: + self.rbl_driver = factory.create(module_type="inv_dec", + size=driver_size, + height=b.height) + else: + self.rbl_driver = factory.create(module_type="buf_dec", + size=driver_size, + height=b.height) + + self.add_mod(self.rbl_driver) def create_row_decoder(self): """ Create the hierarchical row decoder """ @@ -128,11 +171,24 @@ class port_address(design.design): temp.extend(["vdd", "gnd"]) self.connect_inst(temp) + def create_rbl_driver(self): + """ Create the RBL Wordline Driver """ + + self.rbl_driver_inst = self.add_inst(name="rbl_driver", + mod=self.rbl_driver) + + temp = [] + temp.append("wl_en") + temp.append("rbl_wl") + temp.append("vdd") + temp.append("gnd") + self.connect_inst(temp) + def create_wordline_driver(self): """ Create the Wordline Driver """ - - self.wordline_driver_inst = self.add_inst(name="wordline_driver", - mod=self.wordline_driver) + + self.wordline_driver_array_inst = self.add_inst(name="wordline_driver", + mod=self.wordline_driver_array) temp = [] for row in range(self.num_rows): @@ -150,11 +206,23 @@ class port_address(design.design): """ row_decoder_offset = vector(0, 0) - wordline_driver_offset = vector(self.row_decoder.width, 0) - self.wordline_driver_inst.place(wordline_driver_offset) self.row_decoder_inst.place(row_decoder_offset) + + wordline_driver_array_offset = vector(self.row_decoder_inst.rx(), 0) + self.wordline_driver_array_inst.place(wordline_driver_array_offset) + + x_offset = self.wordline_driver_array_inst.rx() - self.rbl_driver.width - self.m1_pitch + if self.port == 0: + rbl_driver_offset = vector(x_offset, + 0) + self.rbl_driver_inst.place(rbl_driver_offset, "MX") + else: + rbl_driver_offset = vector(x_offset, + self.wordline_driver_array.height) + self.rbl_driver_inst.place(rbl_driver_offset) + # Pass this up self.predecoder_height = self.row_decoder.predecoder_height self.height = self.row_decoder.height - self.width = self.wordline_driver_inst.rx() + self.width = self.wordline_driver_array_inst.rx() diff --git a/compiler/modules/wordline_buffer_array.py b/compiler/modules/wordline_buffer_array.py index 7a1bf8d1..45f3ef33 100644 --- a/compiler/modules/wordline_buffer_array.py +++ b/compiler/modules/wordline_buffer_array.py @@ -109,12 +109,13 @@ class wordline_buffer_array(design.design): def place_drivers(self): for row in range(self.rows): + # These are flipped since we always start with an RBL on the bottom if (row % 2): - y_offset = self.wl_driver.height * (row + 1) - inst_mirror = "MX" - else: y_offset = self.wl_driver.height * row inst_mirror = "R0" + else: + y_offset = self.wl_driver.height * (row + 1) + inst_mirror = "MX" offset = [0, y_offset] diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index ac0a0cb2..c334404e 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -44,7 +44,7 @@ class wordline_driver_array(design.design): self.place_drivers() self.route_layout() self.route_vdd_gnd() - self.offset_all_coordinates() + self.offset_x_coordinates() self.add_boundary() self.DRC_LVS() @@ -60,8 +60,10 @@ class wordline_driver_array(design.design): self.add_pin("gnd", "GROUND") def add_modules(self): + self.wl_driver = factory.create(module_type="wordline_driver", - size=self.cols) + cols=self.cols) + self.add_mod(self.wl_driver) def route_vdd_gnd(self): diff --git a/compiler/options.py b/compiler/options.py index 8d8e3b42..8de3b910 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -139,6 +139,7 @@ class options(optparse.Values): bank_select = "bank_select" bitcell_array = "bitcell_array" bitcell = "bitcell" + buf_dec = "pbuf" column_mux_array = "single_level_column_mux_array" control_logic = "control_logic" decoder = "hierarchical_decoder" diff --git a/compiler/pgates/pbuf.py b/compiler/pgates/pbuf.py index e504b89e..c2398d5f 100644 --- a/compiler/pgates/pbuf.py +++ b/compiler/pgates/pbuf.py @@ -96,4 +96,4 @@ class pbuf(pgate.pgate): offset=a_pin.center(), width=a_pin.width(), height=a_pin.height()) - \ No newline at end of file + diff --git a/compiler/pgates/wordline_driver.py b/compiler/pgates/wordline_driver.py index a8ca76f8..5f110249 100644 --- a/compiler/pgates/wordline_driver.py +++ b/compiler/pgates/wordline_driver.py @@ -18,9 +18,9 @@ class wordline_driver(design.design): This is an AND (or NAND) with configurable drive strength to drive the wordlines. It is matched to the bitcell height. """ - def __init__(self, name, size=1, height=None): + def __init__(self, name, cols=1, height=None): debug.info(1, "Creating wordline_driver {}".format(name)) - self.add_comment("size: {}".format(size)) + self.add_comment("cols: {}".format(cols)) super().__init__(name) if height is None: @@ -28,7 +28,7 @@ class wordline_driver(design.design): self.height = b.height else: self.height = height - self.size = size + self.cols = cols self.create_netlist() if not OPTS.netlist_only: @@ -42,10 +42,25 @@ class wordline_driver(design.design): def create_modules(self): self.nand = factory.create(module_type="nand2_dec", height=self.height) - - self.driver = factory.create(module_type="inv_dec", - size=self.size, - height=self.nand.height) + + try: + local_array_size = OPTS.local_array_size + driver_size = int(self.cols / local_array_size) + except AttributeError: + local_array_size = 0 + # Defautl to FO4 + driver_size = int(self.cols / 4) + + # The polarity must be switched if we have a hierarchical wordline + # to compensate for the local array inverters + if local_array_size > 0: + self.driver = factory.create(module_type="buf_dec", + size=driver_size, + height=self.nand.height) + else: + self.driver = factory.create(module_type="inv_dec", + size=driver_size, + height=self.nand.height) self.add_mod(self.nand) self.add_mod(self.driver) From 88731ccd8e7ac93c2d6ee7d0a60b1c350f34a941 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 28 Sep 2020 09:53:01 -0700 Subject: [PATCH 36/83] Fix rounding error for wmask with various word_size --- compiler/base/verilog.py | 9 +++++++-- compiler/characterizer/delay.py | 2 +- compiler/characterizer/functional.py | 3 ++- compiler/characterizer/simulation.py | 2 +- compiler/modules/bank.py | 2 +- compiler/modules/port_data.py | 3 ++- compiler/modules/write_driver_array.py | 3 ++- compiler/modules/write_mask_and_array.py | 3 ++- compiler/sram/sram_base.py | 4 ++-- 9 files changed, 20 insertions(+), 11 deletions(-) diff --git a/compiler/base/verilog.py b/compiler/base/verilog.py index 04344738..aadf602c 100644 --- a/compiler/base/verilog.py +++ b/compiler/base/verilog.py @@ -6,6 +6,7 @@ # All rights reserved. # import debug +import math class verilog: """ @@ -53,7 +54,7 @@ class verilog: self.vf.write("\n );\n\n") if self.write_size: - self.num_wmasks = int(self.word_size/self.write_size) + self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) self.vf.write(" parameter NUM_WMASKS = {0} ;\n".format(self.num_wmasks)) self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size)) self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(self.addr_size)) @@ -189,9 +190,13 @@ class verilog: self.vf.write(" if (!csb{0}_reg)\n".format(port)) if self.write_size: + remainder_bits = self.word_size % self.write_size for mask in range(0,self.num_wmasks): lower = mask * self.write_size - upper = lower + self.write_size-1 + if (remainder_bits and mask == self.num_wmasks - 1): + upper = lower + remainder_bits - 1 + else: + upper = lower + self.write_size - 1 self.vf.write(" if (wmask{0}_reg[{1}])\n".format(port,mask)) self.vf.write(" mem[addr{0}_reg][{1}:{2}] = din{0}_reg[{1}:{2}];\n".format(port,upper,lower)) self.vf.write(" end\n") diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index f04965e5..f81e8fa8 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -47,7 +47,7 @@ class delay(simulation): self.targ_write_ports = [] self.period = 0 if self.write_size: - self.num_wmasks = int(self.word_size / self.write_size) + self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) else: self.num_wmasks = 0 self.set_load_slew(0,0) diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index 395c612b..bb9f990d 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -8,6 +8,7 @@ import collections import debug import random +import math from .stimuli import * from .charutils import * from globals import OPTS @@ -31,7 +32,7 @@ class functional(simulation): random.seed(12345) if self.write_size: - self.num_wmasks = int(self.word_size / self.write_size) + self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) else: self.num_wmasks = 0 diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index b73af4f6..b6774e99 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -39,7 +39,7 @@ class simulation(): self.write_ports = self.sram.write_ports self.words_per_row = self.sram.words_per_row if self.write_size: - self.num_wmasks = int(self.word_size/self.write_size) + self.num_wmasks = int(math.ceil(self.word_size/self.write_size)) else: self.num_wmasks = 0 diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index c7b019d7..f7658f89 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -27,7 +27,7 @@ class bank(design.design): self.sram_config = sram_config sram_config.set_local_config(self) if self.write_size: - self.num_wmasks = int(self.word_size / self.write_size) + self.num_wmasks = int(ceil(self.word_size / self.write_size)) else: self.num_wmasks = 0 diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 0571201d..c013bc4a 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -6,6 +6,7 @@ from tech import drc import debug import design +import math from sram_factory import factory from collections import namedtuple from vector import vector @@ -23,7 +24,7 @@ class port_data(design.design): sram_config.set_local_config(self) self.port = port if self.write_size is not None: - self.num_wmasks = int(self.word_size / self.write_size) + self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) else: self.num_wmasks = 0 diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 568b192d..a2458f42 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -7,6 +7,7 @@ # import design import debug +import math from tech import drc from sram_factory import factory from vector import vector @@ -39,7 +40,7 @@ class write_driver_array(design.design): self.num_spare_cols = num_spare_cols if self.write_size: - self.num_wmasks = int(self.word_size / self.write_size) + self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) self.create_netlist() if not OPTS.netlist_only: diff --git a/compiler/modules/write_mask_and_array.py b/compiler/modules/write_mask_and_array.py index e2048d3d..94446755 100644 --- a/compiler/modules/write_mask_and_array.py +++ b/compiler/modules/write_mask_and_array.py @@ -7,6 +7,7 @@ # import design import debug +import math from sram_factory import factory from vector import vector from globals import OPTS @@ -31,7 +32,7 @@ class write_mask_and_array(design.design): self.offsets = offsets self.column_offset = column_offset self.words_per_row = int(columns / word_size) - self.num_wmasks = int(word_size / write_size) + self.num_wmasks = int(math.ceil(word_size / write_size)) self.create_netlist() if not OPTS.netlist_only: diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index c9eb4ea1..55e2de49 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -7,7 +7,7 @@ # import datetime import debug -from math import log +from math import log, ceil from importlib import reload from vector import vector from globals import OPTS, print_time @@ -36,7 +36,7 @@ class sram_base(design, verilog, lef): self.bank_insts = [] if self.write_size: - self.num_wmasks = int(self.word_size / self.write_size) + self.num_wmasks = int(ceil(self.word_size / self.write_size)) else: self.num_wmasks = 0 From 6f06bb9dd511fc8b39f072b374bb08a1b8695fa1 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 28 Sep 2020 11:30:21 -0700 Subject: [PATCH 37/83] Create sized RBL WL driver in port_address --- compiler/modules/bank.py | 9 ++++----- compiler/modules/global_bitcell_array.py | 1 + compiler/modules/local_bitcell_array.py | 4 ++-- compiler/modules/port_address.py | 13 ++++++++----- compiler/pgates/wordline_driver.py | 2 +- compiler/tests/04_wordline_driver_test.py | 2 +- compiler/tests/18_port_address_1rw_1r_test.py | 4 ++-- compiler/tests/18_port_address_test.py | 4 ++-- 8 files changed, 21 insertions(+), 18 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index e4ac72bc..beb60501 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -372,9 +372,7 @@ class bank(design.design): cols=self.num_cols + self.num_spare_cols, rows=self.num_rows, port=port)) - self.add_mod(self.port_address[port]) - - self.num_rbl = len(self.all_ports) + self.add_mod(self.port_address[port]) try: local_array_size = OPTS.local_array_size @@ -875,8 +873,9 @@ class bank(design.design): def route_port_address_right(self, port): """ Connecting Wordline driver output to Bitcell WL connection """ - driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] - for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port)): + driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] + ["rbl_wl"] + rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)[port] + for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port) + [rbl_wl_name]): # The mid guarantees we exit the input cell to the right. driver_wl_pin = self.port_address_inst[port].get_pin(driver_name) driver_wl_pos = driver_wl_pin.lc() diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index 57f4d716..ce35455a 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -267,3 +267,4 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): for inst in self.local_insts: offsets.extend(inst.lx() + x for x in inst.mod.get_column_offsets()) return offsets + diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index d552d77a..af1462c3 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -207,9 +207,9 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): y_offset = in_pin.cy() if port == 0: - y_offset -= 1.5 * self.m3_pitch + y_offset -= 2 * self.m3_pitch else: - y_offset += 1.5 * self.m3_pitch + y_offset += 2 * self.m3_pitch self.add_layout_pin_segment_center(text=wl_name, layer="m3", diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 3f925851..b30e84cf 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -40,7 +40,7 @@ class port_address(design.design): self.add_modules() self.create_row_decoder() self.create_wordline_driver() - self.create_rbl_driver() + self.create_rbl_driver() def create_layout(self): if "li" in layer: @@ -79,7 +79,8 @@ class port_address(design.design): self.copy_power_pins(inst, "vdd") self.copy_power_pins(inst, "gnd") - self.copy_power_pins(self.rbl_driver_inst, "vdd") + rbl_vdd_pin = self.rbl_driver_inst.get_pin("vdd") + self.add_power_pin("vdd", rbl_vdd_pin.lc()) def route_pins(self): for row in range(self.addr_size): @@ -111,17 +112,19 @@ class port_address(design.design): # Route the RBL from the enable input en_pin = self.wordline_driver_array_inst.get_pin("en") + en_pos = en_pin.center() rbl_in_pin = self.rbl_driver_inst.get_pin("A") rbl_in_pos = rbl_in_pin.center() + mid_pos = vector(en_pin.cx(), rbl_in_pin.cy()) - self.add_path(rbl_in_pin.layer, [rbl_in_pos, mid_pos]) self.add_via_stack_center(from_layer=rbl_in_pin.layer, to_layer=en_pin.layer, - offset=mid_pos) + offset=rbl_in_pos) + self.add_path(en_pin.layer, [rbl_in_pos, mid_pos, en_pos]) self.add_layout_pin_segment_center(text="wl_en", layer=en_pin.layer, start=mid_pos, - end=en_pin.center()) + end=en_pos) def add_modules(self): diff --git a/compiler/pgates/wordline_driver.py b/compiler/pgates/wordline_driver.py index 5f110249..e0dbf1b2 100644 --- a/compiler/pgates/wordline_driver.py +++ b/compiler/pgates/wordline_driver.py @@ -18,7 +18,7 @@ class wordline_driver(design.design): This is an AND (or NAND) with configurable drive strength to drive the wordlines. It is matched to the bitcell height. """ - def __init__(self, name, cols=1, height=None): + def __init__(self, name, cols, height=None): debug.info(1, "Creating wordline_driver {}".format(name)) self.add_comment("cols: {}".format(cols)) super().__init__(name) diff --git a/compiler/tests/04_wordline_driver_test.py b/compiler/tests/04_wordline_driver_test.py index ada65db7..74cfb7a7 100755 --- a/compiler/tests/04_wordline_driver_test.py +++ b/compiler/tests/04_wordline_driver_test.py @@ -25,7 +25,7 @@ class wordline_driver_test(openram_test): # check wordline driver for single port debug.info(2, "Checking driver") - tx = factory.create(module_type="wordline_driver") + tx = factory.create(module_type="wordline_driver", cols=8) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/18_port_address_1rw_1r_test.py b/compiler/tests/18_port_address_1rw_1r_test.py index caf2cb96..42a46614 100755 --- a/compiler/tests/18_port_address_1rw_1r_test.py +++ b/compiler/tests/18_port_address_1rw_1r_test.py @@ -27,11 +27,11 @@ class port_address_1rw_1r_test(openram_test): globals.setup_bitcell() debug.info(1, "Port address 16 rows") - a = factory.create("port_address", cols=16, rows=16) + a = factory.create("port_address", cols=16, rows=16, port=0) self.local_check(a) debug.info(1, "Port address 256 rows") - a = factory.create("port_address", cols=256, rows=256) + a = factory.create("port_address", cols=256, rows=256, port=1) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/18_port_address_test.py b/compiler/tests/18_port_address_test.py index 11da333e..94feedb2 100755 --- a/compiler/tests/18_port_address_test.py +++ b/compiler/tests/18_port_address_test.py @@ -21,11 +21,11 @@ class port_address_test(openram_test): globals.init_openram(config_file) debug.info(1, "Port address 16 rows") - a = factory.create("port_address", cols=16, rows=16) + a = factory.create("port_address", cols=16, rows=16, port=0) self.local_check(a) debug.info(1, "Port address 512 rows") - a = factory.create("port_address", cols=256, rows=512) + a = factory.create("port_address", cols=256, rows=512, port=0) self.local_check(a) globals.end_openram() From d65eb16513e5137aa6ad615fc04416a571aaa5bc Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 28 Sep 2020 12:24:55 -0700 Subject: [PATCH 38/83] Zjog the WL enable. Min driver is 1. --- compiler/modules/port_address.py | 14 ++++++-------- compiler/options.py | 3 +++ compiler/pgates/wordline_driver.py | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index b30e84cf..8af6a756 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -116,15 +116,13 @@ class port_address(design.design): rbl_in_pin = self.rbl_driver_inst.get_pin("A") rbl_in_pos = rbl_in_pin.center() - mid_pos = vector(en_pin.cx(), rbl_in_pin.cy()) self.add_via_stack_center(from_layer=rbl_in_pin.layer, to_layer=en_pin.layer, offset=rbl_in_pos) - self.add_path(en_pin.layer, [rbl_in_pos, mid_pos, en_pos]) - self.add_layout_pin_segment_center(text="wl_en", - layer=en_pin.layer, - start=mid_pos, - end=en_pos) + self.add_zjog(en_pin.layer, rbl_in_pos, en_pos) + self.add_layout_pin_rect_center(text="wl_en", + layer=en_pin.layer, + offset=rbl_in_pos) def add_modules(self): @@ -139,11 +137,11 @@ class port_address(design.design): try: local_array_size = OPTS.local_array_size - driver_size = int(self.num_cols / local_array_size) + driver_size = max(int(self.num_cols / local_array_size), 1) except AttributeError: local_array_size = 0 # Defautl to FO4 - driver_size = int(self.num_cols / 4) + driver_size = max(int(self.num_cols / 4), 1) # The polarity must be switched if we have a hierarchical wordline # to compensate for the local array inverters diff --git a/compiler/options.py b/compiler/options.py index 8de3b910..b9be3999 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -30,6 +30,9 @@ class options(optparse.Values): num_r_ports = 0 num_w_ports = 0 + # By default, use local arrays with a max fanout of 16 + #local_array_size = 16 + # Write mask size, default will be overwritten with word_size if not user specified write_size = None diff --git a/compiler/pgates/wordline_driver.py b/compiler/pgates/wordline_driver.py index e0dbf1b2..6abf7b20 100644 --- a/compiler/pgates/wordline_driver.py +++ b/compiler/pgates/wordline_driver.py @@ -45,11 +45,11 @@ class wordline_driver(design.design): try: local_array_size = OPTS.local_array_size - driver_size = int(self.cols / local_array_size) + driver_size = max(int(self.cols / local_array_size), 1) except AttributeError: local_array_size = 0 # Defautl to FO4 - driver_size = int(self.cols / 4) + driver_size = max(int(self.cols / 4), 1) # The polarity must be switched if we have a hierarchical wordline # to compensate for the local array inverters From 5ab0d0177968b49b179b72a30925b71a0da53d45 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 28 Sep 2020 12:48:37 -0700 Subject: [PATCH 39/83] Remove zjog and go with L shape. --- compiler/modules/port_address.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 8af6a756..33cd4474 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -115,11 +115,12 @@ class port_address(design.design): en_pos = en_pin.center() rbl_in_pin = self.rbl_driver_inst.get_pin("A") rbl_in_pos = rbl_in_pin.center() - + + mid_pos = vector(en_pos.x, rbl_in_pos.y) self.add_via_stack_center(from_layer=rbl_in_pin.layer, to_layer=en_pin.layer, offset=rbl_in_pos) - self.add_zjog(en_pin.layer, rbl_in_pos, en_pos) + self.add_path(en_pin.layer, [rbl_in_pos, mid_pos, en_pos]) self.add_layout_pin_rect_center(text="wl_en", layer=en_pin.layer, offset=rbl_in_pos) From 9c6d8d7aed4ef4e7e70261cc2b97037a23035d59 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 28 Sep 2020 13:16:03 -0700 Subject: [PATCH 40/83] Zjob to bottom. --- compiler/modules/port_address.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 33cd4474..f7e85afd 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -112,15 +112,20 @@ class port_address(design.design): # Route the RBL from the enable input en_pin = self.wordline_driver_array_inst.get_pin("en") - en_pos = en_pin.center() + if self.port == 0: + en_pos = en_pin.bc() + else: + en_pos = en_pin.uc() rbl_in_pin = self.rbl_driver_inst.get_pin("A") rbl_in_pos = rbl_in_pin.center() - mid_pos = vector(en_pos.x, rbl_in_pos.y) self.add_via_stack_center(from_layer=rbl_in_pin.layer, to_layer=en_pin.layer, offset=rbl_in_pos) - self.add_path(en_pin.layer, [rbl_in_pos, mid_pos, en_pos]) + self.add_zjog(layer=en_pin.layer, + start=rbl_in_pos, + end=en_pos, + first_direction="V") self.add_layout_pin_rect_center(text="wl_en", layer=en_pin.layer, offset=rbl_in_pos) From 70c90ca7fb686d0eb4dd29d10f055103f8fcef75 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 28 Sep 2020 14:49:33 -0700 Subject: [PATCH 41/83] Replica bitcell array bbox to include unused WL gnd pins. --- compiler/modules/bank.py | 43 +++++++++++++++-------- compiler/modules/replica_bitcell_array.py | 31 ++++++++++------ 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index beb60501..183d646a 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -845,11 +845,11 @@ class bank(design.design): self.route_port_address_in(port) if port % 2: - self.route_port_address_right(port) + self.route_port_address_out(port, "right") else: - self.route_port_address_left(port) + self.route_port_address_out(port, "left") - def route_port_address_left(self, port): + def route_port_address_out(self, port, side="left"): """ Connecting Wordline driver output to Bitcell WL connection """ driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] + ["rbl_wl"] @@ -857,18 +857,32 @@ class bank(design.design): for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port) + [rbl_wl_name]): # The mid guarantees we exit the input cell to the right. driver_wl_pin = self.port_address_inst[port].get_pin(driver_name) - driver_wl_pos = driver_wl_pin.rc() + if side == "left": + driver_wl_pos = driver_wl_pin.rc() + else: + driver_wl_pos = driver_wl_pin.lc() bitcell_wl_pin = self.bitcell_array_inst.get_pin(array_name) - bitcell_wl_pos = bitcell_wl_pin.lc() - mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * self.port_address_inst[port].rx() + 0.5 * self.bitcell_array_inst.lx(), 0) - mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0.5, 1) - self.add_path(driver_wl_pin.layer, [driver_wl_pos, mid1, mid2]) - # Via is non-preferred direction because mid1->mid2 is non-preferred direction - self.add_via_stack_center(from_layer=driver_wl_pin.layer, - to_layer=bitcell_wl_pin.layer, - offset=mid2, - directions="nonpref") - self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos]) + + if side == "left": + bitcell_wl_pos = bitcell_wl_pin.lc() + port_address_pos = self.port_address_inst[port].rx() + bitcell_array_pos = self.bitcell_array_inst.lx() + else: + bitcell_wl_pos = bitcell_wl_pin.rc() + port_address_pos = self.port_address_inst[port].lx() + bitcell_array_pos = self.bitcell_array_inst.rx() + + mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * port_address_pos + 0.5 * bitcell_array_pos, 0) + mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0, 1) + if driver_wl_pin.layer != bitcell_wl_pin.layer: + self.add_path(driver_wl_pin.layer, [driver_wl_pos, mid1, mid2]) + self.add_via_stack_center(from_layer=driver_wl_pin.layer, + to_layer=bitcell_wl_pin.layer, + offset=mid2) + self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos]) + else: + self.add_path(bitcell_wl_pin.layer, [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) + def route_port_address_right(self, port): """ Connecting Wordline driver output to Bitcell WL connection """ @@ -888,6 +902,7 @@ class bank(design.design): to_layer=bitcell_wl_pin.layer, offset=mid2) self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos]) + def route_column_address_lines(self, port): """ Connecting the select lines of column mux to the address bus """ diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 6c2d54a7..4e1c4df1 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -305,14 +305,21 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def create_layout(self): + # We will need unused wordlines grounded, so we need to know their layer + pin = self.cell.get_pin(self.cell.get_all_wl_names()[0]) + pin_layer = pin.layer + self.unused_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer)) + self.unused_offset = vector(self.unused_pitch, 0) + + # Add extra width on the left and right for the unused WLs self.height = (self.row_size + self.extra_rows) * self.dummy_row.height - self.width = (self.column_size + self.extra_cols) * self.cell.width + self.width = (self.column_size + self.extra_cols) * self.cell.width + 2 * self.unused_pitch # This is a bitcell x bitcell offset to scale self.bitcell_offset = vector(self.cell.width, self.cell.height) - # Everything is computed with the main array at (0, 0) to start - self.bitcell_array_inst.place(offset=[0, 0]) + # Everything is computed with the main array at (self.unused_pitch, 0) to start + self.bitcell_array_inst.place(offset=self.unused_offset) self.add_replica_columns() @@ -356,7 +363,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Grow from left to right, toward the array for bit, port in enumerate(self.left_rbl): - offset = self.bitcell_offset.scale(-len(self.left_rbl) + bit, -self.rbl[0] - 1) + offset = self.bitcell_offset.scale(-len(self.left_rbl) + bit, -self.rbl[0] - 1) + self.unused_offset self.replica_col_insts[port].place(offset) # Grow to the right of the bitcell array, array outward for bit, port in enumerate(self.right_rbl): @@ -367,11 +374,13 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Add the dummy rows even if we aren't adding the replica column to this bitcell array # These grow up, toward the array for bit in range(self.rbl[0]): - self.dummy_row_replica_insts[bit].place(offset=self.bitcell_offset.scale(0, -self.rbl[0] + bit + (-self.rbl[0] + bit) % 2), + dummy_offset = self.bitcell_offset.scale(0, -self.rbl[0] + bit + (-self.rbl[0] + bit) % 2) + self.unused_offset + self.dummy_row_replica_insts[bit].place(offset=dummy_offset, mirror="MX" if (-self.rbl[0] + bit) % 2 else "R0") # These grow up, away from the array for bit in range(self.rbl[1]): - self.dummy_row_replica_insts[self.rbl[0] + bit].place(offset=self.bitcell_offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul(), + dummy_offset = self.bitcell_offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul() + self.dummy_row_replica_insts[self.rbl[0] + bit].place(offset=dummy_offset, mirror="MX" if bit % 2 else "R0") def add_end_caps(self): @@ -386,12 +395,12 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # FIXME: These depend on the array size itself # Far bottom dummy row (first row below array IS flipped) flip_dummy = (self.rbl[0] + 1) % 2 - dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - 1 + flip_dummy) + dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - 1 + flip_dummy) + self.unused_offset self.dummy_row_insts[0].place(offset=dummy_row_offset, mirror="MX" if flip_dummy else "R0") # Far left dummy col # Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array - dummy_col_offset = self.bitcell_offset.scale(-len(self.left_rbl) - 1, -self.rbl[0] - 1) + dummy_col_offset = self.bitcell_offset.scale(-len(self.left_rbl) - 1, -self.rbl[0] - 1) + self.unused_offset self.dummy_col_insts[0].place(offset=dummy_col_offset) # Far right dummy col # Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array @@ -495,13 +504,13 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def ground_pin(self, inst, name): pin = inst.get_pin(name) pin_layer = pin.layer - layer_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer)) + left_pin_loc = vector(self.dummy_col_insts[0].lx(), pin.cy()) right_pin_loc = vector(self.dummy_col_insts[1].rx(), pin.cy()) # Place the pins a track outside of the array - left_loc = left_pin_loc - vector(layer_pitch, 0) - right_loc = right_pin_loc + vector(layer_pitch, 0) + left_loc = left_pin_loc - vector(self.unused_pitch, 0) + right_loc = right_pin_loc + vector(self.unused_pitch, 0) self.add_power_pin("gnd", left_loc, directions=("H", "H")) self.add_power_pin("gnd", right_loc, directions=("H", "H")) From b2dab486fc035131eb773ec96de290f89b2ae724 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 28 Sep 2020 16:05:21 -0700 Subject: [PATCH 42/83] Add draft of path exclusion calls --- compiler/modules/global_bitcell_array.py | 32 ++++++++++++++++++++++++ compiler/modules/local_bitcell_array.py | 17 +++++++++++++ 2 files changed, 49 insertions(+) diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index ce35455a..a6d079aa 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -267,4 +267,36 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): for inst in self.local_insts: offsets.extend(inst.lx() + x for x in inst.mod.get_column_offsets()) return offsets + + def graph_exclude_bits(self, targ_row, targ_col): + """ + Excludes bits in column from being added to graph except target + """ + # This must find which local array includes the specified column + # Find the summation of columns that is large and take the one before + for i, col in enumerate(self.col_offsets): + if col > targ_col: + break + + # We must also translate the global array column number to the local array column number + self.local_mods[i - 1].graph_exclude_bits(targ_row, targ_col - self.col_offsets[i - 1]) + def graph_exclude_replica_col_bits(self): + """ + Exclude all but replica in every local array. + """ + + for mod in self.local_mods: + mod.graph_exclude_replica_col_bits() + + def get_cell_name(self, inst_name, row, col): + """Gets the spice name of the target bitcell.""" + + # This must find which local array includes the specified column + # Find the summation of columns that is large and take the one before + for i, local_col in enumerate(self.col_offsets): + if local_col > col: + break + + return self.local_mods[i - 1].get_cell_name(inst_name + '.x' + self.local_insts[i - 1].name, row, col) + diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index af1462c3..840178a6 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -263,3 +263,20 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): offsets = [self.bitcell_array_inst.lx() + x for x in self.bitcell_array.get_column_offsets()] return offsets + def graph_exclude_bits(self, targ_row, targ_col): + """ + Excludes bits in column from being added to graph except target + """ + self.bitcell_array.graph_exclude_bits(targ_row, targ_col) + + def graph_exclude_replica_col_bits(self): + """ + Exclude all but replica in the local array. + """ + + self.bitcell_array.graph_exclude_replica_col_bits() + + def get_cell_name(self, inst_name, row, col): + """Gets the spice name of the target bitcell.""" + return self.bitcell_array.get_cell_name(inst_name + '.x' + self.bitcell_array_inst.name, row, col) + From 1eb8798bb6019d6f27b8eaae8c9c5587841130d3 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 28 Sep 2020 16:12:09 -0700 Subject: [PATCH 43/83] Add global functional test --- .../22_sram_1bank_2mux_global_func_test.py | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100755 compiler/tests/22_sram_1bank_2mux_global_func_test.py diff --git a/compiler/tests/22_sram_1bank_2mux_global_func_test.py b/compiler/tests/22_sram_1bank_2mux_global_func_test.py new file mode 100755 index 00000000..c8ff5969 --- /dev/null +++ b/compiler/tests/22_sram_1bank_2mux_global_func_test.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys,os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + +#@unittest.skip("SKIPPING 22_sram_1bank_2mux_func_test") +class sram_1bank_2mux_func_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + OPTS.analytical_delay = False + OPTS.netlist_only = True + OPTS.trim_netlist = False + + # This is a hack to reload the characterizer __init__ with the spice version + from importlib import reload + import characterizer + reload(characterizer) + from characterizer import functional, delay + from sram_config import sram_config + OPTS.local_array_size = 8 + OPTS.route_supplies = False + c = sram_config(word_size=8, + num_words=32, + num_banks=1) + c.words_per_row=2 + c.recompute_sizes() + debug.info(1, "Functional test for sram with " + "{} bit words, {} words, {} words per row, {} banks".format(c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) + s = factory.create(module_type="sram", sram_config=c) + tempspice = OPTS.openram_temp + "sram.sp" + s.sp_write(tempspice) + + corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) + f = functional(s.s, tempspice, corner) + (fail, error) = f.run() + self.assertTrue(fail,error) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From d7e2340e62d34fc082c9768f692778f0e79706ea Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 29 Sep 2020 10:26:31 -0700 Subject: [PATCH 44/83] Lots of PEP8 cleanup. Refactor path graph to simulation class. --- compiler/base/graph_util.py | 44 ++--- compiler/base/hierarchy_design.py | 23 ++- compiler/base/hierarchy_spice.py | 13 +- compiler/characterizer/delay.py | 147 ++++++---------- compiler/characterizer/functional.py | 60 +------ compiler/characterizer/simulation.py | 205 +++++++++++++--------- compiler/modules/bank.py | 20 ++- compiler/modules/bitcell_array.py | 4 +- compiler/modules/global_bitcell_array.py | 9 + compiler/modules/local_bitcell_array.py | 8 +- compiler/modules/replica_bitcell_array.py | 18 +- compiler/modules/replica_column.py | 16 +- compiler/sram/sram_base.py | 13 +- 13 files changed, 305 insertions(+), 275 deletions(-) diff --git a/compiler/base/graph_util.py b/compiler/base/graph_util.py index 5d1ee692..6f8af016 100644 --- a/compiler/base/graph_util.py +++ b/compiler/base/graph_util.py @@ -40,9 +40,9 @@ class timing_graph(): """Helper function to remove edges, useful for removing vdd/gnd""" node = node.lower() - self.graph[node] = set() + self.graph[node] = set() - def get_all_paths(self, src_node, dest_node, remove_rail_nodes=True, reduce_paths=True): + def get_all_paths(self, src_node, dest_node, remove_rail_nodes=True, reduce_paths=True): """Traverse all paths from source to destination""" src_node = src_node.lower() @@ -59,44 +59,44 @@ class timing_graph(): visited = set() # Create an array to store paths - path = [] + path = [] self.all_paths = [] # Call the recursive helper function to print all paths - self.get_all_paths_util(src_node, dest_node, visited, path) + self.get_all_paths_util(src_node, dest_node, visited, path) debug.info(2, "Paths found={}".format(len(self.all_paths))) if reduce_paths: self.reduce_paths() - return self.all_paths + return self.all_paths def reduce_paths(self): """ Remove any path that is a subset of another path """ self.all_paths = [p1 for p1 in self.all_paths if not any(set(p1)<=set(p2) for p2 in self.all_paths if p1 is not p2)] - def get_all_paths_util(self, cur_node, dest_node, visited, path): + def get_all_paths_util(self, cur_node, dest_node, visited, path): """Recursive function to find all paths in a Depth First Search manner""" # Mark the current node as visited and store in path visited.add(cur_node) - path.append(cur_node) + path.append(cur_node) # If current vertex is same as destination, then print # current path[] - if cur_node == dest_node: + if cur_node == dest_node: self.all_paths.append(copy.deepcopy(path)) - else: + else: # If current vertex is not destination # Recur for all the vertices adjacent to this vertex - for node in self.graph[cur_node]: - if node not in visited: - self.get_all_paths_util(node, dest_node, visited, path) + for node in self.graph[cur_node]: + if node not in visited: + self.get_all_paths_util(node, dest_node, visited, path) # Remove current vertex from path[] and mark it as unvisited - path.pop() - visited.remove(cur_node) + path.pop() + visited.remove(cur_node) def get_timing(self, path, corner, slew, load): """Returns the analytical delays in the input path""" @@ -106,20 +106,20 @@ class timing_graph(): delays = [] cur_slew = slew - for i in range(len(path)-1): + for i in range(len(path) - 1): - path_edge_mod = self.edge_mods[(path[i], path[i+1])] + path_edge_mod = self.edge_mods[(path[i], path[i + 1])] # On the output of the current stage, get COUT from all other mods connected cout = 0 - for node in self.graph[path[i+1]]: - output_edge_mod = self.edge_mods[(path[i+1], node)] + for node in self.graph[path[i + 1]]: + output_edge_mod = self.edge_mods[(path[i + 1], node)] cout+=output_edge_mod.get_cin() # If at the last output, include the final output load - if i == len(path)-2: - cout+=load + if i == len(path) - 2: + cout += load - delays.append(path_edge_mod.analytical_delay(corner, slew, cout)) + delays.append(path_edge_mod.analytical_delay(corner, slew, cout)) cur_slew = delays[-1].slew return delays @@ -127,4 +127,4 @@ class timing_graph(): def __str__(self): """ override print function output """ - return "Nodes: {}\nEdges:{} ".format(list(self.graph), self.graph) + return "Nodes: {}\nEdges:{} ".format(list(self.graph), self.graph) diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index 16d2bb4e..b4b0ef72 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -12,6 +12,7 @@ import os from globals import OPTS import tech + class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): """ Design Class for all modules to inherit the base features. @@ -137,12 +138,16 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): os.remove(tempgds) def init_graph_params(self): - """Initializes parameters relevant to the graph creation""" + """ + Initializes parameters relevant to the graph creation + """ # Only initializes a set for checking instances which should not be added self.graph_inst_exclude = set() def build_graph(self, graph, inst_name, port_nets): - """Recursively create graph from instances in module.""" + """ + Recursively create graph from instances in module. + """ # Translate port names to external nets if len(port_nets) != len(self.pins): @@ -159,7 +164,9 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): subinst.mod.build_graph(graph, subinst_name, subinst_ports) def build_names(self, name_dict, inst_name, port_nets): - """Collects all the nets and the parent inst of that net.""" + """ + Collects all the nets and the parent inst of that net. + """ # Translate port names to external nets if len(port_nets) != len(self.pins): debug.error("Port length mismatch:\nExt nets={}, Ports={}".format(port_nets, @@ -178,7 +185,9 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): subinst.mod.build_names(name_dict, subinst_name, subinst_ports) def translate_nets(self, subinst_ports, port_dict, inst_name): - """Converts connection names to their spice hierarchy equivalent""" + """ + Converts connection names to their spice hierarchy equivalent + """ converted_conns = [] for conn in subinst_ports: if conn in port_dict: @@ -188,8 +197,10 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): return converted_conns def add_graph_edges(self, graph, port_nets): - """For every input, adds an edge to every output. - Only intended to be used for gates and other simple modules.""" + """ + For every input, adds an edge to every output. + Only intended to be used for gates and other simple modules. + """ # The final pin names will depend on the spice hierarchy, so # they are passed as an input. pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)} diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index cfb9f9fa..08e2b474 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -500,8 +500,9 @@ class spice(): return power_data(dynamic, leakage) def find_aliases(self, inst_name, port_nets, path_nets, alias, alias_mod, exclusion_set=None): - """Given a list of nets, will compare the internal alias of a mod to determine - if the nets have a connection to this mod's net (but not inst). + """ + Given a list of nets, will compare the internal alias of a mod to determine + if the nets have a connection to this mod's net (but not inst). """ if not exclusion_set: exclusion_set = set() @@ -520,7 +521,9 @@ class spice(): return aliases def is_net_alias(self, known_net, net_alias, mod, exclusion_set): - """Checks if the alias_net in input mod is the same as the input net for this mod (self).""" + """ + Checks if the alias_net in input mod is the same as the input net for this mod (self). + """ if self in exclusion_set: return False # Check ports of this mod @@ -540,7 +543,9 @@ class spice(): return False def is_net_alias_name_check(self, parent_net, child_net, alias_net, mod): - """Utility function for checking single net alias.""" + """ + Utility function for checking single net alias. + """ return self == mod and \ child_net.lower() == alias_net.lower() and \ parent_net.lower() == alias_net.lower() diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index f81e8fa8..3f3aeee4 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -5,7 +5,7 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import sys,re,shutil,copy +import shutil import debug import tech import math @@ -14,13 +14,10 @@ from .trim_spice import * from .charutils import * from .sram_op import * from .bit_polarity import * -import utils from globals import OPTS from .simulation import simulation from .measurements import * -import logical_effort -import graph_util -from sram_factory import factory + class delay(simulation): """ @@ -50,7 +47,7 @@ class delay(simulation): self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) else: self.num_wmasks = 0 - self.set_load_slew(0,0) + self.set_load_slew(0, 0) self.set_corner(corner) self.create_signal_names() self.add_graph_exclusions() @@ -69,7 +66,7 @@ class delay(simulation): self.read_meas_lists = self.create_read_port_measurement_objects() self.write_meas_lists = self.create_write_port_measurement_objects() - self.check_meas_names(self.read_meas_lists+self.write_meas_lists) + self.check_meas_names(self.read_meas_lists + self.write_meas_lists) def check_meas_names(self, measures_lists): """ @@ -80,8 +77,8 @@ class delay(simulation): for meas_list in measures_lists: for meas in meas_list: name = meas.name.lower() - debug.check(name not in name_set,("SPICE measurements must have unique names. " - "Duplicate name={}").format(name)) + debug.check(name not in name_set, ("SPICE measurements must have unique names. " + "Duplicate name={}").format(name)) name_set.add(name) def create_read_port_measurement_objects(self): @@ -89,7 +86,7 @@ class delay(simulation): self.read_lib_meas = [] self.clk_frmt = "clk{0}" # Unformatted clock name - targ_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) # Empty values are the port and probe data bit + targ_name = "{0}{1}_{2}".format(self.dout_name, "{}", self.probe_data) # Empty values are the port and probe data bit self.delay_meas = [] self.delay_meas.append(delay_measure("delay_lh", self.clk_frmt, targ_name, "RISE", "RISE", measure_scale=1e9)) self.delay_meas[-1].meta_str = sram_op.READ_ONE # Used to index time delay values when measurements written to spice file. @@ -217,7 +214,7 @@ class delay(simulation): meas.meta_str = cycle self.write_bit_meas[polarity].append(meas) # Dictionary values are lists, reduce to a single list of measurements - return [meas for meas_list in self.write_bit_meas.values() for meas in meas_list] + return [meas for meas_list in self.write_bit_meas.values() for meas in meas_list] def get_bit_measures(self, meas_tag, probe_address, probe_data): """ @@ -231,9 +228,9 @@ class delay(simulation): storage_names = cell_inst.mod.get_storage_net_names() debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes" "supported for characterization. Storage nets={}").format(storage_names)) - if not OPTS.use_pex: - q_name = cell_name+'.'+str(storage_names[0]) - qbar_name = cell_name+'.'+str(storage_names[1]) + if not OPTS.use_pex: + q_name = cell_name + '.' + str(storage_names[0]) + qbar_name = cell_name + '.' + str(storage_names[1]) else: bank_num = self.sram.get_bank_num(self.sram.name, bit_row, bit_col) q_name = "bitcell_Q_b{0}_r{1}_c{2}".format(bank_num, bit_row, bit_col) @@ -243,54 +240,15 @@ class delay(simulation): # but they is enforced externally. {} added to names to differentiate between ports allow the # measurements are independent of the ports q_meas = voltage_at_measure("v_q_{}".format(meas_tag), q_name) - qbar_meas = voltage_at_measure("v_qbar_{}".format(meas_tag), qbar_name) + qbar_meas = voltage_at_measure("v_qbar_{}".format(meas_tag), qbar_name) - return {bit_polarity.NONINVERTING:q_meas, bit_polarity.INVERTING:qbar_meas} + return {bit_polarity.NONINVERTING: q_meas, bit_polarity.INVERTING: qbar_meas} - def set_load_slew(self,load,slew): + def set_load_slew(self, load, slew): """ Set the load and slew """ self.load = load self.slew = slew - - def create_graph(self): - """Creates timing graph to generate the timing paths for the SRAM output.""" - - self.sram.bank.bitcell_array.bitcell_array.init_graph_params() # Removes previous bit exclusions - self.sram.bank.bitcell_array.graph_exclude_bits(self.wordline_row, self.bitline_column) - - # Generate new graph every analysis as edges might change depending on test bit - self.graph = graph_util.timing_graph() - self.sram_spc_name = "X{}".format(self.sram.name) - self.sram.build_graph(self.graph,self.sram_spc_name,self.pins) - - def get_bl_name_search_exclusions(self): - """Gets the mods as a set which should be excluded while searching for name.""" - - # Exclude the RBL as it contains bitcells which are not in the main bitcell array - # so it makes the search awkward - return set(factory.get_mods(OPTS.replica_bitline)) - - def get_alias_in_path(self, paths, int_net, mod, exclusion_set=None): - """ - Finds a single alias for the int_net in given paths. - More or less hits cause an error - """ - - net_found = False - for path in paths: - aliases = self.sram.find_aliases(self.sram_spc_name, self.pins, path, int_net, mod, exclusion_set) - if net_found and len(aliases) >= 1: - debug.error('Found multiple paths with {} net.'.format(int_net),1) - elif len(aliases) > 1: - debug.error('Found multiple {} nets in single path.'.format(int_net),1) - elif not net_found and len(aliases) == 1: - path_net_name = aliases[0] - net_found = True - if not net_found: - debug.error("Could not find {} net in timing paths.".format(int_net),1) - - return path_net_name def check_arguments(self): """Checks if arguments given for write_stimulus() meets requirements""" @@ -298,19 +256,19 @@ class delay(simulation): try: int(self.probe_address, 2) except ValueError: - debug.error("Probe Address is not of binary form: {0}".format(self.probe_address),1) + debug.error("Probe Address is not of binary form: {0}".format(self.probe_address), 1) if len(self.probe_address) != self.addr_size: - debug.error("Probe Address's number of bits does not correspond to given SRAM",1) + debug.error("Probe Address's number of bits does not correspond to given SRAM", 1) if not isinstance(self.probe_data, int) or self.probe_data>self.word_size or self.probe_data<0: - debug.error("Given probe_data is not an integer to specify a data bit",1) + debug.error("Given probe_data is not an integer to specify a data bit", 1) # Adding port options here which the characterizer cannot handle. Some may be added later like ROM if len(self.read_ports) == 0: - debug.error("Characterizer does not currently support SRAMs without read ports.",1) + debug.error("Characterizer does not currently support SRAMs without read ports.", 1) if len(self.write_ports) == 0: - debug.error("Characterizer does not currently support SRAMs without write ports.",1) + debug.error("Characterizer does not currently support SRAMs without write ports.", 1) def write_generic_stimulus(self): """ Create the instance, supplies, loads, and access transistors. """ @@ -323,17 +281,16 @@ class delay(simulation): self.sf.write("\n* Instantiation of the SRAM\n") if not OPTS.use_pex: self.stim.inst_model(pins=self.pins, - model_name=self.sram.name) + model_name=self.sram.name) else: - self.stim.inst_sram_pex(pins=self.pins, - model_name=self.sram.name) + self.stim.inst_sram_pex(pins=self.pins, + model_name=self.sram.name) self.sf.write("\n* SRAM output loads\n") for port in self.read_ports: for i in range(self.word_size): - self.sf.write("CD{0}{1} {2}{0}_{1} 0 {3}f\n".format(port,i,self.dout_name,self.load)) + self.sf.write("CD{0}{1} {2}{0}_{1} 0 {3}f\n".format(port, i, self.dout_name, self.load)) - def write_delay_stimulus(self): """ Creates a stimulus file for simulations to probe a bitcell at a given clock period. @@ -385,7 +342,6 @@ class delay(simulation): self.sf.close() - def write_power_stimulus(self, trim): """ Creates a stimulus file to measure leakage power only. This works on the *untrimmed netlist*. @@ -410,11 +366,11 @@ class delay(simulation): self.sf.write("\n* Generation of data and address signals\n") for write_port in self.write_ports: for i in range(self.word_size): - self.stim.gen_constant(sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i), - v_val=0) + self.stim.gen_constant(sig_name="{0}{1}_{2} ".format(self.din_name, write_port, i), + v_val=0) for port in self.all_ports: for i in range(self.addr_size): - self.stim.gen_constant(sig_name="{0}{1}_{2}".format(self.addr_name,port, i), + self.stim.gen_constant(sig_name="{0}{1}_{2}".format(self.addr_name, port, i), v_val=0) # generate control signals @@ -431,7 +387,7 @@ class delay(simulation): self.write_power_measures() # run until the end of the cycle time - self.stim.write_control(2*self.period) + self.stim.write_control(2 * self.period) self.sf.close() @@ -1257,23 +1213,23 @@ class delay(simulation): debug.warning("In analytical mode, all ports have the timing of the first read port.") # Probe set to 0th bit, does not matter for analytical delay. - self.set_probe('0'*self.addr_size, 0) + self.set_probe('0' * self.addr_size, 0) self.create_graph() self.set_internal_spice_names() self.create_measurement_names() port = self.read_ports[0] - self.graph.get_all_paths('{}{}'.format("clk", port), + self.graph.get_all_paths('{}{}'.format("clk", port), '{}{}_{}'.format(self.dout_name, port, self.probe_data)) # Select the path with the bitline (bl) - bl_name,br_name = self.get_bl_name(self.graph.all_paths, port) + bl_name, br_name = self.get_bl_name(self.graph.all_paths, port) bl_path = [path for path in self.graph.all_paths if bl_name in path][0] # Set delay/power for slews and loads port_data = self.get_empty_measure_data_dict() power = self.analytical_power(slews, loads) - debug.info(1,'Slew, Load, Delay(ns), Slew(ns)') + debug.info(1, 'Slew, Load, Delay(ns), Slew(ns)') max_delay = 0.0 for slew in slews: for load in loads: @@ -1282,41 +1238,45 @@ class delay(simulation): total_delay = self.sum_delays(path_delays) max_delay = max(max_delay, total_delay.delay) - debug.info(1,'{}, {}, {}, {}'.format(slew,load,total_delay.delay/1e3, total_delay.slew/1e3)) + debug.info(1, + '{}, {}, {}, {}'.format(slew, + load, + total_delay.delay / 1e3, + total_delay.slew / 1e3)) # Delay is only calculated on a single port and replicated for now. for port in self.all_ports: - for mname in self.delay_meas_names+self.power_meas_names: + for mname in self.delay_meas_names + self.power_meas_names: if "power" in mname: port_data[port][mname].append(power.dynamic) elif "delay" in mname and port in self.read_ports: - port_data[port][mname].append(total_delay.delay/1e3) + port_data[port][mname].append(total_delay.delay / 1e3) elif "slew" in mname and port in self.read_ports: - port_data[port][mname].append(total_delay.slew/1e3) + port_data[port][mname].append(total_delay.slew / 1e3) else: - debug.error("Measurement name not recognized: {}".format(mname),1) + debug.error("Measurement name not recognized: {}".format(mname), 1) # Estimate the period as double the delay with margin period_margin = 0.1 - sram_data = { "min_period":(max_delay/1e3)*2*period_margin, - "leakage_power": power.leakage} + sram_data = {"min_period": (max_delay / 1e3) * 2 * period_margin, + "leakage_power": power.leakage} - debug.info(2,"SRAM Data:\n{}".format(sram_data)) - debug.info(2,"Port Data:\n{}".format(port_data)) + debug.info(2, "SRAM Data:\n{}".format(sram_data)) + debug.info(2, "Port Data:\n{}".format(port_data)) - return (sram_data,port_data) + return (sram_data, port_data) def analytical_power(self, slews, loads): """Get the dynamic and leakage power from the SRAM""" # slews unused, only last load is used load = loads[-1] - power = self.sram.analytical_power(self.corner, load) + power = self.sram.analytical_power(self.corner, load) # convert from nW to mW - power.dynamic /= 1e6 + power.dynamic /= 1e6 power.leakage /= 1e6 - debug.info(1,"Dynamic Power: {0} mW".format(power.dynamic)) - debug.info(1,"Leakage Power: {0} mW".format(power.leakage)) + debug.info(1, "Dynamic Power: {0} mW".format(power.dynamic)) + debug.info(1, "Leakage Power: {0} mW".format(power.leakage)) return power def gen_data(self): @@ -1324,7 +1284,7 @@ class delay(simulation): for write_port in self.write_ports: for i in range(self.word_size): - sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i) + sig_name="{0}{1}_{2} ".format(self.din_name, write_port, i) self.stim.gen_pwl(sig_name, self.cycle_times, self.data_values[write_port][i], self.period, self.slew, 0.05) def gen_addr(self): @@ -1335,7 +1295,7 @@ class delay(simulation): for port in self.all_ports: for i in range(self.addr_size): - sig_name = "{0}{1}_{2}".format(self.addr_name,port,i) + sig_name = "{0}{1}_{2}".format(self.addr_name, port, i) self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][i], self.period, self.slew, 0.05) def gen_control(self): @@ -1346,11 +1306,10 @@ class delay(simulation): if port in self.readwrite_ports: self.stim.gen_pwl("WEB{0}".format(port), self.cycle_times, self.web_values[port], self.period, self.slew, 0.05) - def get_empty_measure_data_dict(self): """Make a dict of lists for each type of delay and power measurement to append results to""" - measure_names = self.delay_meas_names + self.power_meas_names + measure_names = self.delay_meas_names + self.power_meas_names # Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists. - measure_data = [{mname:[] for mname in measure_names} for i in self.all_ports] + measure_data = [{mname: [] for mname in measure_names} for i in self.all_ports] return measure_data diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index bb9f990d..ed2baeec 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -13,9 +13,6 @@ from .stimuli import * from .charutils import * from globals import OPTS from .simulation import simulation -# from .delay import delay -import graph_util -from sram_factory import factory class functional(simulation): @@ -39,7 +36,7 @@ class functional(simulation): if not self.num_spare_cols: self.num_spare_cols = 0 - self.probe_address, self.probe_data = '0'*self.addr_size,0 + self.probe_address, self.probe_data = '0' * self.addr_size, 0 self.set_corner(corner) self.set_spice_constants() self.set_stimulus_variables() @@ -49,7 +46,7 @@ class functional(simulation): self.add_graph_exclusions() self.create_graph() self.set_internal_spice_names() - self.q_name, self.qbar_name = self.get_bit_name() + self.q_name, self.qbar_name = self.get_bit_name() debug.info(2, "q name={}\nqbar name={}".format(self.q_name, self.qbar_name)) # Number of checks can be changed @@ -60,7 +57,7 @@ class functional(simulation): self.read_results = [] def run(self, feasible_period=None): - if feasible_period: #period defaults to tech.py feasible period otherwise. + if feasible_period: # period defaults to tech.py feasible period otherwise. self.period = feasible_period # Generate a random sequence of reads and writes self.create_random_memory_sequence() @@ -249,11 +246,12 @@ class functional(simulation): def check_stim_results(self): for i in range(len(self.read_check)): if self.read_check[i][0] != self.read_results[i][0]: - error = "FAILED: {0} value {1} does not match written value {2} read during cycle {3} at time {4}n".format(self.read_results[i][1], - self.read_results[i][0], - self.read_check[i][0], - int((self.read_results[i][2]-self.period)/self.period), - self.read_results[i][2]) + str = "FAILED: {0} value {1} does not match written value {2} read during cycle {3} at time {4}n" + error = str.format(self.read_results[i][1], + self.read_results[i][0], + self.read_check[i][0], + int((self.read_results[i][2] - self.period) / self.period), + self.read_results[i][2]) return(0, error) return(1, "SUCCESS") @@ -423,19 +421,6 @@ class functional(simulation): self.stim.write_control(self.cycle_times[-1] + self.period) self.sf.close() - - # FIXME: refactor to share with delay.py - def create_graph(self): - """Creates timing graph to generate the timing paths for the SRAM output.""" - - self.sram.bank.bitcell_array.init_graph_params() # Removes previous bit exclusions - # Does wordline=0 and column=0 just for debug names - self.sram.bank.bitcell_array.graph_exclude_bits(0, 0) - - # Generate new graph every analysis as edges might change depending on test bit - self.graph = graph_util.timing_graph() - self.sram_spc_name = "X{}".format(self.sram.name) - self.sram.build_graph(self.graph, self.sram_spc_name, self.pins) #FIXME: Similar function to delay.py, refactor this def get_bit_name(self): @@ -449,31 +434,4 @@ class functional(simulation): return (q_name, qbar_name) - def get_bl_name_search_exclusions(self): - """Gets the mods as a set which should be excluded while searching for name.""" - - # Exclude the RBL as it contains bitcells which are not in the main bitcell array - # so it makes the search awkward - return set(factory.get_mods(OPTS.replica_bitline)) - - def get_alias_in_path(self, paths, int_net, mod, exclusion_set=None): - """ - Finds a single alias for the int_net in given paths. - More or less hits cause an error - """ - - net_found = False - for path in paths: - aliases = self.sram.find_aliases(self.sram_spc_name, self.pins, path, int_net, mod, exclusion_set) - if net_found and len(aliases) >= 1: - debug.error('Found multiple paths with {} net.'.format(int_net), 1) - elif len(aliases) > 1: - debug.error('Found multiple {} nets in single path.'.format(int_net), 1) - elif not net_found and len(aliases) == 1: - path_net_name = aliases[0] - net_found = True - if not net_found: - debug.error("Could not find {} net in timing paths.".format(int_net), 1) - - return path_net_name diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index b6774e99..51f99c03 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -5,17 +5,13 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -import sys,re,shutil -from design import design import debug import math import tech -from .stimuli import * -from .trim_spice import * -from .charutils import * -import utils from globals import OPTS from sram_factory import factory +import graph_util + class simulation(): @@ -39,11 +35,11 @@ class simulation(): self.write_ports = self.sram.write_ports self.words_per_row = self.sram.words_per_row if self.write_size: - self.num_wmasks = int(math.ceil(self.word_size/self.write_size)) + self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) else: self.num_wmasks = 0 - def set_corner(self,corner): + def set_corner(self, corner): """ Set the corner values """ self.corner = corner (self.process, self.vdd_voltage, self.temperature) = corner @@ -51,8 +47,8 @@ class simulation(): def set_spice_constants(self): """ sets feasible timing parameters """ self.period = tech.spice["feasible_period"] - self.slew = tech.spice["rise_time"]*2 - self.load = tech.spice["dff_in_cap"]*4 + self.slew = tech.spice["rise_time"] * 2 + self.load = tech.spice["dff_in_cap"] * 4 self.v_high = self.vdd_voltage - tech.spice["nom_threshold"] self.v_low = tech.spice["nom_threshold"] @@ -79,20 +75,20 @@ class simulation(): self.t_current = 0 # control signals: only one cs_b for entire multiported sram, one we_b for each write port - self.csb_values = {port:[] for port in self.all_ports} - self.web_values = {port:[] for port in self.readwrite_ports} + self.csb_values = {port: [] for port in self.all_ports} + self.web_values = {port: [] for port in self.readwrite_ports} # Raw values added as a bit vector - self.addr_value = {port:[] for port in self.all_ports} - self.data_value = {port:[] for port in self.write_ports} - self.wmask_value = {port:[] for port in self.write_ports} - self.spare_wen_value = {port:[] for port in self.write_ports} + self.addr_value = {port: [] for port in self.all_ports} + self.data_value = {port: [] for port in self.write_ports} + self.wmask_value = {port: [] for port in self.write_ports} + self.spare_wen_value = {port: [] for port in self.write_ports} # Three dimensional list to handle each addr and data bits for each port over the number of checks - self.addr_values = {port:[[] for bit in range(self.addr_size)] for port in self.all_ports} - self.data_values = {port:[[] for bit in range(self.word_size + self.num_spare_cols)] for port in self.write_ports} - self.wmask_values = {port:[[] for bit in range(self.num_wmasks)] for port in self.write_ports} - self.spare_wen_values = {port:[[] for bit in range(self.num_spare_cols)] for port in self.write_ports} + self.addr_values = {port: [[] for bit in range(self.addr_size)] for port in self.all_ports} + self.data_values = {port: [[] for bit in range(self.word_size + self.num_spare_cols)] for port in self.write_ports} + self.wmask_values = {port: [[] for bit in range(self.num_wmasks)] for port in self.write_ports} + self.spare_wen_values = {port: [[] for bit in range(self.num_spare_cols)] for port in self.write_ports} # For generating comments in SPICE stimulus self.cycle_comments = [] @@ -109,7 +105,7 @@ class simulation(): csb_val = 0 web_val = 0 elif op != "noop": - debug.error("Could not add control signals for port {0}. Command {1} not recognized".format(port,op),1) + debug.error("Could not add control signals for port {0}. Command {1} not recognized".format(port, op), 1) # Append the values depending on the type of port self.csb_values[port].append(csb_val) @@ -129,7 +125,7 @@ class simulation(): elif c=="1": self.data_values[port][bit].append(1) else: - debug.error("Non-binary data string",1) + debug.error("Non-binary data string", 1) bit -= 1 def add_address(self, address, port): @@ -142,12 +138,11 @@ class simulation(): if c=="0": self.addr_values[port][bit].append(0) elif c=="1": - self.addr_values[port][bit].append(1) + self.addr_values[port][bit].append(1) else: - debug.error("Non-binary address string",1) + debug.error("Non-binary address string", 1) bit -= 1 - def add_wmask(self, wmask, port): """ Add the array of address values """ debug.check(len(wmask) == self.num_wmasks, "Invalid wmask size.") @@ -191,9 +186,9 @@ class simulation(): self.t_current += self.period self.add_control_one_port(port, "write") - self.add_data(data,port) - self.add_address(address,port) - self.add_wmask(wmask,port) + self.add_data(data, port) + self.add_address(address, port) + self.add_wmask(wmask, port) self.add_spare_wen("1" * self.num_spare_cols, port) #Add noops to all other ports. @@ -221,11 +216,11 @@ class simulation(): try: self.add_data(self.data_value[port][-1], port) except: - self.add_data("0"*(self.word_size + self.num_spare_cols), port) + self.add_data("0" * (self.word_size + self.num_spare_cols), port) try: self.add_wmask(self.wmask_value[port][-1], port) except: - self.add_wmask("0"*self.num_wmasks, port) + self.add_wmask("0" * self.num_wmasks, port) self.add_spare_wen("0" * self.num_spare_cols, port) #Add noops to all other ports. @@ -276,12 +271,12 @@ class simulation(): try: self.add_data(self.data_value[port][-1], port) except: - self.add_data("0"*(self.word_size + self.num_spare_cols), port) + self.add_data("0" * (self.word_size + self.num_spare_cols), port) try: self.add_wmask(self.wmask_value[port][-1], port) except: - self.add_wmask("0"*self.num_wmasks, port) - self.add_spare_wen("0" * self.num_spare_cols, port) + self.add_wmask("0" * self.num_wmasks, port) + self.add_spare_wen("0" * self.num_spare_cols, port) def add_noop_one_port(self, port): """ Add the control values for a noop to a single port. Does not increment the period. """ @@ -290,7 +285,7 @@ class simulation(): try: self.add_address(self.addr_value[port][-1], port) except: - self.add_address("0"*self.addr_size, port) + self.add_address("0" * self.addr_size, port) # If the port is also a readwrite then add # the same value as previous cycle @@ -298,11 +293,11 @@ class simulation(): try: self.add_data(self.data_value[port][-1], port) except: - self.add_data("0"*(self.word_size + self.num_spare_cols), port) + self.add_data("0" * (self.word_size + self.num_spare_cols), port) try: self.add_wmask(self.wmask_value[port][-1], port) except: - self.add_wmask("0"*self.num_wmasks, port) + self.add_wmask("0" * self.num_wmasks, port) self.add_spare_wen("0" * self.num_spare_cols, port) def add_noop_clock_one_port(self, port): @@ -321,23 +316,23 @@ class simulation(): if unselected_port != port: self.add_noop_one_port(unselected_port) - def append_cycle_comment(self, port, comment): """Add comment to list to be printed in stimulus file""" #Clean up time before appending. Make spacing dynamic as well. time = "{0:.2f} ns:".format(self.t_current) - time_spacing = len(time)+6 + time_spacing = len(time) + 6 self.cycle_comments.append("Cycle {0:<6d} Port {1:<6} {2:<{3}}: {4}".format(len(self.cycle_times), port, time, time_spacing, - comment)) + comment)) def gen_cycle_comment(self, op, word, addr, wmask, port, t_current): if op == "noop": - comment = "\tIdle during cycle {0} ({1}ns - {2}ns)".format(int(t_current/self.period), - t_current, - t_current+self.period) + str = "\tIdle during cycle {0} ({1}ns - {2}ns)" + comment = str.format(int(t_current / self.period), + t_current, + t_current + self.period) elif op == "write": comment = "\tWriting {0} to address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word, addr, @@ -346,40 +341,41 @@ class simulation(): t_current, t_current+self.period) elif op == "partial_write": - comment = "\tWriting (partial) {0} to address {1} with mask bit {2} (from port {3}) during cycle {4} ({5}ns - {6}ns)".format(word, - addr, - wmask, - port, - int(t_current / self.period), - t_current, - t_current + self.period) + str = "\tWriting (partial) {0} to address {1} with mask bit {2} (from port {3}) during cycle {4} ({5}ns - {6}ns)" + comment = str.format(word, + addr, + wmask, + port, + int(t_current / self.period), + t_current, + t_current + self.period) else: - comment = "\tReading {0} from address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word, - addr, - port, - int(t_current/self.period), - t_current, - t_current+self.period) - + str = "\tReading {0} from address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)" + comment = str.format(word, + addr, + port, + int(t_current / self.period), + t_current, + t_current + self.period) return comment def gen_pin_names(self, port_signal_names, port_info, abits, dbits): """Creates the pins names of the SRAM based on the no. of ports.""" - #This may seem redundant as the pin names are already defined in the sram. However, it is difficult - #to extract the functionality from the names, so they are recreated. As the order is static, changing - #the order of the pin names will cause issues here. + # This may seem redundant as the pin names are already defined in the sram. However, it is difficult + # to extract the functionality from the names, so they are recreated. As the order is static, changing + # the order of the pin names will cause issues here. pin_names = [] (addr_name, din_name, dout_name) = port_signal_names (total_ports, write_index, read_index) = port_info for write_input in write_index: for i in range(dbits): - pin_names.append("{0}{1}_{2}".format(din_name,write_input, i)) + pin_names.append("{0}{1}_{2}".format(din_name, write_input, i)) for port in range(total_ports): for i in range(abits): - pin_names.append("{0}{1}_{2}".format(addr_name,port,i)) + pin_names.append("{0}{1}_{2}".format(addr_name, port, i)) #Control signals not finalized. for port in range(total_ports): @@ -394,16 +390,16 @@ class simulation(): if self.write_size: for port in write_index: for bit in range(self.num_wmasks): - pin_names.append("WMASK{0}_{1}".format(port,bit)) + pin_names.append("WMASK{0}_{1}".format(port, bit)) if self.num_spare_cols: for port in write_index: for bit in range(self.num_spare_cols): - pin_names.append("SPARE_WEN{0}_{1}".format(port,bit)) + pin_names.append("SPARE_WEN{0}_{1}".format(port, bit)) for read_output in read_index: for i in range(dbits): - pin_names.append("{0}{1}_{2}".format(dout_name,read_output, i)) + pin_names.append("{0}{1}_{2}".format(dout_name, read_output, i)) pin_names.append("{0}".format("vdd")) pin_names.append("{0}".format("gnd")) @@ -425,8 +421,8 @@ class simulation(): port = self.read_ports[0] if not OPTS.use_pex: - self.graph.get_all_paths('{}{}'.format("clk", port), - '{}{}_{}'.format(self.dout_name, port, self.probe_data)) + self.graph.get_all_paths('{}{}'.format("clk", port), + '{}{}_{}'.format(self.dout_name, port, self.probe_data)) sen_with_port = self.get_sen_name(self.graph.all_paths) if sen_with_port.endswith(str(port)): @@ -435,38 +431,38 @@ class simulation(): self.sen_name = sen_with_port debug.warning("Error occurred while determining SEN name. Can cause faults in simulation.") - debug.info(2,"s_en name = {}".format(self.sen_name)) + debug.info(2, "s_en name = {}".format(self.sen_name)) bl_name_port, br_name_port = self.get_bl_name(self.graph.all_paths, port) - port_pos = -1-len(str(self.probe_data))-len(str(port)) + port_pos = -1 - len(str(self.probe_data)) - len(str(port)) - if bl_name_port.endswith(str(port)+"_"+str(self.probe_data)): - self.bl_name = bl_name_port[:port_pos] +"{}"+ bl_name_port[port_pos+len(str(port)):] + if bl_name_port.endswith(str(port) + "_" + str(self.probe_data)): + self.bl_name = bl_name_port[:port_pos] + "{}" + bl_name_port[port_pos + len(str(port)):] elif not bl_name_port[port_pos].isdigit(): # single port SRAM case, bl will not be numbered eg bl_0 self.bl_name = bl_name_port else: self.bl_name = bl_name_port debug.warning("Error occurred while determining bitline names. Can cause faults in simulation.") - if br_name_port.endswith(str(port)+"_"+str(self.probe_data)): - self.br_name = br_name_port[:port_pos] +"{}"+ br_name_port[port_pos+len(str(port)):] + if br_name_port.endswith(str(port) + "_" + str(self.probe_data)): + self.br_name = br_name_port[:port_pos] + "{}" + br_name_port[port_pos + len(str(port)):] elif not br_name_port[port_pos].isdigit(): # single port SRAM case, bl will not be numbered eg bl_0 self.br_name = br_name_port else: - self.br_name = br_name_port + self.br_name = br_name_port debug.warning("Error occurred while determining bitline names. Can cause faults in simulation.") - debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name)) + debug.info(2, "bl name={}, br name={}".format(self.bl_name, self.br_name)) else: - self.graph.get_all_paths('{}{}'.format("clk", port), - '{}{}_{}'.format(self.dout_name, port, self.probe_data)) + self.graph.get_all_paths('{}{}'.format("clk", port), + '{}{}_{}'.format(self.dout_name, port, self.probe_data)) - self.sen_name = self.get_sen_name(self.graph.all_paths) - debug.info(2,"s_en name = {}".format(self.sen_name)) + self.sen_name = self.get_sen_name(self.graph.all_paths) + debug.info(2, "s_en name = {}".format(self.sen_name)) - self.bl_name = "bl{0}_{1}".format(port, OPTS.word_size-1) - self.br_name = "br{0}_{1}".format(port, OPTS.word_size-1) - debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name)) + self.bl_name = "bl{0}_{1}".format(port, OPTS.word_size - 1) + self.br_name = "br{0}_{1}".format(port, OPTS.word_size - 1) + debug.info(2, "bl name={}, br name={}".format(self.bl_name, self.br_name)) def get_sen_name(self, paths, assumed_port=None): """ @@ -482,17 +478,53 @@ class simulation(): sen_name = self.get_alias_in_path(paths, enable_name, sa_mods[0]) if OPTS.use_pex: sen_name = sen_name.split('.')[-1] - return sen_name + return sen_name + def create_graph(self): + """Creates timing graph to generate the timing paths for the SRAM output.""" + self.sram.clear_exclude_bits() # Removes previous bit exclusions + self.sram.graph_exclude_bits(self.wordline_row, self.bitline_column) + + # Generate new graph every analysis as edges might change depending on test bit + self.graph = graph_util.timing_graph() + self.sram_instance_name = "X{}".format(self.sram.name) + self.sram.build_graph(self.graph, self.sram_instance_name, self.pins) + + def get_bl_name_search_exclusions(self): + """Gets the mods as a set which should be excluded while searching for name.""" + + # Exclude the RBL as it contains bitcells which are not in the main bitcell array + # so it makes the search awkward + return set(factory.get_mods(OPTS.replica_bitline)) + + def get_alias_in_path(self, paths, internal_net, mod, exclusion_set=None): + """ + Finds a single alias for the internal_net in given paths. + More or less hits cause an error + """ + net_found = False + for path in paths: + aliases = self.sram.find_aliases(self.sram_instance_name, self.pins, path, internal_net, mod, exclusion_set) + if net_found and len(aliases) >= 1: + debug.error('Found multiple paths with {} net.'.format(internal_net), 1) + elif len(aliases) > 1: + debug.error('Found multiple {} nets in single path.'.format(internal_net), 1) + elif not net_found and len(aliases) == 1: + path_net_name = aliases[0] + net_found = True + if not net_found: + debug.error("Could not find {} net in timing paths.".format(internal_net), 1) + + return path_net_name + def get_bl_name(self, paths, port): """Gets the signal name associated with the bitlines in the bank.""" - cell_mod = factory.create(module_type=OPTS.bitcell) + cell_mod = factory.create(module_type=OPTS.bitcell) cell_bl = cell_mod.get_bl_name(port) cell_br = cell_mod.get_br_name(port) - bl_found = False # Only a single path should contain a single s_en name. Anything else is an error. bl_names = [] exclude_set = self.get_bl_name_search_exclusions() @@ -501,4 +533,7 @@ class simulation(): if OPTS.use_pex: for i in range(len(bl_names)): bl_names[i] = bl_names[i].split('.')[-1] - return bl_names[0], bl_names[1] \ No newline at end of file + return bl_names[0], bl_names[1] + + + diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 5dfaa007..2371a609 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -1076,14 +1076,30 @@ class bank(design.design): offset=control_pos) def graph_exclude_precharge(self): - """Precharge adds a loop between bitlines, can be excluded to reduce complexity""" + """ + Precharge adds a loop between bitlines, can be excluded to reduce complexity + """ for port in self.read_ports: if self.port_data[port]: self.port_data[port].graph_exclude_precharge() def get_cell_name(self, inst_name, row, col): - """Gets the spice name of the target bitcell.""" + """ + Gets the spice name of the target bitcell. + """ return self.bitcell_array_inst.mod.get_cell_name(inst_name + '.x' + self.bitcell_array_inst.name, row, col) + def graph_exclude_bits(self, targ_row, targ_col): + """ + Excludes bits in column from being added to graph except target + """ + self.bitcell_array.graph_exclude_bits(targ_row, targ_col) + + def clear_exclude_bits(self): + """ + Clears the bit exclusions + """ + self.bitcell_array.clear_exclude_bits() + diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 111f2795..6ce7a7da 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -105,7 +105,9 @@ class bitcell_array(bitcell_base_array): return bl_wire def graph_exclude_bits(self, targ_row, targ_col): - """Excludes bits in column from being added to graph except target""" + """ + Excludes bits in column from being added to graph except target + """ # Function is not robust with column mux configurations for row in range(self.row_size): for col in range(self.column_size): diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index a6d079aa..db6f5f26 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -297,6 +297,15 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): for i, local_col in enumerate(self.col_offsets): if local_col > col: break + else: + # In this case, we it should be in the last bitcell array + i = len(self.col_offsets) return self.local_mods[i - 1].get_cell_name(inst_name + '.x' + self.local_insts[i - 1].name, row, col) + def clear_exclude_bits(self): + """ + Clears the bit exclusions + """ + for mod in self.local_mods: + mod.clear_exclude_bits() diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index 840178a6..633478c1 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -279,4 +279,10 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): def get_cell_name(self, inst_name, row, col): """Gets the spice name of the target bitcell.""" return self.bitcell_array.get_cell_name(inst_name + '.x' + self.bitcell_array_inst.name, row, col) - + + def clear_exclude_bits(self): + """ + Clears the bit exclusions + """ + self.bitcell_array.clear_exclude_bits() + diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 4e1c4df1..5dffd116 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -529,15 +529,27 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): return bl_wire def graph_exclude_bits(self, targ_row, targ_col): - """Excludes bits in column from being added to graph except target""" + """ + Excludes bits in column from being added to graph except target + """ self.bitcell_array.graph_exclude_bits(targ_row, targ_col) def graph_exclude_replica_col_bits(self): - """Exclude all replica/dummy cells in the replica columns except the replica bit.""" + """ + Exclude all replica/dummy cells in the replica columns except the replica bit. + """ for port in self.left_rbl + self.right_rbl: self.replica_columns[port].exclude_all_but_replica() def get_cell_name(self, inst_name, row, col): - """Gets the spice name of the target bitcell.""" + """ + Gets the spice name of the target bitcell. + """ return self.bitcell_array.get_cell_name(inst_name + '.x' + self.bitcell_array_inst.name, row, col) + + def clear_exclude_bits(self): + """ + Clears the bit exclusions + """ + self.bitcell_array.init_graph_params() diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index e7b938e7..dafe51e6 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -200,8 +200,10 @@ class replica_column(bitcell_base_array): return self.bitline_names[port] def get_bitcell_pins(self, row, col): - """ Creates a list of connections in the bitcell, - indexed by column and row, for instance use in bitcell_array """ + """ + Creates a list of connections in the bitcell, + indexed by column and row, for instance use in bitcell_array + """ bitcell_pins = [] for port in self.all_ports: bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))]) @@ -212,8 +214,10 @@ class replica_column(bitcell_base_array): return bitcell_pins def get_bitcell_pins_col_cap(self, row, col): - """ Creates a list of connections in the bitcell, - indexed by column and row, for instance use in bitcell_array """ + """ + Creates a list of connections in the bitcell, + indexed by column and row, for instance use in bitcell_array + """ bitcell_pins = [] for port in self.all_ports: bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))]) @@ -223,7 +227,9 @@ class replica_column(bitcell_base_array): return bitcell_pins def exclude_all_but_replica(self): - """Excludes all bits except the replica cell (self.replica_bit).""" + """ + Excludes all bits except the replica cell (self.replica_bit). + """ for row, cell in self.cell_inst.items(): if row != self.replica_bit: diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 55e2de49..d18e1366 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -630,4 +630,15 @@ class sram_base(design, verilog, lef): def lvs_write(self, sp_name): self.sp_write(sp_name, lvs_netlist=True) - \ No newline at end of file + + def graph_exclude_bits(self, targ_row, targ_col): + """ + Excludes bits in column from being added to graph except target + """ + self.bank.graph_exclude_bits(targ_row, targ_col) + + def clear_exclude_bits(self): + """ + Clears the bit exclusions + """ + self.bank.clear_exclude_bits() From 9032bb98691fe5ec2449484f87f4c6f1132f53cf Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 29 Sep 2020 10:28:57 -0700 Subject: [PATCH 45/83] Add global wordline delay test --- .../tests/21_ngspice_delay_global_test.py | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100755 compiler/tests/21_ngspice_delay_global_test.py diff --git a/compiler/tests/21_ngspice_delay_global_test.py b/compiler/tests/21_ngspice_delay_global_test.py new file mode 100755 index 00000000..83d4e9a9 --- /dev/null +++ b/compiler/tests/21_ngspice_delay_global_test.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys,os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + +class timing_sram_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + OPTS.spice_name="ngspice" + OPTS.analytical_delay = False + OPTS.netlist_only = True + + # This is a hack to reload the characterizer __init__ with the spice version + from importlib import reload + import characterizer + reload(characterizer) + from characterizer import delay + from sram_config import sram_config + OPTS.local_array_size = 8 + OPTS.route_supplies = False + c = sram_config(word_size=8, + num_words=32, + num_banks=1) + + c.words_per_row=2 + c.recompute_sizes() + debug.info(1, "Testing timing for global hierarchical array") + s = factory.create(module_type="sram", sram_config=c) + + tempspice = OPTS.openram_temp + "temp.sp" + s.sp_write(tempspice) + + probe_address = "1" * s.s.addr_size + probe_data = s.s.word_size - 1 + debug.info(1, "Probe address {0} probe data bit {1}".format(probe_address, probe_data)) + + corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) + d = delay(s.s, tempspice, corner) + import tech + loads = [tech.spice["dff_in_cap"]*4] + slews = [tech.spice["rise_time"]*2] + data, port_data = d.analyze(probe_address, probe_data, slews, loads) + #Combine info about port into all data + data.update(port_data[0]) + + if OPTS.tech_name == "freepdk45": + golden_data = {'slew_lh': [0.2592187], + 'slew_hl': [0.2592187], + 'delay_lh': [0.2465583], + 'disabled_write0_power': [0.1924678], + 'disabled_read0_power': [0.152483], + 'write0_power': [0.3409064], + 'disabled_read1_power': [0.1737818], + 'read0_power': [0.3096708], + 'read1_power': [0.3107916], + 'delay_hl': [0.2465583], + 'write1_power': [0.26915849999999997], + 'leakage_power': 0.002044307, + 'min_period': 0.898, + 'disabled_write1_power': [0.201411]} + elif OPTS.tech_name == "scn4m_subm": + golden_data = {'delay_hl': [1.8435739999999998], + 'delay_lh': [1.8435739999999998], + 'disabled_read0_power': [5.917947], + 'disabled_read1_power': [7.154297], + 'disabled_write0_power': [7.696351], + 'disabled_write1_power': [7.999409000000001], + 'leakage_power': 0.004809726, + 'min_period': 6.875, + 'read0_power': [11.833079999999999], + 'read1_power': [11.99236], + 'slew_hl': [1.8668490000000002], + 'slew_lh': [1.8668490000000002], + 'write0_power': [13.287510000000001], + 'write1_power': [10.416369999999999]} + else: + self.assertTrue(False) # other techs fail + + # Check if no too many or too few results + self.assertTrue(len(data.keys())==len(golden_data.keys())) + + self.assertTrue(self.check_golden_data(data,golden_data,0.25)) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From 4b5bbe755f8593f1ccdcebcbad941a97a38f88ac Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 29 Sep 2020 11:13:58 -0700 Subject: [PATCH 46/83] PEP8 cleanup. Fix cur_slew bug. --- compiler/base/graph_util.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/compiler/base/graph_util.py b/compiler/base/graph_util.py index 6f8af016..03ee96e8 100644 --- a/compiler/base/graph_util.py +++ b/compiler/base/graph_util.py @@ -1,13 +1,7 @@ -import os, copy +import copy from collections import defaultdict - -import gdsMill -import tech -import math -import globals import debug -from vector import vector -from pin_layout import pin_layout + class timing_graph(): """ @@ -33,7 +27,7 @@ class timing_graph(): """Add node to graph with no edges""" node = node.lower() - if not node in self.graph: + if node not in self.graph: self.graph[node] = set() def remove_edges(self, node): @@ -119,7 +113,7 @@ class timing_graph(): if i == len(path) - 2: cout += load - delays.append(path_edge_mod.analytical_delay(corner, slew, cout)) + delays.append(path_edge_mod.analytical_delay(corner, cur_slew, cout)) cur_slew = delays[-1].slew return delays From 0c280e062ab421ef929d29b680b13da3b7c0a28a Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 29 Sep 2020 11:35:58 -0700 Subject: [PATCH 47/83] Fix func test with row/col of 0. PEP8 cleanup. Smaller global test case. --- compiler/base/graph_util.py | 13 +++- compiler/characterizer/delay.py | 70 +++++++++---------- compiler/characterizer/functional.py | 2 + .../tests/21_ngspice_delay_global_test.py | 17 +++-- 4 files changed, 59 insertions(+), 43 deletions(-) diff --git a/compiler/base/graph_util.py b/compiler/base/graph_util.py index 03ee96e8..6d4ee5da 100644 --- a/compiler/base/graph_util.py +++ b/compiler/base/graph_util.py @@ -121,4 +121,15 @@ class timing_graph(): def __str__(self): """ override print function output """ - return "Nodes: {}\nEdges:{} ".format(list(self.graph), self.graph) + str = "" + for n in self.graph: + str += n + "\n" + for d in self.graph[n]: + str += "\t\t-> " + d + "\n" + return str + + def __repr__(self): + """ override print function output """ + + return str(self) + diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 3f3aeee4..273666cf 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -891,7 +891,6 @@ class delay(simulation): target_period = 0.5 * (ub_period + lb_period) # key=input("press return to continue") - def try_period(self, feasible_delays): """ This tries to simulate a period and checks if the result @@ -914,19 +913,19 @@ class delay(simulation): if self.sram.col_addr_size>0 and "slew" in dname: continue - if not relative_compare(results[port][dname],feasible_delays[port][dname],error_tolerance=0.05): - debug.info(2,"Delay too big {0} vs {1}".format(results[port][dname],feasible_delays[port][dname])) + if not relative_compare(results[port][dname], feasible_delays[port][dname], error_tolerance=0.05): + debug.info(2, "Delay too big {0} vs {1}".format(results[port][dname], feasible_delays[port][dname])) return False # key=raw_input("press return to continue") delay_str = ', '.join("{0}={1}ns".format(mname, results[port][mname]) for mname in self.delay_meas_names) - debug.info(2,"Successful period {0}, Port {2}, {1}".format(self.period, - delay_str, - port)) + debug.info(2, "Successful period {0}, Port {2}, {1}".format(self.period, + delay_str, + port)) return True - def set_probe(self,probe_address, probe_data): + def set_probe(self, probe_address, probe_data): """ Probe address and data can be set separately to utilize other functions in this characterizer besides analyze. @@ -942,16 +941,16 @@ class delay(simulation): """Calculates bitline column number of data bit under test using bit position and mux size""" if self.sram.col_addr_size>0: - col_address = int(probe_address[0:self.sram.col_addr_size],2) + col_address = int(probe_address[0:self.sram.col_addr_size], 2) else: col_address = 0 - bl_column = int(self.sram.words_per_row*probe_data + col_address) - return bl_column + bl_column = int(self.sram.words_per_row * probe_data + col_address) + return bl_column def get_address_row_number(self, probe_address): """Calculates wordline row number of data bit under test using address and column mux size""" - return int(probe_address[self.sram.col_addr_size:],2) + return int(probe_address[self.sram.col_addr_size:], 2) def prepare_netlist(self): """ Prepare a trimmed netlist and regular netlist. """ @@ -965,7 +964,7 @@ class delay(simulation): self.num_cols, self.word_size, self.num_spare_rows) - self.trimsp.trim(self.probe_address,self.probe_data) + self.trimsp.trim(self.probe_address, self.probe_data) else: # The non-reduced netlist file when it is disabled self.trim_sp_file = "{}sram.sp".format(OPTS.openram_temp) @@ -1000,9 +999,9 @@ class delay(simulation): feasible_delays = self.find_feasible_period() # 2) Finds the minimum period without degrading the delays by X% - self.set_load_slew(max(loads),max(slews)) + self.set_load_slew(max(loads), max(slews)) min_period = self.find_min_period(feasible_delays) - debug.check(type(min_period)==float,"Couldn't find minimum period.") + debug.check(type(min_period)==float, "Couldn't find minimum period.") debug.info(1, "Min Period Found: {0}ns".format(min_period)) char_sram_data["min_period"] = round_time(min_period) @@ -1036,14 +1035,14 @@ class delay(simulation): self.targ_write_ports = self.write_ports for slew in slews: for load in loads: - self.set_load_slew(load,slew) + self.set_load_slew(load, slew) # Find the delay, dynamic power, and leakage power of the trimmed array. (success, delay_results) = self.run_delay_simulation() - debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(self.slew,self.load)) - debug.info(1, "Simulation Passed: Port {0} slew={1} load={2}".format("All", self.slew,self.load)) + debug.check(success, "Couldn't run a simulation. slew={0} load={1}\n".format(self.slew, self.load)) + debug.info(1, "Simulation Passed: Port {0} slew={1} load={2}".format("All", self.slew, self.load)) # The results has a dict for every port but dicts can be empty (e.g. ports were not targeted). for port in self.all_ports: - for mname,value in delay_results[port].items(): + for mname, value in delay_results[port].items(): if "power" in mname: # Subtract partial array leakage and add full array leakage for the power measures measure_data[port][mname].append(value + leakage_offset) @@ -1064,8 +1063,8 @@ class delay(simulation): elif c=="1": inverse_address += "0" else: - debug.error("Non-binary address string",1) - return inverse_address+column_addr + debug.error("Non-binary address string", 1) + return inverse_address + column_addr def gen_test_cycles_one_port(self, read_port, write_port): """Sets a list of key time-points [ns] of the waveform (each rising edge) @@ -1075,10 +1074,10 @@ class delay(simulation): inverse_address = self.calculate_inverse_address() # For now, ignore data patterns and write ones or zeros - data_ones = "1"*self.word_size - data_zeros = "0"*self.word_size - wmask_ones = "1"*self.num_wmasks - wmask_zeroes = "0"*self.num_wmasks + data_ones = "1" * self.word_size + data_zeros = "0" * self.word_size + wmask_ones = "1" * self.num_wmasks + wmask_zeroes = "0" * self.num_wmasks if self.t_current == 0: self.add_noop_all_ports("Idle cycle (no positive clock edge)") @@ -1094,10 +1093,10 @@ class delay(simulation): data_zeros, wmask_ones, write_port) - self.measure_cycles[write_port][sram_op.WRITE_ZERO] = len(self.cycle_times)-1 + self.measure_cycles[write_port][sram_op.WRITE_ZERO] = len(self.cycle_times) - 1 self.add_noop_clock_one_port(write_port) - self.measure_cycles[write_port]["disabled_write0"] = len(self.cycle_times)-1 + self.measure_cycles[write_port]["disabled_write0"] = len(self.cycle_times) - 1 # This also ensures we will have a H->L transition on the next read self.add_read("R data 1 address {} to set dout caps".format(inverse_address), @@ -1107,12 +1106,11 @@ class delay(simulation): self.add_read("R data 0 address {} to check W0 worked".format(self.probe_address), self.probe_address, read_port) - self.measure_cycles[read_port][sram_op.READ_ZERO] = len(self.cycle_times)-1 + self.measure_cycles[read_port][sram_op.READ_ZERO] = len(self.cycle_times) - 1 self.add_noop_clock_one_port(read_port) self.measure_cycles[read_port]["disabled_read0"] = len(self.cycle_times) - 1 - self.add_noop_all_ports("Idle cycle (if read takes >1 cycle)") self.add_write("W data 1 address {} to write value".format(self.probe_address), @@ -1120,10 +1118,10 @@ class delay(simulation): data_ones, wmask_ones, write_port) - self.measure_cycles[write_port][sram_op.WRITE_ONE] = len(self.cycle_times)-1 + self.measure_cycles[write_port][sram_op.WRITE_ONE] = len(self.cycle_times) - 1 self.add_noop_clock_one_port(write_port) - self.measure_cycles[write_port]["disabled_write1"] = len(self.cycle_times)-1 + self.measure_cycles[write_port]["disabled_write1"] = len(self.cycle_times) - 1 self.add_write("W data 0 address {} to clear din caps".format(inverse_address), inverse_address, @@ -1143,11 +1141,11 @@ class delay(simulation): self.add_read("R data 1 address {} to check W1 worked".format(self.probe_address), self.probe_address, read_port) - self.measure_cycles[read_port][sram_op.READ_ONE] = len(self.cycle_times)-1 + self.measure_cycles[read_port][sram_op.READ_ONE] = len(self.cycle_times) - 1 self.add_noop_all_ports("Idle cycle (if read takes >1 cycle))") - def get_available_port(self,get_read_port): + def get_available_port(self, get_read_port): """Returns the first accessible read or write port. """ if get_read_port and len(self.read_ports) > 0: @@ -1169,12 +1167,12 @@ class delay(simulation): # Using this requires setting at least one port to target for simulation. if len(self.targ_write_ports) == 0 or len(self.targ_read_ports) == 0: - debug.error("Write and read port must be specified for characterization.",1) + debug.error("Write and read port must be specified for characterization.", 1) self.set_stimulus_variables() # Get any available read/write port in case only a single write or read ports is being characterized. - cur_read_port = self.get_available_port(get_read_port=True) - cur_write_port = self.get_available_port(get_read_port=False) + cur_read_port = self.get_available_port(get_read_port=True) + cur_write_port = self.get_available_port(get_read_port=False) debug.check(cur_read_port != None, "Characterizer requires at least 1 read port") debug.check(cur_write_port != None, "Characterizer requires at least 1 write port") @@ -1203,7 +1201,7 @@ class delay(simulation): delay = delays[0] for i in range(1, len(delays)): delay+=delays[i] - return delay + return delay def analytical_delay(self, slews, loads): """ diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index ed2baeec..4fa4f06b 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -42,6 +42,8 @@ class functional(simulation): self.set_stimulus_variables() # For the debug signal names + self.wordline_row = 0 + self.bitline_column = 0 self.create_signal_names() self.add_graph_exclusions() self.create_graph() diff --git a/compiler/tests/21_ngspice_delay_global_test.py b/compiler/tests/21_ngspice_delay_global_test.py index 83d4e9a9..c2344d90 100755 --- a/compiler/tests/21_ngspice_delay_global_test.py +++ b/compiler/tests/21_ngspice_delay_global_test.py @@ -15,6 +15,7 @@ from globals import OPTS from sram_factory import factory import debug + class timing_sram_test(openram_test): def runTest(self): @@ -30,14 +31,18 @@ class timing_sram_test(openram_test): reload(characterizer) from characterizer import delay from sram_config import sram_config - OPTS.local_array_size = 8 - OPTS.route_supplies = False - c = sram_config(word_size=8, - num_words=32, + OPTS.local_array_size = 2 + c = sram_config(word_size=4, + num_words=16, num_banks=1) - - c.words_per_row=2 + c.words_per_row=1 c.recompute_sizes() + # c = sram_config(word_size=8, + # num_words=32, + # num_banks=1) + + # c.words_per_row=2 + # c.recompute_sizes() debug.info(1, "Testing timing for global hierarchical array") s = factory.create(module_type="sram", sram_config=c) From 449a4c26607875a02d0fd487078e2d49b8a880a5 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 29 Sep 2020 12:15:42 -0700 Subject: [PATCH 48/83] Exclude bitcells in other local areas not of interest --- compiler/modules/bank.py | 2 +- compiler/modules/bitcell_array.py | 2 +- compiler/modules/global_bitcell_array.py | 33 ++++++++++++++++++++--- compiler/modules/local_bitcell_array.py | 2 +- compiler/modules/replica_bitcell_array.py | 2 +- compiler/sram/sram_1bank.py | 32 +++++++++++++++------- 6 files changed, 55 insertions(+), 18 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 2371a609..41433e46 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -412,7 +412,7 @@ class bank(design.design): def create_bitcell_array(self): """ Creating Bitcell Array """ - self.bitcell_array_inst=self.add_inst(name="replica_bitcell_array", + self.bitcell_array_inst=self.add_inst(name="bitcell_array", mod=self.bitcell_array) # Arrays are always: # word lines (bottom to top) diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 6ce7a7da..03227622 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -104,7 +104,7 @@ class bitcell_array(bitcell_base_array): bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c return bl_wire - def graph_exclude_bits(self, targ_row, targ_col): + def graph_exclude_bits(self, targ_row=None, targ_col=None): """ Excludes bits in column from being added to graph except target """ diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index db6f5f26..4cb384b6 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -272,15 +272,27 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): """ Excludes bits in column from being added to graph except target """ + # This must find which local array includes the specified column # Find the summation of columns that is large and take the one before for i, col in enumerate(self.col_offsets): if col > targ_col: break + else: + i = len(self.local_mods) + # This is the array with the column + local_array = self.local_mods[i - 1] # We must also translate the global array column number to the local array column number - self.local_mods[i - 1].graph_exclude_bits(targ_row, targ_col - self.col_offsets[i - 1]) - + local_col = targ_col - self.col_offsets[i - 1] + + for mod in self.local_mods: + if mod == local_array: + mod.graph_exclude_bits(targ_row, local_col) + else: + # Otherwise, we exclude ALL of the rows/columns + mod.graph_exclude_bits() + def graph_exclude_replica_col_bits(self): """ Exclude all but replica in every local array. @@ -300,8 +312,15 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): else: # In this case, we it should be in the last bitcell array i = len(self.col_offsets) - - return self.local_mods[i - 1].get_cell_name(inst_name + '.x' + self.local_insts[i - 1].name, row, col) + + # This is the local instance + local_inst = self.local_insts[i - 1] + # This is the array with the column + local_array = self.local_mods[i - 1] + # We must also translate the global array column number to the local array column number + local_col = col - self.col_offsets[i - 1] + + return local_array.get_cell_name(inst_name + '.x' + local_inst.name, row, local_col) def clear_exclude_bits(self): """ @@ -309,3 +328,9 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): """ for mod in self.local_mods: mod.clear_exclude_bits() + + def graph_exclude_dffs(self): + """Exclude dffs from graph as they do not represent critical path""" + + self.graph_inst_exclude.add(self.ctrl_dff_inst) + diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index 633478c1..80708dec 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -263,7 +263,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): offsets = [self.bitcell_array_inst.lx() + x for x in self.bitcell_array.get_column_offsets()] return offsets - def graph_exclude_bits(self, targ_row, targ_col): + def graph_exclude_bits(self, targ_row=None, targ_col=None): """ Excludes bits in column from being added to graph except target """ diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 5dffd116..3c093177 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -528,7 +528,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell return bl_wire - def graph_exclude_bits(self, targ_row, targ_col): + def graph_exclude_bits(self, targ_row=None, targ_col=None): """ Excludes bits in column from being added to graph except target """ diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index c67f7233..d35baf23 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -542,7 +542,9 @@ class sram_1bank(sram_base): [data_dff_clk_pos, mid_pos, clk_steiner_pos]) def route_control_logic(self): - """ Route the control logic pins that are not inputs """ + """ + Route the control logic pins that are not inputs + """ for port in self.all_ports: for signal in self.control_logic_outputs[port]: @@ -567,7 +569,9 @@ class sram_1bank(sram_base): offset=dest_pin.center()) def route_row_addr_dff(self): - """ Connect the output of the row flops to the bank pins """ + """ + Connect the output of the row flops to the bank pins + """ for port in self.all_ports: for bit in range(self.row_addr_size): flop_name = "dout_{}".format(bit) @@ -600,7 +604,9 @@ class sram_1bank(sram_base): offset=pin.center()) def graph_exclude_data_dff(self): - """Removes data dff and wmask dff (if applicable) from search graph. """ + """ + Removes data dff and wmask dff (if applicable) from search graph. + """ # Data dffs and wmask dffs are only for writing so are not useful for evaluating read delay. for inst in self.data_dff_insts: self.graph_inst_exclude.add(inst) @@ -612,7 +618,9 @@ class sram_1bank(sram_base): self.graph_inst_exclude.add(inst) def graph_exclude_addr_dff(self): - """Removes data dff from search graph. """ + """ + Removes data dff from search graph. + """ # Address is considered not part of the critical path, subjectively removed for inst in self.row_addr_dff_insts: self.graph_inst_exclude.add(inst) @@ -622,17 +630,21 @@ class sram_1bank(sram_base): self.graph_inst_exclude.add(inst) def graph_exclude_ctrl_dffs(self): - """Exclude dffs for CSB, WEB, etc from graph""" + """ + Exclude dffs for CSB, WEB, etc from graph + """ # Insts located in control logic, exclusion function called here for inst in self.control_logic_insts: inst.mod.graph_exclude_dffs() def get_cell_name(self, inst_name, row, col): - """Gets the spice name of the target bitcell.""" + """ + Gets the spice name of the target bitcell. + """ # Sanity check in case it was forgotten - if inst_name.find('x') != 0: - inst_name = 'x'+inst_name - return self.bank_inst.mod.get_cell_name(inst_name+'.x'+self.bank_inst.name, row, col) + if inst_name.find("x") != 0: + inst_name = "x" + inst_name + return self.bank_inst.mod.get_cell_name(inst_name + ".x" + self.bank_inst.name, row, col) def get_bank_num(self, inst_name, row, col): - return 0; + return 0 From 54890a8d77e50a505735b13beb6a703753eebe7b Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 29 Sep 2020 13:43:34 -0700 Subject: [PATCH 49/83] Add new golden data --- .../tests/21_ngspice_delay_global_test.py | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/compiler/tests/21_ngspice_delay_global_test.py b/compiler/tests/21_ngspice_delay_global_test.py index c2344d90..ac463883 100755 --- a/compiler/tests/21_ngspice_delay_global_test.py +++ b/compiler/tests/21_ngspice_delay_global_test.py @@ -63,35 +63,35 @@ class timing_sram_test(openram_test): data.update(port_data[0]) if OPTS.tech_name == "freepdk45": - golden_data = {'slew_lh': [0.2592187], - 'slew_hl': [0.2592187], - 'delay_lh': [0.2465583], - 'disabled_write0_power': [0.1924678], - 'disabled_read0_power': [0.152483], - 'write0_power': [0.3409064], - 'disabled_read1_power': [0.1737818], - 'read0_power': [0.3096708], - 'read1_power': [0.3107916], - 'delay_hl': [0.2465583], - 'write1_power': [0.26915849999999997], - 'leakage_power': 0.002044307, - 'min_period': 0.898, - 'disabled_write1_power': [0.201411]} + golden_data = {'delay_hl': [0.26308339999999997], + 'delay_lh': [0.26308339999999997], + 'disabled_read0_power': [0.1829355], + 'disabled_read1_power': [0.1962055], + 'disabled_write0_power': [0.2130763], + 'disabled_write1_power': [0.2349011], + 'leakage_power': 0.002509793, + 'min_period': 0.977, + 'read0_power': [0.4028693], + 'read1_power': [0.4055884], + 'slew_hl': [0.27116019999999996], + 'slew_lh': [0.27116019999999996], + 'write0_power': [0.44159149999999997], + 'write1_power': [0.3856132]} elif OPTS.tech_name == "scn4m_subm": - golden_data = {'delay_hl': [1.8435739999999998], - 'delay_lh': [1.8435739999999998], - 'disabled_read0_power': [5.917947], - 'disabled_read1_power': [7.154297], - 'disabled_write0_power': [7.696351], - 'disabled_write1_power': [7.999409000000001], - 'leakage_power': 0.004809726, - 'min_period': 6.875, - 'read0_power': [11.833079999999999], - 'read1_power': [11.99236], - 'slew_hl': [1.8668490000000002], - 'slew_lh': [1.8668490000000002], - 'write0_power': [13.287510000000001], - 'write1_power': [10.416369999999999]} + golden_data = {'delay_hl': [2.0149939999999997], + 'delay_lh': [2.0149939999999997], + 'disabled_read0_power': [7.751129], + 'disabled_read1_power': [9.025803], + 'disabled_write0_power': [9.546656], + 'disabled_write1_power': [10.2449], + 'leakage_power': 0.004770704, + 'min_period': 7.188, + 'read0_power': [17.68452], + 'read1_power': [18.24353], + 'slew_hl': [1.942796], + 'slew_lh': [1.942796], + 'write0_power': [20.02101], + 'write1_power': [15.389470000000001]} else: self.assertTrue(False) # other techs fail From bca69b24e37c8c532ea3eabc93b023e690ca4eaf Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 29 Sep 2020 13:43:54 -0700 Subject: [PATCH 50/83] Optional number of functional cycles --- compiler/characterizer/functional.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index 4fa4f06b..270c1a2b 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -21,7 +21,7 @@ class functional(simulation): for successful SRAM operation. """ - def __init__(self, sram, spfile, corner): + def __init__(self, sram, spfile, corner, cycles=15): super().__init__(sram, spfile, corner) # Seed the characterizer with a constant seed for unit tests @@ -52,7 +52,7 @@ class functional(simulation): debug.info(2, "q name={}\nqbar name={}".format(self.q_name, self.qbar_name)) # Number of checks can be changed - self.num_cycles = 15 + self.num_cycles = cycles # This is to have ordered keys for random selection self.stored_words = collections.OrderedDict() self.read_check = [] From 8e908f016ee92782c42679b1ce8da1a2eaf89b55 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 29 Sep 2020 13:43:59 -0700 Subject: [PATCH 51/83] PEP8 formatting --- compiler/tests/22_psram_1bank_2mux_func_test.py | 9 +++++---- compiler/tests/22_psram_1bank_4mux_func_test.py | 9 +++++---- compiler/tests/22_psram_1bank_8mux_func_test.py | 9 +++++---- compiler/tests/22_psram_1bank_nomux_func_test.py | 8 ++++---- compiler/tests/22_sram_1bank_2mux_func_test.py | 9 +++++---- compiler/tests/22_sram_1bank_2mux_global_func_test.py | 9 +++++---- compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py | 9 +++++---- compiler/tests/22_sram_1bank_4mux_func_test.py | 9 +++++---- compiler/tests/22_sram_1bank_8mux_func_test.py | 9 +++++---- compiler/tests/22_sram_1bank_nomux_1rw_1r_func_test.py | 9 +++++---- compiler/tests/22_sram_1bank_nomux_func_test.py | 5 +++-- .../tests/22_sram_1bank_nomux_sparecols_func_test.py | 5 +++-- compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py | 2 +- compiler/tests/22_sram_wmask_func_test.py | 5 +++-- 14 files changed, 59 insertions(+), 47 deletions(-) diff --git a/compiler/tests/22_psram_1bank_2mux_func_test.py b/compiler/tests/22_psram_1bank_2mux_func_test.py index 7a6da149..5e4040d6 100755 --- a/compiler/tests/22_psram_1bank_2mux_func_test.py +++ b/compiler/tests/22_psram_1bank_2mux_func_test.py @@ -8,13 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + class psram_1bank_2mux_func_test(openram_test): def runTest(self): @@ -36,7 +37,7 @@ class psram_1bank_2mux_func_test(openram_test): from importlib import reload import characterizer reload(characterizer) - from characterizer import functional, delay + from characterizer import functional from sram_config import sram_config c = sram_config(word_size=2, num_words=32, @@ -52,13 +53,13 @@ class psram_1bank_2mux_func_test(openram_test): c.words_per_row, c.num_banks)) s = factory.create(module_type="sram", sram_config=c) - tempspice = OPTS.openram_temp + "sram.sp" + tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail,error) + self.assertTrue(fail, error) globals.end_openram() diff --git a/compiler/tests/22_psram_1bank_4mux_func_test.py b/compiler/tests/22_psram_1bank_4mux_func_test.py index facd3874..2c51f2f3 100755 --- a/compiler/tests/22_psram_1bank_4mux_func_test.py +++ b/compiler/tests/22_psram_1bank_4mux_func_test.py @@ -8,13 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + #@unittest.skip("SKIPPING 22_psram_1bank_4mux_func_test, third port reads are broken?") class psram_1bank_4mux_func_test(openram_test): @@ -37,7 +38,7 @@ class psram_1bank_4mux_func_test(openram_test): from importlib import reload import characterizer reload(characterizer) - from characterizer import functional, delay + from characterizer import functional from sram_config import sram_config c = sram_config(word_size=2, num_words=256, @@ -53,13 +54,13 @@ class psram_1bank_4mux_func_test(openram_test): c.words_per_row, c.num_banks)) s = factory.create(module_type="sram", sram_config=c) - tempspice = OPTS.openram_temp + "sram.sp" + tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail,error) + self.assertTrue(fail, error) globals.end_openram() diff --git a/compiler/tests/22_psram_1bank_8mux_func_test.py b/compiler/tests/22_psram_1bank_8mux_func_test.py index acf0c3a4..447b7512 100755 --- a/compiler/tests/22_psram_1bank_8mux_func_test.py +++ b/compiler/tests/22_psram_1bank_8mux_func_test.py @@ -8,13 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + #@unittest.skip("SKIPPING 22_psram_1bank_8mux_func_test") class psram_1bank_8mux_func_test(openram_test): @@ -37,7 +38,7 @@ class psram_1bank_8mux_func_test(openram_test): from importlib import reload import characterizer reload(characterizer) - from characterizer import functional, delay + from characterizer import functional from sram_config import sram_config c = sram_config(word_size=4, num_words=256, @@ -53,13 +54,13 @@ class psram_1bank_8mux_func_test(openram_test): c.words_per_row, c.num_banks)) s = factory.create(module_type="sram", sram_config=c) - tempspice = OPTS.openram_temp + "sram.sp" + tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail,error) + self.assertTrue(fail, error) globals.end_openram() diff --git a/compiler/tests/22_psram_1bank_nomux_func_test.py b/compiler/tests/22_psram_1bank_nomux_func_test.py index b7d6cf78..5f2e81c8 100755 --- a/compiler/tests/22_psram_1bank_nomux_func_test.py +++ b/compiler/tests/22_psram_1bank_nomux_func_test.py @@ -8,7 +8,7 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS @@ -37,7 +37,7 @@ class psram_1bank_nomux_func_test(openram_test): from importlib import reload import characterizer reload(characterizer) - from characterizer import functional, delay + from characterizer import functional from sram_config import sram_config c = sram_config(word_size=2, num_words=32, @@ -53,13 +53,13 @@ class psram_1bank_nomux_func_test(openram_test): c.words_per_row, c.num_banks)) s = factory.create(module_type="sram", sram_config=c) - tempspice = OPTS.openram_temp + "sram.sp" + tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail,error) + self.assertTrue(fail, error) globals.end_openram() diff --git a/compiler/tests/22_sram_1bank_2mux_func_test.py b/compiler/tests/22_sram_1bank_2mux_func_test.py index 10d19c1c..20ac52f0 100755 --- a/compiler/tests/22_sram_1bank_2mux_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_func_test.py @@ -8,13 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + #@unittest.skip("SKIPPING 22_sram_1bank_2mux_func_test") class sram_1bank_2mux_func_test(openram_test): @@ -29,7 +30,7 @@ class sram_1bank_2mux_func_test(openram_test): from importlib import reload import characterizer reload(characterizer) - from characterizer import functional, delay + from characterizer import functional from sram_config import sram_config c = sram_config(word_size=4, num_words=32, @@ -42,13 +43,13 @@ class sram_1bank_2mux_func_test(openram_test): c.words_per_row, c.num_banks)) s = factory.create(module_type="sram", sram_config=c) - tempspice = OPTS.openram_temp + "sram.sp" + tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail,error) + self.assertTrue(fail, error) globals.end_openram() diff --git a/compiler/tests/22_sram_1bank_2mux_global_func_test.py b/compiler/tests/22_sram_1bank_2mux_global_func_test.py index c8ff5969..e5b8853a 100755 --- a/compiler/tests/22_sram_1bank_2mux_global_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_global_func_test.py @@ -8,13 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + #@unittest.skip("SKIPPING 22_sram_1bank_2mux_func_test") class sram_1bank_2mux_func_test(openram_test): @@ -29,7 +30,7 @@ class sram_1bank_2mux_func_test(openram_test): from importlib import reload import characterizer reload(characterizer) - from characterizer import functional, delay + from characterizer import functional from sram_config import sram_config OPTS.local_array_size = 8 OPTS.route_supplies = False @@ -44,13 +45,13 @@ class sram_1bank_2mux_func_test(openram_test): c.words_per_row, c.num_banks)) s = factory.create(module_type="sram", sram_config=c) - tempspice = OPTS.openram_temp + "sram.sp" + tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail,error) + self.assertTrue(fail, error) globals.end_openram() diff --git a/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py b/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py index 902cacdd..a09ab17e 100755 --- a/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py @@ -8,13 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + #@unittest.skip("SKIPPING 22_sram_1bank_2mux_sparecols_func_test") class sram_1bank_2mux_sparecols_func_test(openram_test): @@ -29,7 +30,7 @@ class sram_1bank_2mux_sparecols_func_test(openram_test): from importlib import reload import characterizer reload(characterizer) - from characterizer import functional, delay + from characterizer import functional from sram_config import sram_config c = sram_config(word_size=4, num_words=32, @@ -44,13 +45,13 @@ class sram_1bank_2mux_sparecols_func_test(openram_test): c.num_spare_cols, c.num_banks)) s = factory.create(module_type="sram", sram_config=c) - tempspice = OPTS.openram_temp + "sram.sp" + tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail,error) + self.assertTrue(fail, error) globals.end_openram() diff --git a/compiler/tests/22_sram_1bank_4mux_func_test.py b/compiler/tests/22_sram_1bank_4mux_func_test.py index d2bf7886..baa25906 100755 --- a/compiler/tests/22_sram_1bank_4mux_func_test.py +++ b/compiler/tests/22_sram_1bank_4mux_func_test.py @@ -8,13 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + #@unittest.skip("SKIPPING 22_sram_1bank_4mux_func_test") class sram_1bank_4mux_func_test(openram_test): @@ -29,7 +30,7 @@ class sram_1bank_4mux_func_test(openram_test): from importlib import reload import characterizer reload(characterizer) - from characterizer import functional, delay + from characterizer import functional from sram_config import sram_config c = sram_config(word_size=4, num_words=128, @@ -42,13 +43,13 @@ class sram_1bank_4mux_func_test(openram_test): c.words_per_row, c.num_banks)) s = factory.create(module_type="sram", sram_config=c) - tempspice = OPTS.openram_temp + "sram.sp" + tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail,error) + self.assertTrue(fail, error) globals.end_openram() diff --git a/compiler/tests/22_sram_1bank_8mux_func_test.py b/compiler/tests/22_sram_1bank_8mux_func_test.py index 3f6ff55f..d9cd794a 100755 --- a/compiler/tests/22_sram_1bank_8mux_func_test.py +++ b/compiler/tests/22_sram_1bank_8mux_func_test.py @@ -8,13 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + #@unittest.skip("SKIPPING 22_sram_1bank_8mux_func_test") class sram_1bank_8mux_func_test(openram_test): @@ -29,7 +30,7 @@ class sram_1bank_8mux_func_test(openram_test): from importlib import reload import characterizer reload(characterizer) - from characterizer import functional, delay + from characterizer import functional if not OPTS.spice_exe: debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) @@ -45,13 +46,13 @@ class sram_1bank_8mux_func_test(openram_test): c.words_per_row, c.num_banks)) s = factory.create(module_type="sram", sram_config=c) - tempspice = OPTS.openram_temp + "sram.sp" + tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail,error) + self.assertTrue(fail, error) globals.end_openram() diff --git a/compiler/tests/22_sram_1bank_nomux_1rw_1r_func_test.py b/compiler/tests/22_sram_1bank_nomux_1rw_1r_func_test.py index f2958f9f..50906e62 100755 --- a/compiler/tests/22_sram_1bank_nomux_1rw_1r_func_test.py +++ b/compiler/tests/22_sram_1bank_nomux_1rw_1r_func_test.py @@ -8,13 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + #@unittest.skip("SKIPPING 22_sram_1rw_1r_1bank_nomux_func_test") class psram_1bank_nomux_func_test(openram_test): @@ -33,7 +34,7 @@ class psram_1bank_nomux_func_test(openram_test): from importlib import reload import characterizer reload(characterizer) - from characterizer import functional, delay + from characterizer import functional from sram_config import sram_config c = sram_config(word_size=4, num_words=32, @@ -46,13 +47,13 @@ class psram_1bank_nomux_func_test(openram_test): c.words_per_row, c.num_banks)) s = factory.create(module_type="sram", sram_config=c) - tempspice = OPTS.openram_temp + "sram.sp" + tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail,error) + self.assertTrue(fail, error) globals.end_openram() diff --git a/compiler/tests/22_sram_1bank_nomux_func_test.py b/compiler/tests/22_sram_1bank_nomux_func_test.py index 2aa20e99..0af55ec2 100755 --- a/compiler/tests/22_sram_1bank_nomux_func_test.py +++ b/compiler/tests/22_sram_1bank_nomux_func_test.py @@ -8,13 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + #@unittest.skip("SKIPPING 22_sram_func_test") class sram_1bank_nomux_func_test(openram_test): @@ -47,7 +48,7 @@ class sram_1bank_nomux_func_test(openram_test): corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail,error) + self.assertTrue(fail, error) globals.end_openram() diff --git a/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py b/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py index 347d15d0..dbb9d7b2 100755 --- a/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py +++ b/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py @@ -8,13 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + #@unittest.skip("SKIPPING 22_sram_func_test") class sram_1bank_nomux_sparecols_func_test(openram_test): @@ -48,7 +49,7 @@ class sram_1bank_nomux_sparecols_func_test(openram_test): corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail,error) + self.assertTrue(fail, error) globals.end_openram() diff --git a/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py b/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py index 07cff70e..7ab35824 100755 --- a/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py +++ b/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py @@ -35,7 +35,7 @@ class sram_wmask_1w_1r_func_test(openram_test): from importlib import reload import characterizer reload(characterizer) - from characterizer import functional, delay + from characterizer import functional from sram_config import sram_config c = sram_config(word_size=8, num_words=16, diff --git a/compiler/tests/22_sram_wmask_func_test.py b/compiler/tests/22_sram_wmask_func_test.py index d29795a9..b59c3b95 100755 --- a/compiler/tests/22_sram_wmask_func_test.py +++ b/compiler/tests/22_sram_wmask_func_test.py @@ -8,13 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + #@unittest.skip("SKIPPING sram_wmask_func_test") class sram_wmask_func_test(openram_test): @@ -29,7 +30,7 @@ class sram_wmask_func_test(openram_test): from importlib import reload import characterizer reload(characterizer) - from characterizer import functional, delay + from characterizer import functional from sram_config import sram_config c = sram_config(word_size=8, num_words=16, From 066570bfeb6f5ce8bf22588c594867f74c90ba0b Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 29 Sep 2020 16:51:55 -0700 Subject: [PATCH 52/83] Fix length of write driver --- compiler/modules/write_driver_array.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index a2458f42..a5ee20f8 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -215,27 +215,25 @@ class write_driver_array(design.design): start_layer=pin.layer) if self.write_size: for bit in range(self.num_wmasks): - inst = self.driver_insts[bit * self.write_size] - en_pin = inst.get_pin(inst.mod.en_name) - # Determine width of wmask modified en_pin with/without col mux - wmask_en_len = self.words_per_row * (self.write_size * self.driver_spacing) - if (self.words_per_row == 1): - en_gap = self.driver_spacing - en_pin.width() - else: - en_gap = self.driver_spacing + first_inst = self.driver_insts[bit * self.write_size] + first_en_pin = first_inst.get_pin(first_inst.mod.en_name) + last_inst = self.driver_insts[(bit + 1) * self.write_size - 1] + last_en_pin = last_inst.get_pin(last_inst.mod.en_name) + + wmask_en_len = last_en_pin.rx() - first_en_pin.lx() self.add_layout_pin(text=self.en_name + "_{0}".format(bit), - layer=en_pin.layer, - offset=en_pin.ll(), - width=wmask_en_len - en_gap, - height=en_pin.height()) + layer=first_en_pin.layer, + offset=first_en_pin.ll(), + width=wmask_en_len, + height=first_en_pin.height()) for i in range(self.num_spare_cols): inst = self.driver_insts[self.word_size + i] en_pin = inst.get_pin(inst.mod.en_name) self.add_layout_pin(text=self.en_name + "_{0}".format(i + self.num_wmasks), layer="m1", - offset=en_pin.lr() + vector(-drc("minwidth_m1"),0)) + offset=en_pin.lr() + vector(-drc("minwidth_m1"), 0)) elif self.num_spare_cols and not self.write_size: # shorten enable rail to accomodate those for spare write drivers From b147e8485cab916c545b5a3c34c45c5da2313e45 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 29 Sep 2020 16:52:27 -0700 Subject: [PATCH 53/83] PEP8 formatting --- compiler/modules/bank.py | 7 +++--- compiler/options.py | 3 --- compiler/sram/sram_base.py | 35 +++++++++++++++++----------- compiler/sram/sram_config.py | 2 +- compiler/tests/50_riscv_func_test.py | 9 +++---- compiler/tests/50_riscv_phys_test.py | 5 ++-- 6 files changed, 34 insertions(+), 27 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 41433e46..52cf9b8d 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -8,8 +8,8 @@ import debug import design from sram_factory import factory -from math import log, ceil, floor -from tech import drc, layer +from math import log, ceil, floor, sqrt +from tech import drc from vector import vector from globals import OPTS @@ -377,7 +377,8 @@ class bank(design.design): try: local_array_size = OPTS.local_array_size except AttributeError: - local_array_size = 0 + #local_array_size = ceil(sqrt(self.num_cols + self.num_spare_cols)) + local_array_size = ceil(sqrt(self.num_cols + self.num_spare_cols)) if local_array_size > 0: # Find the even multiple that satisfies the fanout with equal sized local arrays diff --git a/compiler/options.py b/compiler/options.py index b9be3999..8de3b910 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -30,9 +30,6 @@ class options(optparse.Values): num_r_ports = 0 num_w_ports = 0 - # By default, use local arrays with a max fanout of 16 - #local_array_size = 16 - # Write mask size, default will be overwritten with word_size if not user specified write_size = None diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index d18e1366..fbefc2de 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -87,8 +87,8 @@ class sram_base(design, verilog, lef): for bit in range(self.word_size + self.num_spare_cols): self.add_pin("dout{0}[{1}]".format(port, bit), "OUTPUT") - self.add_pin("vdd","POWER") - self.add_pin("gnd","GROUND") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def add_global_pex_labels(self): """ @@ -118,8 +118,19 @@ class sram_base(design, verilog, lef): Q = [bank_offset[cell][0] + Q_offset[cell][0], bank_offset[cell][1] + Q_offset[cell][1]] Q_bar = [bank_offset[cell][0] + Q_bar_offset[cell][0], bank_offset[cell][1] + Q_bar_offset[cell][1]] OPTS.words_per_row = self.words_per_row - self.add_layout_pin_rect_center("bitcell_Q_b{}_r{}_c{}".format(bank_num, int(cell % (OPTS.num_words / self.words_per_row)), int(cell / (OPTS.num_words))) , storage_layer_name, Q) - self.add_layout_pin_rect_center("bitcell_Q_bar_b{}_r{}_c{}".format(bank_num, int(cell % (OPTS.num_words / self.words_per_row)), int(cell / (OPTS.num_words))), storage_layer_name, Q_bar) + row = int(cell % (OPTS.num_words / self.words_per_row)) + col = int(cell / (OPTS.num_words)) + self.add_layout_pin_rect_center("bitcell_Q_b{}_r{}_c{}".format(bank_num, + row, + col, + storage_layer_name, + Q)) + + self.add_layout_pin_rect_center("bitcell_Q_bar_b{}_r{}_c{}".format(bank_num, + row, + col, + storage_layer_name, + Q_bar)) for cell in range(len(bl_offsets)): col = bl_meta[cell][0][2] @@ -131,27 +142,23 @@ class sram_base(design, verilog, lef): col = br_meta[cell][0][2] for bitline in range(len(br_offsets[cell])): bitline_location = [float(bank_offset[cell][0]) + br_offsets[cell][bitline][0], float(bank_offset[cell][1]) + br_offsets[cell][bitline][1]] - br.append([bitline_location, br_meta[cell][bitline][3], col]) + br.append([bitline_location, br_meta[cell][bitline][3], col]) for i in range(len(bl)): - self.add_layout_pin_rect_center("bl{0}_{1}".format(bl[i][1], bl[i][2]), bitline_layer_name, bl[i][0]) + self.add_layout_pin_rect_center("bl{0}_{1}".format(bl[i][1], bl[i][2]), bitline_layer_name, bl[i][0]) for i in range(len(br)): - self.add_layout_pin_rect_center("br{0}_{1}".format(br[i][1], br[i][2]), bitline_layer_name, br[i][0]) + self.add_layout_pin_rect_center("br{0}_{1}".format(br[i][1], br[i][2]), bitline_layer_name, br[i][0]) # add pex labels for control logic - for i in range (len(self.control_logic_insts)): + for i in range(len(self.control_logic_insts)): instance = self.control_logic_insts[i] control_logic_offset = instance.offset for output in instance.mod.output_list: pin = instance.mod.get_pin(output) - pin.transform([0,0], instance.mirror, instance.rotate) + pin.transform([0, 0], instance.mirror, instance.rotate) offset = [control_logic_offset[0] + pin.center()[0], control_logic_offset[1] + pin.center()[1]] - self.add_layout_pin_rect_center("{0}{1}".format(pin.name,i), storage_layer_name, offset) - - - - + self.add_layout_pin_rect_center("{0}{1}".format(pin.name, i), storage_layer_name, offset) def create_netlist(self): """ Netlist creation """ diff --git a/compiler/sram/sram_config.py b/compiler/sram/sram_config.py index fa70d730..ee137e4a 100644 --- a/compiler/sram/sram_config.py +++ b/compiler/sram/sram_config.py @@ -25,7 +25,7 @@ class sram_config: # This will get over-written when we determine the organization self.words_per_row = words_per_row - self.compute_sizes() + self.compute_sizes() def set_local_config(self, module): """ Copy all of the member variables to the given module for convenience """ diff --git a/compiler/tests/50_riscv_func_test.py b/compiler/tests/50_riscv_func_test.py index 1d5720f7..da2e3786 100755 --- a/compiler/tests/50_riscv_func_test.py +++ b/compiler/tests/50_riscv_func_test.py @@ -8,14 +8,15 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug -@unittest.skip("SKIPPING 50_riscv_func_test") + +# @unittest.skip("SKIPPING 50_riscv_func_test") class riscv_func_test(openram_test): def runTest(self): @@ -33,7 +34,7 @@ class riscv_func_test(openram_test): from importlib import reload import characterizer reload(characterizer) - from characterizer import functional, delay + from characterizer import functional from sram_config import sram_config c = sram_config(word_size=32, write_size=8, @@ -53,7 +54,7 @@ class riscv_func_test(openram_test): corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail,error) + self.assertTrue(fail, error) globals.end_openram() diff --git a/compiler/tests/50_riscv_phys_test.py b/compiler/tests/50_riscv_phys_test.py index 0ae11025..4b51084f 100755 --- a/compiler/tests/50_riscv_phys_test.py +++ b/compiler/tests/50_riscv_phys_test.py @@ -8,14 +8,15 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug -@unittest.skip("SKIPPING 50_riscv_phys_test") + +# @unittest.skip("SKIPPING 50_riscv_phys_test") class riscv_phys_test(openram_test): def runTest(self): From 7cbf456a4fa502b2e5262fb1adf43d3028e04bd6 Mon Sep 17 00:00:00 2001 From: jcirimel Date: Wed, 30 Sep 2020 07:34:05 -0700 Subject: [PATCH 54/83] sky130 rba done --- compiler/custom/s8_col_end.py | 4 +- compiler/custom/s8_corner.py | 2 +- compiler/custom/s8_replica_bitcell.py | 18 +- compiler/modules/bitcell_array.py | 3 - compiler/modules/dummy_array.py | 34 +- compiler/modules/replica_bitcell_array.py | 181 ++- compiler/modules/replica_column.py | 26 +- compiler/tests/sram_1b_16_1rw_sky130.log | 1768 ++++++++++++++++++++- missing_pin.gds | Bin 3328 -> 7442 bytes sram_1b_16_1rw_sky130.log | 10 +- 10 files changed, 1949 insertions(+), 97 deletions(-) diff --git a/compiler/custom/s8_col_end.py b/compiler/custom/s8_col_end.py index a6961027..827692f0 100644 --- a/compiler/custom/s8_col_end.py +++ b/compiler/custom/s8_col_end.py @@ -21,8 +21,8 @@ class s8_col_end(design.design): type_list = [] if version == "colend": - self.name = "s8sram16x16_colend" - structure = "s8sram16x16_colend\x00" + self.name = "s8sram16x16_colenda" + structure = "s8sram16x16_colenda\x00" elif version == "colend_p_cent": self.name = "s8sram16x16_colend_p_cent" structure = "s8sram16x16_colend_p_cent\x00" diff --git a/compiler/custom/s8_corner.py b/compiler/custom/s8_corner.py index bb4fec51..a0144c00 100644 --- a/compiler/custom/s8_corner.py +++ b/compiler/custom/s8_corner.py @@ -27,7 +27,7 @@ class s8_corner(design.design): elif location == "ll": self.name = "s8sram16x16_cornera" elif location == "lr": - self.name = "s8sram16x16_cornerb" + self.name = "s8sram16x16_cornera" else: debug.error("Invalid s8_corner location", -1) design.design.__init__(self, name=self.name) diff --git a/compiler/custom/s8_replica_bitcell.py b/compiler/custom/s8_replica_bitcell.py index dd8fae0c..25965d9e 100644 --- a/compiler/custom/s8_replica_bitcell.py +++ b/compiler/custom/s8_replica_bitcell.py @@ -33,14 +33,26 @@ class replica_bitcell(design.design): type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] if not OPTS.netlist_only: - (width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"]) - pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"]) + (self.width, self.height) = utils.get_libcell_size(self.name, + GDS["unit"], + layer["mem"], + "s8sram_cell\x00") + self.pin_map = utils.get_libcell_pins(self.pin_names, self.name, GDS["unit"]) else: (width,height) = (0,0) pin_map = [] - def __init__(self, name=""): + def __init__(self, version, name=""): # Ignore the name argument + + if version == "opt1": + self.name = "s8sram_cell_opt1" + self.border_structure = "s8sram_cell" + elif version == "opt1a": + self.name = "s8sram_cell_opt1a" + self.border_structure = "s8sram_cell" + + self.pin_map = utils.get_libcell_pins(self.pin_names, self.name, GDS["unit"]) design.design.__init__(self, "replica_cell_6t") debug.info(2, "Create replica bitcell object") diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 9f908bbe..29bcb57a 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -58,9 +58,6 @@ class bitcell_array(bitcell_base_array): self.add_mod(factory.create(module_type="s8_internal", version = "wlstrap")) self.add_mod(factory.create(module_type="s8_internal", version = "wlstrap_p")) - - - def create_instances(self): """ Create the module instances used in this design """ diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py index 9004994b..bb4f72a2 100644 --- a/compiler/modules/dummy_array.py +++ b/compiler/modules/dummy_array.py @@ -5,6 +5,8 @@ # from bitcell_base_array import bitcell_base_array from sram_factory import factory +from tech import GDS,layer,drc,parameter,cell_properties +from tech import cell_properties as props from globals import OPTS @@ -38,21 +40,33 @@ class dummy_array(bitcell_base_array): def add_modules(self): """ Add the modules used in this design """ - self.dummy_cell = factory.create(module_type="dummy_{}".format(OPTS.bitcell)) + + if not props.compare_ports(props.bitcell_array.use_custom_cell_arrangement): + self.dummy_cell = factory.create(module_type="dummy_{}".format(OPTS.bitcell)) + self.cell = factory.create(module_type="bitcell") + else: + self.dummy_cell = factory.create(module_type="s8_bitcell", version = "opt1") + self.dummy_cell2 = factory.create(module_type="s8_bitcell", version = "opt1a") + self.add_mod(factory.create(module_type="s8_internal", version = "wlstrap")) + self.add_mod(factory.create(module_type="s8_internal", version = "wlstrap_p")) + self.cell = factory.create(module_type="s8_bitcell", version = "opt1") + self.add_mod(self.dummy_cell2) self.add_mod(self.dummy_cell) - - self.cell = factory.create(module_type="bitcell") def create_instances(self): """ Create the module instances used in this design """ self.cell_inst = {} - for col in range(self.column_size): - for row in range(self.row_size): - name = "bit_r{0}_c{1}".format(row, col) - self.cell_inst[row, col]=self.add_inst(name=name, - mod=self.dummy_cell) - self.connect_inst(self.get_bitcell_pins(row, col)) - + if not props.compare_ports(props.bitcell_array.use_custom_cell_arrangement): + for col in range(self.column_size): + for row in range(self.row_size): + name = "bit_r{0}_c{1}".format(row, col) + self.cell_inst[row, col]=self.add_inst(name=name, + mod=self.dummy_cell) + self.connect_inst(self.get_bitcell_pins(row, col)) + else: + from tech import custom_cell_arrangement + custom_cell_arrangement(self) + def input_load(self): wl_wire = self.gen_wl_wire() return wl_wire.return_input_cap() diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index d3c25ba0..e98a51dc 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -45,15 +45,11 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): debug.check(sum(rbl) <= len(self.all_ports), "Invalid number of RBLs for port configuration.") - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - # Two dummy rows plus replica even if we don't add the column - self.extra_rows = 2 + sum(rbl) - # Two dummy cols plus replica if we add the column - self.extra_cols = 2 + self.add_left_rbl + self.add_right_rbl - else: - self.extra_rows = 0 - self.extra_cols = 2 + self.add_left_rbl + self.add_right_rbl + # Two dummy rows plus replica even if we don't add the column + self.extra_rows = 2 + sum(rbl) + # Two dummy cols plus replica if we add the column + self.extra_cols = 2 + self.add_left_rbl + self.add_right_rbl self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -123,15 +119,15 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): end_caps_enabled = cell_properties.bitcell.end_caps except AttributeError: end_caps_enabled = False - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): # Dummy row - self.dummy_row = factory.create(module_type="dummy_array", + self.dummy_row = factory.create(module_type="dummy_array", cols=self.column_size, rows=1, # dummy column + left replica column column_offset=1 + self.add_left_rbl, mirror=0) - self.add_mod(self.dummy_row) + self.add_mod(self.dummy_row) + if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): # Dummy Row or Col Cap, depending on bitcell array properties col_cap_module_type = ("col_cap_array" if end_caps_enabled else "dummy_array") @@ -164,6 +160,25 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): mirror=(self.left_rbl + 1) %2) self.add_mod(self.row_cap_right) else: + # Dummy Row or Col Cap, depending on bitcell array properties + col_cap_module_type = ("s8_col_cap_array" if end_caps_enabled else "dummy_array") + self.col_cap_top = factory.create(module_type=col_cap_module_type, + cols=self.column_size, + rows=1, + # dummy column + left replica column(s) + column_offset=1 + self.add_left_rbl, + mirror=0, + location="top") + self.add_mod(self.col_cap_top) + + self.col_cap_bottom = factory.create(module_type=col_cap_module_type, + cols=self.column_size, + rows=1, + # dummy column + left replica column(s) + column_offset=1 + self.add_left_rbl, + mirror=0, + location="bottom") + self.add_mod(self.col_cap_bottom) # Dummy Col or Row Cap, depending on bitcell array properties row_cap_module_type = ("s8_row_cap_array" if end_caps_enabled else "dummy_array") @@ -258,8 +273,15 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): self.all_dummy_row_wordline_names = [x for sl in self.dummy_row_wordline_names for x in sl] for port in range(self.left_rbl + self.right_rbl): - wordline_names=["rbl_wl_{0}_{1}".format(x, port) for x in self.all_ports] - self.rbl_wordline_names.append(wordline_names) + if not cell_properties.compare_ports(cell_properties.bitcell.split_wl): + wordline_names=["rbl_wl_{0}_{1}".format(x, port) for x in self.all_ports] + self.rbl_wordline_names.append(wordline_names) + else: + for x in self.all_ports: + wordline_names = [] + wordline_names.append("rbl_wl0_{0}_{1}".format(x, port)) + wordline_names.append("rbl_wl1_{0}_{1}".format(x, port)) + self.rbl_wordline_names.append(wordline_names) self.all_rbl_wordline_names = [x for sl in self.rbl_wordline_names for x in sl] for port in self.all_ports: @@ -290,8 +312,11 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def create_instances(self): """ Create the module instances used in this design """ - - supplies = ["vdd", "gnd"] + + if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): + self.supplies = ["vdd", "gnd"] + else: + self.supplies = ["vpwr", "vgnd"] # Used for names/dimensions only if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): @@ -302,52 +327,82 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # Main array self.bitcell_array_inst=self.add_inst(name="bitcell_array", mod=self.bitcell_array) - self.connect_inst(self.all_bitline_names + self.all_wordline_names + supplies) + self.connect_inst(self.all_bitline_names + self.all_wordline_names + self.supplies) # Replica columns self.replica_col_insts = [] for port in range(self.add_left_rbl + self.add_right_rbl): self.replica_col_insts.append(self.add_inst(name="replica_col_{}".format(port), mod=self.replica_columns[port])) - self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + supplies) - + self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + self.supplies) # Dummy rows under the bitcell array (connected with with the replica cell wl) self.dummy_row_replica_insts = [] # Note, this is the number of left and right even if we aren't adding the columns to this bitcell array! for port in range(self.left_rbl + self.right_rbl): self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port), - mod=self.dummy_row)) - self.connect_inst(self.all_bitline_names + self.rbl_wordline_names[port] + supplies) + mod=self.dummy_row)) + self.connect_inst(self.all_bitline_names + self.rbl_wordline_names[port] + self.supplies) - # Top/bottom dummy rows or col caps - self.dummy_row_insts = [] - self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot", - mod=self.col_cap)) - self.connect_inst(self.all_bitline_names - + self.dummy_row_wordline_names[0] - + supplies) - self.dummy_row_insts.append(self.add_inst(name="dummy_row_top", - mod=self.col_cap)) - self.connect_inst(self.all_bitline_names - + self.dummy_row_wordline_names[1] - + supplies) - # Left/right Dummy columns - self.dummy_col_insts = [] - self.dummy_col_insts.append(self.add_inst(name="dummy_col_left", - mod=self.row_cap_left)) - self.connect_inst(self.dummy_col_bitline_names[0] + self.replica_array_wordline_names + supplies) - self.dummy_col_insts.append(self.add_inst(name="dummy_col_right", - mod=self.row_cap_right)) - self.connect_inst(self.dummy_col_bitline_names[1] + self.replica_array_wordline_names + supplies) + if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): + # Top/bottom dummy rows or col caps + self.dummy_row_insts = [] + self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot", + mod=self.col_cap)) + self.connect_inst(self.all_bitline_names + + self.dummy_row_wordline_names[0] + + self.supplies) + self.dummy_row_insts.append(self.add_inst(name="dummy_row_top", + mod=self.col_cap)) + self.connect_inst(self.all_bitline_names + + self.dummy_row_wordline_names[1] + + self.supplies) + # Left/right Dummy columns + self.dummy_col_insts = [] + self.dummy_col_insts.append(self.add_inst(name="dummy_col_left", + mod=self.row_cap_left)) + self.connect_inst(self.dummy_col_bitline_names[0] + self.replica_array_wordline_names + self.supplies) + self.dummy_col_insts.append(self.add_inst(name="dummy_col_right", + mod=self.row_cap_right)) + self.connect_inst(self.dummy_col_bitline_names[1] + self.replica_array_wordline_names + self.supplies) + else: + # Top/bottom dummy rows or col caps + self.dummy_row_insts = [] + self.dummy_row_insts.append(self.add_inst(name="col_cap_bottom", + mod=self.col_cap_bottom)) + self.connect_inst(self.all_bitline_names + + self.supplies) + self.dummy_row_insts.append(self.add_inst(name="col_cap_top", + mod=self.col_cap_top)) + self.connect_inst(self.all_bitline_names + + self.supplies) + # Left/right Dummy columns + self.dummy_col_insts = [] + self.dummy_col_insts.append(self.add_inst(name="row_cap_left", + mod=self.row_cap_left)) + self.connect_inst(self.replica_array_wordline_names + self.supplies) + self.dummy_col_insts.append(self.add_inst(name="row_cap_right", + mod=self.row_cap_right)) + self.connect_inst(self.replica_array_wordline_names + self.supplies) def create_layout(self): - - self.height = (self.row_size + self.extra_rows) * self.dummy_row.height - self.width = (self.column_size + self.extra_cols) * self.cell.width + if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): + self.height = (self.row_size + self.extra_rows) * self.dummy_row.height + self.width = (self.column_size + self.extra_cols) * self.cell.width + else: + self.width = self.row_cap_left.top_corner.width + self.row_cap_right.top_corner.width + (self.col_cap_top.colend1.width + self.col_cap_top.colend2.width) * (self.column_size + self.extra_cols) - self.col_cap_top.colend2.width + self.height = self.row_cap_left.height # This is a bitcell x bitcell offset to scale self.bitcell_offset = vector(self.cell.width, self.cell.height) + if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): + self.strap_offset = vector(0, 0) + self.col_end_offset = vector(self.cell.width, self.cell.height) + self.row_end_offset = vector(self.cell.width, self.cell.height) + else: + self.strap_offset = vector(self.replica_col_insts[0].mod.strap1.width, self.replica_col_insts[0].mod.strap1.height) + self.col_end_offset = vector(self.dummy_row_insts[0].mod.colend1.width, self.dummy_row_insts[0].mod.colend1.height) + self.row_end_offset = vector(self.dummy_col_insts[0].mod.rowend1.width, self.dummy_col_insts[0].mod.rowend1.height) # Everything is computed with the main array at (0, 0) to start self.bitcell_array_inst.place(offset=[0, 0]) @@ -368,14 +423,23 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def add_replica_columns(self): """ Add replica columns on left and right of array """ + end_caps_enabled = cell_properties.bitcell.end_caps # Grow from left to right, toward the array for bit in range(self.add_left_rbl): - offset = self.bitcell_offset.scale(-self.add_left_rbl + bit, -self.left_rbl - 1) + if not end_caps_enabled: + offset = self.bitcell_offset.scale(-self.add_left_rbl + bit, -self.left_rbl - 1) + self.strap_offset.scale(-self.add_left_rbl + bit, 0) + else: + offset = self.bitcell_offset.scale(-self.add_left_rbl + bit, -self.left_rbl - (self.col_end_offset.y/self.cell.height)) + self.strap_offset.scale(-self.add_left_rbl + bit, 0) + self.replica_col_insts[bit].place(offset) # Grow to the right of the bitcell array, array outward for bit in range(self.add_right_rbl): - offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.left_rbl - 1) + if not end_caps_enabled: + offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.left_rbl - 1) + self.strap_offset.scale(bit, -self.left_rbl - 1) + else: + offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.left_rbl - (self.col_end_offset.y/self.cell.height)) + self.strap_offset.scale(bit, -self.left_rbl - 1) + self.replica_col_insts[self.add_left_rbl + bit].place(offset) # Replica dummy rows @@ -391,26 +455,42 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def add_end_caps(self): """ Add dummy cells or end caps around the array """ + end_caps_enabled = cell_properties.bitcell.end_caps # FIXME: These depend on the array size itself # Far top dummy row (first row above array is NOT flipped) flip_dummy = self.right_rbl % 2 - dummy_row_offset = self.bitcell_offset.scale(0, self.right_rbl + flip_dummy) + self.bitcell_array_inst.ul() + if not end_caps_enabled: + dummy_row_offset = self.bitcell_offset.scale(0, self.right_rbl + flip_dummy) + self.bitcell_array_inst.ul() + else: + dummy_row_offset = self.bitcell_offset.scale(0, self.right_rbl + flip_dummy) + self.bitcell_array_inst.ul() + self.dummy_row_insts[1].place(offset=dummy_row_offset, mirror="MX" if flip_dummy else "R0") # FIXME: These depend on the array size itself # Far bottom dummy row (first row below array IS flipped) flip_dummy = (self.left_rbl + 1) % 2 - dummy_row_offset = self.bitcell_offset.scale(0, -self.left_rbl - 1 + flip_dummy) + if not end_caps_enabled: + dummy_row_offset = self.bitcell_offset.scale(0, -self.left_rbl - 1 + flip_dummy) + else: + dummy_row_offset = self.bitcell_offset.scale(0, -self.left_rbl - (self.col_end_offset.y/self.cell.height) + flip_dummy) self.dummy_row_insts[0].place(offset=dummy_row_offset, mirror="MX" if flip_dummy else "R0") # Far left dummy col # Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array - dummy_col_offset = self.bitcell_offset.scale(-self.add_left_rbl - 1, -self.left_rbl - 1) + if not end_caps_enabled: + dummy_col_offset = self.bitcell_offset.scale(-self.add_left_rbl - 1, -self.left_rbl - 1) + else: + dummy_col_offset = self.bitcell_offset.scale(-(self.add_left_rbl*(1+self.strap_offset.x/self.cell.width)) - (self.row_end_offset.x/self.cell.width), -self.left_rbl - (self.col_end_offset.y/self.cell.height)) + self.dummy_col_insts[0].place(offset=dummy_col_offset) # Far right dummy col # Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array - dummy_col_offset = self.bitcell_offset.scale(self.add_right_rbl, -self.left_rbl - 1) + self.bitcell_array_inst.lr() + if not end_caps_enabled: + dummy_col_offset = self.bitcell_offset.scale(self.add_right_rbl*(1+self.strap_offset.x/self.cell.width), -self.left_rbl - 1) + self.bitcell_array_inst.lr() + else: + dummy_col_offset = self.bitcell_offset.scale(self.add_right_rbl*(1+self.strap_offset.x/self.cell.width), -self.left_rbl - (self.col_end_offset.y/self.cell.height)) + self.bitcell_array_inst.lr() + self.dummy_col_insts[1].place(offset=dummy_col_offset) def add_layout_pins(self): @@ -470,7 +550,8 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # vdd/gnd are only connected in the perimeter cells # replica column should only have a vdd/gnd in the dummy cell on top/bottom supply_insts = self.dummy_col_insts + self.dummy_row_insts - for pin_name in ["vdd", "gnd"]: + + for pin_name in self.supplies: for inst in supply_insts: pin_list = inst.get_pins(pin_name) for pin in pin_list: diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index a28aebf9..a995c850 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -28,7 +28,10 @@ class replica_column(design.design): self.right_rbl = rbl[1] self.replica_bit = replica_bit # left, right, regular rows plus top/bottom dummy cells - self.total_size = self.left_rbl + rows + self.right_rbl + 2 + if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): + self.total_size = self.left_rbl + rows + self.right_rbl + 2 + else: + self.total_size = self.left_rbl + rows + self.right_rbl + 2 self.column_offset = column_offset debug.check(replica_bit != 0 and replica_bit != rows, @@ -78,13 +81,14 @@ class replica_column(design.design): self.add_pin_list(self.all_wordline_names, "INPUT") else: self.wordline_names = [[] for port in self.all_ports] - for row in range(self.rows): + for row in range(self.total_size): for port in self.all_ports: if not cell_properties.compare_ports(cell_properties.bitcell.split_wl): self.wordline_names[port].append("wl_{0}_{1}".format(port, row)) else: - self.wordline_names[port].append("wl0_{0}_{1}".format(port, row)) - self.wordline_names[port].append("wl1_{0}_{1}".format(port, row)) + if (row > 0 and row < self.total_size-1): + self.wordline_names[port].append("wl0_{0}_{1}".format(port, row)) + self.wordline_names[port].append("wl1_{0}_{1}".format(port, row)) self.all_wordline_names = [x for sl in zip(*self.wordline_names) for x in sl] self.add_pin_list(self.all_wordline_names, "INPUT") @@ -276,13 +280,13 @@ class replica_column(design.design): width=self.width, height=wl_pin.height()) - # # Supplies are only connected in the ends - # for (index, inst) in self.cell_inst.items(): - # for pin_name in ["vdd", "gnd"]: - # if inst in [self.cell_inst[0], self.cell_inst[self.total_size - 1]]: - # self.copy_power_pins(inst, pin_name) - # else: - # self.copy_layout_pin(inst, pin_name) + # Supplies are only connected in the ends + for (index, inst) in self.cell_inst.items(): + for pin_name in ["vpwr", "vgnd"]: + if inst in [self.cell_inst[0], self.cell_inst[self.total_size - 1]]: + self.copy_power_pins(inst, pin_name) + else: + self.copy_layout_pin(inst, pin_name) def get_bitline_names(self, port=None): if port == None: diff --git a/compiler/tests/sram_1b_16_1rw_sky130.log b/compiler/tests/sram_1b_16_1rw_sky130.log index f7fb9395..4fd3c1ee 100644 --- a/compiler/tests/sram_1b_16_1rw_sky130.log +++ b/compiler/tests/sram_1b_16_1rw_sky130.log @@ -1,9 +1,1761 @@ -ERROR: file hierarchy_spice.py: line 176: Connection mismatch: -Inst (4) -> Mod (6) -bl_0_0 -> bl0 -br_0_0 -> bl1 -vdd -> wl0 -gnd -> wl1 - -> vpwr - -> vgnd +[globals/init_openram]: Initializing OpenRAM... +[globals/setup_paths]: Temporary files saved in /home/jesse/output/ +[globals/read_config]: Configuration file is /home/jesse/openram/compiler/tests/configs/config.py +[globals/read_config]: Output saved in /home/jesse/openram/compiler/tests/./ +[globals/import_tech]: Adding technology path: /home/jesse/openram/technology +[globals/init_paths]: Creating temp directory: /home/jesse/output/ +[characterizer/]: Initializing characterizer... +[characterizer/]: Analytical model enabled. +[verify/]: Initializing verify... +[verify/]: Finding DRC/LVS/PEX tools. +[globals/get_tool]: Using DRC: /usr/local/bin/magic +[globals/get_tool]: Using LVS: /usr/local/bin/netgen +[globals/get_tool]: Using PEX: /usr/local/bin/magic +[globals/get_tool]: Using GDS: /usr/local/bin/magic +[bitcell_base_array/__init__]: Creating replica_bitcell_array 4 x 4 +[replica_bitcell_array/__init__]: Creating replica_bitcell_array 4 x 4 +[bitcell_base_array/__init__]: Creating bitcell_array 4 x 4 +[bitcell_base_array/__init__]: Creating dummy_array 1 x 4 +[verify.magic/run_drc]: Cell replica_bitcell_array has 2074 error tiles. +WARNING: file magic.py: line 210: DRC Errors replica_bitcell_array 2074 + +[verify.magic/run_lvs]: Flattening unmatched subcell s8sram_cell in circuit s8sram_cell_opt1_ce (0)(1 instance) +[verify.magic/run_lvs]: Flattening unmatched subcell s8sram16x16_colend_ce in circuit s8sram16x16_colenda (0)(1 instance) +[verify.magic/run_lvs]: Flattening unmatched subcell s8sram_cell_opt1_ce in circuit s8sram_cell_opt1a (0)(1 instance) +[verify.magic/run_lvs]: Flattening unmatched subcell s8sram_cell_opt1_ce in circuit s8sram_cell_opt1 (0)(1 instance) +[verify.magic/run_lvs]: Flattening unmatched subcell s8_col_cap_array in circuit replica_bitcell_array (0)(1 instance) +[verify.magic/run_lvs]: Flattening unmatched subcell s8_row_cap_array in circuit replica_bitcell_array (0)(1 instance) +[verify.magic/run_lvs]: Flattening unmatched subcell s8_row_cap_array_0 in circuit replica_bitcell_array (0)(1 instance) +[verify.magic/run_lvs]: Flattening unmatched subcell s8_col_cap_array_0 in circuit replica_bitcell_array (0)(1 instance) +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell s8sram16x16_colenda disconnected node: s8sram_colend_met2_0/m2_0_4# +[verify.magic/run_lvs]: Cell s8sram16x16_colenda disconnected node: s8sram_colend_met2_0/m2_0_236# +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell s8sram16x16_colenda disconnected node: bl0 +[verify.magic/run_lvs]: Cell s8sram16x16_colenda disconnected node: bl1 +[verify.magic/run_lvs]: Cell s8sram16x16_colenda disconnected node: vpwr +[verify.magic/run_lvs]: Cell s8sram16x16_colenda disconnected node: vgnd +[verify.magic/run_lvs]: Equate pins: cell s8sram16x16_colenda and/or s8sram16x16_colenda has no elements. +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell s8sram_cell_opt1a disconnected node: s8sram_cell_met2_0/m2_0_59# +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell s8sram_cell_opt1a disconnected node: bl0 +[verify.magic/run_lvs]: Cell s8sram_cell_opt1a disconnected node: bl1 +[verify.magic/run_lvs]: Cell s8sram_cell_opt1a disconnected node: wl0 +[verify.magic/run_lvs]: Cell s8sram_cell_opt1a disconnected node: wl1 +[verify.magic/run_lvs]: Cell s8sram_cell_opt1a disconnected node: vpwr +[verify.magic/run_lvs]: Cell s8sram_cell_opt1a disconnected node: vgnd +[verify.magic/run_lvs]: Equate pins: cell s8sram_cell_opt1a and/or s8sram_cell_opt1a has no elements. +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell s8sram_cell_opt1 disconnected node: s8sram_cell_met2_0/m2_0_59# +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell s8sram_cell_opt1 disconnected node: bl0 +[verify.magic/run_lvs]: Cell s8sram_cell_opt1 disconnected node: bl1 +[verify.magic/run_lvs]: Cell s8sram_cell_opt1 disconnected node: wl0 +[verify.magic/run_lvs]: Cell s8sram_cell_opt1 disconnected node: wl1 +[verify.magic/run_lvs]: Cell s8sram_cell_opt1 disconnected node: vpwr +[verify.magic/run_lvs]: Cell s8sram_cell_opt1 disconnected node: vgnd +[verify.magic/run_lvs]: Equate pins: cell s8sram_cell_opt1 and/or s8sram_cell_opt1 has no elements. +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/polygon00010_0/m1_42_0# +[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/a_113_124# +[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/a_113_124# +[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# +[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/a_113_143# +[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell dummy_array disconnected node: vpwr +[verify.magic/run_lvs]: Cell dummy_array disconnected node: vgnd +[verify.magic/run_lvs]: Class dummy_array: Merged 1 devices. +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/polygon00010_0/m1_42_0# +[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/a_113_124# +[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/a_113_124# +[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# +[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/a_113_143# +[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell dummy_array disconnected node: vpwr +[verify.magic/run_lvs]: Cell dummy_array disconnected node: vgnd +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Subcircuit summary: +[verify.magic/run_lvs]: Circuit 1: dummy_array |Circuit 2: dummy_array +[verify.magic/run_lvs]: -------------------------------------------|------------------------------------------- +[verify.magic/run_lvs]: s8sram_cell_opt1a (4) |s8sram_cell_opt1a (4) +[verify.magic/run_lvs]: s8sram_wlstrap (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_wlstrap_p (1) |(no matching element) +[verify.magic/run_lvs]: Number of devices: 6 **Mismatch** |Number of devices: 4 **Mismatch** +[verify.magic/run_lvs]: Number of nets: 20 **Mismatch** |Number of nets: 15 **Mismatch** +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: NET mismatches: Class fragments follow (with fanout counts): +[verify.magic/run_lvs]: Circuit 1: dummy_array |Circuit 2: dummy_array +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Net: bl0_0_3 |Net: col_0_bitcell +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 1 | s8sram_cell_opt1a/bl0 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: bl0_0_2 |Net: col_1_bitcell +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 1 | s8sram_cell_opt1a/bl0 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: bl0_0_1 |Net: col_2_bitcell +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 1 | s8sram_cell_opt1a/bl0 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: bl0_0_0 |Net: col_3_bitcell +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 1 | s8sram_cell_opt1a/bl0 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: bl1_0_3 |Net: bl_0_0 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 1 | s8sram_cell_opt1a/bl1 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: bl1_0_2 |Net: bl_0_1 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 1 | s8sram_cell_opt1a/bl1 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: bl1_0_1 |Net: bl_0_2 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 1 | s8sram_cell_opt1a/bl1 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: bl1_0_0 |Net: bl_0_3 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 1 | s8sram_cell_opt1a/bl1 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_1674_61# |Net: br_0_0 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_1174_61# |Net: br_0_1 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_674_61# |Net: br_0_2 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_38_62# |Net: br_0_3 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_1538_220# |Net: wl0_0_0 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | s8sram_cell_opt1a/wl1 = 4 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_1038_220# |Net: wl1_0_0 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | s8sram_cell_opt1a/vpwr = 4 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_538_220# |Net: vdd +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | s8sram_cell_opt1a/vgnd = 4 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_38_220# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: vpwr |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/vgnd = 4 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/vpwr = 4 | +[verify.magic/run_lvs]: s8sram_wlstrap/1 = 1 | +[verify.magic/run_lvs]: s8sram16x16_wlstrap_p/1 = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_0/vpb |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/vpb = 4 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: VSUBS |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/vnb = 4 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: wl0_0_0 |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 4 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 4 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: DEVICE mismatches: Class fragments follow (with node fanout counts): +[verify.magic/run_lvs]: Circuit 1: dummy_array |Circuit 2: dummy_array +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Instance: s8sram_wlstrap_0 |(no matching instance) +[verify.magic/run_lvs]: 1 = 10 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram16x16_wlstrap_p_0 |(no matching instance) +[verify.magic/run_lvs]: 1 = 10 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_3 |Instance: s8sram_cell_opt1arow_0, +[verify.magic/run_lvs]: bl0 = 1 | bl0 = 1 +[verify.magic/run_lvs]: bl1 = 1 | bl1 = 1 +[verify.magic/run_lvs]: vgnd = 10 | wl0 = 1 +[verify.magic/run_lvs]: vpwr = 10 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 4 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 4 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 4 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_2 |Instance: s8sram_cell_opt1arow_0, +[verify.magic/run_lvs]: bl0 = 1 | bl0 = 1 +[verify.magic/run_lvs]: bl1 = 1 | bl1 = 1 +[verify.magic/run_lvs]: vgnd = 10 | wl0 = 1 +[verify.magic/run_lvs]: vpwr = 10 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 4 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 4 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 4 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_1 |Instance: s8sram_cell_opt1arow_0, +[verify.magic/run_lvs]: bl0 = 1 | bl0 = 1 +[verify.magic/run_lvs]: bl1 = 1 | bl1 = 1 +[verify.magic/run_lvs]: vgnd = 10 | wl0 = 1 +[verify.magic/run_lvs]: vpwr = 10 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 4 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 4 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 4 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_0 |Instance: s8sram_cell_opt1arow_0, +[verify.magic/run_lvs]: bl0 = 1 | bl0 = 1 +[verify.magic/run_lvs]: bl1 = 1 | bl1 = 1 +[verify.magic/run_lvs]: vgnd = 10 | wl0 = 1 +[verify.magic/run_lvs]: vpwr = 10 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 4 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 4 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 4 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Netlists do not match. +[verify.magic/run_lvs]: Flattening non-matched subcircuits dummy_array dummy_array +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/polygon00010_0/m1_42_0# +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/a_113_124# +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/a_113_124# +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/a_113_143# +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: vpwr +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: vgnd +[verify.magic/run_lvs]: Class bitcell_array: Merged 10 devices. +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/polygon00010_0/m1_42_0# +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/a_113_124# +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/a_113_124# +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/a_113_143# +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: vpwr +[verify.magic/run_lvs]: Cell bitcell_array disconnected node: vgnd +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Subcircuit summary: +[verify.magic/run_lvs]: Circuit 1: bitcell_array |Circuit 2: bitcell_array +[verify.magic/run_lvs]: -------------------------------------------|------------------------------------------- +[verify.magic/run_lvs]: s8sram_cell_opt1a (8) |s8sram_cell_opt1a (8) +[verify.magic/run_lvs]: s8sram_wlstrap (1) |(no matching element) +[verify.magic/run_lvs]: s8sram_cell_opt1 (8) |s8sram_cell_opt1 (8) +[verify.magic/run_lvs]: s8sram16x16_wlstrap_p (1) |(no matching element) +[verify.magic/run_lvs]: Number of devices: 18 **Mismatch** |Number of devices: 16 **Mismatch** +[verify.magic/run_lvs]: Number of nets: 43 **Mismatch** |Number of nets: 21 **Mismatch** +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: NET mismatches: Class fragments follow (with fanout counts): +[verify.magic/run_lvs]: Circuit 1: bitcell_array |Circuit 2: bitcell_array +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Net: bl1_0_3 |Net: vdd +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 2 | s8sram_cell_opt1a/vgnd = 8 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 2 | s8sram_cell_opt1/vgnd = 8 +[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: bl1_0_2 |Net: col_0_bitcell +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 2 | s8sram_cell_opt1a/bl0 = 2 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 2 | s8sram_cell_opt1/bl0 = 2 +[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: bl1_0_1 |Net: col_1_bitcell +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 2 | s8sram_cell_opt1a/bl0 = 2 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 2 | s8sram_cell_opt1/bl0 = 2 +[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: bl1_0_0 |Net: col_2_bitcell +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 2 | s8sram_cell_opt1a/bl0 = 2 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 2 | s8sram_cell_opt1/bl0 = 2 +[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: vpwr |Net: col_3_bitcell +[verify.magic/run_lvs]: s8sram_cell_opt1a/vgnd = 8 | s8sram_cell_opt1a/bl0 = 2 +[verify.magic/run_lvs]: s8sram_cell_opt1a/vpwr = 8 | s8sram_cell_opt1/bl0 = 2 +[verify.magic/run_lvs]: s8sram_wlstrap/1 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1/vgnd = 8 | +[verify.magic/run_lvs]: s8sram_cell_opt1/vpwr = 8 | +[verify.magic/run_lvs]: s8sram16x16_wlstrap_p/1 = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_0/vpb |Net: bl_0_0 +[verify.magic/run_lvs]: s8sram_cell_opt1a/vpb = 8 | s8sram_cell_opt1a/bl1 = 2 +[verify.magic/run_lvs]: s8sram_cell_opt1/vpb = 8 | s8sram_cell_opt1/bl1 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: VSUBS |Net: bl_0_1 +[verify.magic/run_lvs]: s8sram_cell_opt1a/vnb = 8 | s8sram_cell_opt1a/bl1 = 2 +[verify.magic/run_lvs]: s8sram_cell_opt1/vnb = 8 | s8sram_cell_opt1/bl1 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_0/s8sram_cell_opt1_ |Net: bl_0_2 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/bl1 = 2 +[verify.magic/run_lvs]: | s8sram_cell_opt1/bl1 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_1/s8sram_cell_opt1_ |Net: bl_0_3 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/bl1 = 2 +[verify.magic/run_lvs]: | s8sram_cell_opt1/bl1 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_2/s8sram_cell_opt1_ |Net: br_0_0 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 2 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_3/s8sram_cell_opt1_ |Net: br_0_1 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 2 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_4/s8sram_cell_opt1_ |Net: br_0_2 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 2 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_5/s8sram_cell_opt1_ |Net: br_0_3 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 2 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_6/s8sram_cell_opt1_ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_7/s8sram_cell_opt1_ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_0/s8sram_cell_opt1_ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_1/s8sram_cell_opt1_ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_2/s8sram_cell_opt1_ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_3/s8sram_cell_opt1_ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_4/s8sram_cell_opt1_ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_5/s8sram_cell_opt1_ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_6/s8sram_cell_opt1_ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_7/s8sram_cell_opt1_ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_0/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_1/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_2/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_3/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_4/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_5/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_6/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_7/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_0/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_1/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_2/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_3/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_4/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_5/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_6/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_7/s8sram_cell_opt1_c |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_3 +[verify.magic/run_lvs]: | s8sram_cell_opt1/vpwr = 4 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_1 +[verify.magic/run_lvs]: | s8sram_cell_opt1/vpwr = 4 +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_3 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl1 = 4 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_1 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl1 = 4 +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_2 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/vpwr = 4 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_0 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/vpwr = 4 +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_2 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 4 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_0 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 4 +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Net: wl0_0_1 |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 4 | +[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 4 | +[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: wl0_0_3 |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 4 | +[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 4 | +[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Net: wl0_0_0 |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 4 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 4 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: wl0_0_2 |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 4 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 4 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: DEVICE mismatches: Class fragments follow (with node fanout counts): +[verify.magic/run_lvs]: Circuit 1: bitcell_array |Circuit 2: bitcell_array +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Instance: s8sram_wlstrap_0 |(no matching instance) +[verify.magic/run_lvs]: 1 = 34 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram16x16_wlstrap_p_0 |(no matching instance) +[verify.magic/run_lvs]: 1 = 34 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_7 |Instance: s8sram_cell_opt1row_3, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_6 |Instance: s8sram_cell_opt1row_3, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_5 |Instance: s8sram_cell_opt1row_3, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_4 |Instance: s8sram_cell_opt1row_3, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_3 |Instance: s8sram_cell_opt1row_1, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_2 |Instance: s8sram_cell_opt1row_1, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_1 |Instance: s8sram_cell_opt1row_1, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_0 |Instance: s8sram_cell_opt1row_1, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_7 |Instance: s8sram_cell_opt1arow_2, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_6 |Instance: s8sram_cell_opt1arow_2, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_5 |Instance: s8sram_cell_opt1arow_2, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_4 |Instance: s8sram_cell_opt1arow_2, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_3 |Instance: s8sram_cell_opt1arow_0, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_2 |Instance: s8sram_cell_opt1arow_0, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_1 |Instance: s8sram_cell_opt1arow_0, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_0 |Instance: s8sram_cell_opt1arow_0, +[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 +[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 +[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 +[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 +[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 12 | +[verify.magic/run_lvs]: vnb = 16 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Netlists do not match. +[verify.magic/run_lvs]: Flattening non-matched subcircuits bitcell_array bitcell_arrayClass replica_column: Merged 4 devices. +[verify.magic/run_lvs]: Class replica_column: Merged 1 devices. +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Subcircuit summary: +[verify.magic/run_lvs]: Circuit 1: replica_column |Circuit 2: replica_column +[verify.magic/run_lvs]: -------------------------------------------|------------------------------------------- +[verify.magic/run_lvs]: s8sram_cell_opt1a (2) |s8sram_cell_opt1a (2) +[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent (1) |(no matching element) +[verify.magic/run_lvs]: s8sram_cell_opt1 (3) |s8sram_cell_opt1 (3) +[verify.magic/run_lvs]: s8sram16x16_colenda (2) |s8sram16x16_colenda (1) **Mismatch** +[verify.magic/run_lvs]: s8sram16x16_wlstrap_p (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_colend_p_cent (1) |(no matching element) +[verify.magic/run_lvs]: Number of devices: 10 **Mismatch** |Number of devices: 6 **Mismatch** +[verify.magic/run_lvs]: Number of nets: 22 **Mismatch** |Number of nets: 14 **Mismatch** +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Flattening instances of s8sram16x16_colenda in cell replica_column makes a better match +[verify.magic/run_lvs]: Flattening instances of s8sram16x16_colenda in cell replica_column makes a better match +[verify.magic/run_lvs]: Making another compare attempt. +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Subcircuit summary: +[verify.magic/run_lvs]: Circuit 1: replica_column |Circuit 2: replica_column +[verify.magic/run_lvs]: -------------------------------------------|------------------------------------------- +[verify.magic/run_lvs]: s8sram_cell_opt1a (2) |s8sram_cell_opt1a (2) +[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent (1) |(no matching element) +[verify.magic/run_lvs]: s8sram_cell_opt1 (3) |s8sram_cell_opt1 (3) +[verify.magic/run_lvs]: nshort (2) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_wlstrap_p (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_colend_p_cent (1) |(no matching element) +[verify.magic/run_lvs]: Number of devices: 10 **Mismatch** |Number of devices: 5 **Mismatch** +[verify.magic/run_lvs]: Number of nets: 22 **Mismatch** |Number of nets: 14 **Mismatch** +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: NET mismatches: Class fragments follow (with fanout counts): +[verify.magic/run_lvs]: Circuit 1: replica_column |Circuit 2: replica_column +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Net: br_0_0 |Net: wl0_0_1 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 2 | s8sram_cell_opt1/wl0 = 1 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 2 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 3 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 3 | +[verify.magic/run_lvs]: nshort/(drain|source) = 4 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: vgnd |Net: wl0_0_3 +[verify.magic/run_lvs]: s8sram_cell_opt1a/vgnd = 2 | s8sram_cell_opt1/wl0 = 1 +[verify.magic/run_lvs]: s8sram_cell_opt1a/vpwr = 2 | +[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent/1 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1/vgnd = 3 | +[verify.magic/run_lvs]: s8sram_cell_opt1/vpwr = 3 | +[verify.magic/run_lvs]: s8sram16x16_wlstrap_p/1 = 1 | +[verify.magic/run_lvs]: s8sram16x16_colend_p_cent/1 = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: wl_0_5 |Net: wl0_0_5 +[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 1 | s8sram_cell_opt1/wl0 = 1 +[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: wl_0_3 |Net: wl1_0_1 +[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 1 | s8sram_cell_opt1/wl1 = 1 +[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: wl_0_1 |Net: wl1_0_3 +[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 1 | s8sram_cell_opt1/wl1 = 1 +[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_38_1737# |Net: wl1_0_5 +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | s8sram_cell_opt1/wl1 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_38_1105# |Net: bl_0_0 +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | s8sram_cell_opt1/bl0 = 3 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/bl0 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_38_473# |Net: br_0_0 +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | s8sram_cell_opt1/bl1 = 3 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/bl1 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_38_1895# |Net: vdd +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | s8sram_cell_opt1/vpwr = 3 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/vpwr = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_38_1263# |Net: gnd +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | s8sram_cell_opt1/vgnd = 3 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/vgnd = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_38_631# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram16x16_colend_p_cent_0/vpb |(no matching net) +[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent/2 = 1 | +[verify.magic/run_lvs]: s8sram16x16_colend_p_cent/2 = 1 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_4 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_2 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 1 +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_4 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl0 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_2 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl0 = 1 +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Net: s8sram16x16_colenda_1/s8sram16x16_col |(no matching net) +[verify.magic/run_lvs]: nshort/gate = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram16x16_colenda_0/s8sram16x16_col |(no matching net) +[verify.magic/run_lvs]: nshort/gate = 1 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Net: a_38_947# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_38_1579# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Net: a_38_789# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: a_38_1421# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Net: wl_0_2 |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: wl_0_4 |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Net: VSUBS |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/vnb = 2 | +[verify.magic/run_lvs]: s8sram_cell_opt1/vnb = 3 | +[verify.magic/run_lvs]: nshort/bulk = 2 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: s8sram_cell_opt1_0/vpb |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/vpb = 2 | +[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent/3 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1/vpb = 3 | +[verify.magic/run_lvs]: s8sram16x16_colend_p_cent/3 = 1 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: DEVICE mismatches: Class fragments follow (with node fanout counts): +[verify.magic/run_lvs]: Circuit 1: replica_column |Circuit 2: replica_column +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Instance: s8sram16x16_colenda_p_cent_0 |(no matching instance) +[verify.magic/run_lvs]: 1 = 13 | +[verify.magic/run_lvs]: 2 = 2 | +[verify.magic/run_lvs]: 3 = 7 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram16x16_wlstrap_p_0 |(no matching instance) +[verify.magic/run_lvs]: 1 = 13 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram16x16_colend_p_cent_0 |(no matching instance) +[verify.magic/run_lvs]: 1 = 13 | +[verify.magic/run_lvs]: 2 = 2 | +[verify.magic/run_lvs]: 3 = 7 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Instance: s8sram16x16_colenda_1//s8sram16x |(no matching instance) +[verify.magic/run_lvs]: (drain,source) = (14,14) | +[verify.magic/run_lvs]: gate = 1 | +[verify.magic/run_lvs]: bulk = 7 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram16x16_colenda_0//s8sram16x |(no matching instance) +[verify.magic/run_lvs]: (drain,source) = (14,14) | +[verify.magic/run_lvs]: gate = 1 | +[verify.magic/run_lvs]: bulk = 7 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_2 |Instance: s8sram_cell_opt1rbc_5 +[verify.magic/run_lvs]: bl0 = 14 | bl0 = 5 +[verify.magic/run_lvs]: bl1 = 14 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 13 | wl0 = 1 +[verify.magic/run_lvs]: vpwr = 13 | wl1 = 1 +[verify.magic/run_lvs]: vpb = 7 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 3 | vgnd = 5 +[verify.magic/run_lvs]: wl0 = 3 | +[verify.magic/run_lvs]: vnb = 7 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 3 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_1 |Instance: s8sram_cell_opt1rbc_3 +[verify.magic/run_lvs]: bl0 = 14 | bl0 = 5 +[verify.magic/run_lvs]: bl1 = 14 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 13 | wl0 = 1 +[verify.magic/run_lvs]: vpwr = 13 | wl1 = 1 +[verify.magic/run_lvs]: vpb = 7 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 3 | vgnd = 5 +[verify.magic/run_lvs]: wl0 = 3 | +[verify.magic/run_lvs]: vnb = 7 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 3 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_0 |Instance: s8sram_cell_opt1rbc_1 +[verify.magic/run_lvs]: bl0 = 14 | bl0 = 5 +[verify.magic/run_lvs]: bl1 = 14 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 13 | wl0 = 1 +[verify.magic/run_lvs]: vpwr = 13 | wl1 = 1 +[verify.magic/run_lvs]: vpb = 7 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 3 | vgnd = 5 +[verify.magic/run_lvs]: wl0 = 3 | +[verify.magic/run_lvs]: vnb = 7 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 3 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_0 |(no matching instance) +[verify.magic/run_lvs]: bl0 = 14 | +[verify.magic/run_lvs]: bl1 = 14 | +[verify.magic/run_lvs]: vgnd = 13 | +[verify.magic/run_lvs]: vpwr = 13 | +[verify.magic/run_lvs]: vpb = 7 | +[verify.magic/run_lvs]: wl1 = 3 | +[verify.magic/run_lvs]: wl0 = 3 | +[verify.magic/run_lvs]: vnb = 7 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 3 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_1 |(no matching instance) +[verify.magic/run_lvs]: bl0 = 14 | +[verify.magic/run_lvs]: bl1 = 14 | +[verify.magic/run_lvs]: vgnd = 13 | +[verify.magic/run_lvs]: vpwr = 13 | +[verify.magic/run_lvs]: vpb = 7 | +[verify.magic/run_lvs]: wl1 = 3 | +[verify.magic/run_lvs]: wl0 = 3 | +[verify.magic/run_lvs]: vnb = 7 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 3 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: (no matching instance) |Instance: s8sram_cell_opt1arbc_2 +[verify.magic/run_lvs]: | bl0 = 5 +[verify.magic/run_lvs]: | bl1 = 5 +[verify.magic/run_lvs]: | wl0 = 1 +[verify.magic/run_lvs]: | wl1 = 1 +[verify.magic/run_lvs]: | vpwr = 5 +[verify.magic/run_lvs]: | vgnd = 5 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: (no matching instance) |Instance: s8sram_cell_opt1arbc_4 +[verify.magic/run_lvs]: | bl0 = 5 +[verify.magic/run_lvs]: | bl1 = 5 +[verify.magic/run_lvs]: | wl0 = 1 +[verify.magic/run_lvs]: | wl1 = 1 +[verify.magic/run_lvs]: | vpwr = 5 +[verify.magic/run_lvs]: | vgnd = 5 +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Netlists do not match. +[verify.magic/run_lvs]: Flattening non-matched subcircuits replica_column replica_column +[verify.magic/run_lvs]: Cell replica_bitcell_array disconnected node: vdd +[verify.magic/run_lvs]: Cell replica_bitcell_array disconnected node: gnd +[verify.magic/run_lvs]: Class replica_bitcell_array: Merged 23 devices. +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell replica_bitcell_array disconnected node: vdd +[verify.magic/run_lvs]: Cell replica_bitcell_array disconnected node: gnd +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Subcircuit summary: +[verify.magic/run_lvs]: Circuit 1: replica_bitcell_array |Circuit 2: replica_bitcell_array +[verify.magic/run_lvs]: -------------------------------------------|------------------------------------------- +[verify.magic/run_lvs]: s8sram16x16_colenda (4) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_colend_p_cent (1) |(no matching element) +[verify.magic/run_lvs]: s8sram_cell_opt1a (14) |s8sram_cell_opt1a (14) +[verify.magic/run_lvs]: s8sram_wlstrap (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_wlstrap_p (1) |(no matching element) +[verify.magic/run_lvs]: s8sram_cell_opt1 (11) |s8sram_cell_opt1 (11) +[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent (1) |(no matching element) +[verify.magic/run_lvs]: nshort (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_corner (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_cornera (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_rowenda (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_rowend (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_cornerb (1) |(no matching element) +[verify.magic/run_lvs]: Number of devices: 39 **Mismatch** |Number of devices: 25 **Mismatch** +[verify.magic/run_lvs]: Number of nets: 62 **Mismatch** |Number of nets: 32 **Mismatch** +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Flattening instances of s8sram16x16_colenda in cell replica_bitcell_array makes a better match +[verify.magic/run_lvs]: Flattening instances of s8sram16x16_colenda in cell replica_bitcell_array makes a better match +[verify.magic/run_lvs]: Making another compare attempt. +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Cell replica_bitcell_array disconnected node: vdd +[verify.magic/run_lvs]: Cell replica_bitcell_array disconnected node: gnd +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: Subcircuit summary: +[verify.magic/run_lvs]: Circuit 1: replica_bitcell_array |Circuit 2: replica_bitcell_array +[verify.magic/run_lvs]: -------------------------------------------|------------------------------------------- +[verify.magic/run_lvs]: nshort (5) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_colend_p_cent (1) |(no matching element) +[verify.magic/run_lvs]: s8sram_cell_opt1a (14) |s8sram_cell_opt1a (14) +[verify.magic/run_lvs]: s8sram_wlstrap (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_wlstrap_p (1) |(no matching element) +[verify.magic/run_lvs]: s8sram_cell_opt1 (11) |s8sram_cell_opt1 (11) +[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_corner (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_cornera (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_rowenda (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_rowend (1) |(no matching element) +[verify.magic/run_lvs]: s8sram16x16_cornerb (1) |(no matching element) +[verify.magic/run_lvs]: Number of devices: 39 **Mismatch** |Number of devices: 25 **Mismatch** +[verify.magic/run_lvs]: Number of nets: 62 **Mismatch** |Number of nets: 32 **Mismatch** +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: NET mismatches: Class fragments follow (with fanout counts): +[verify.magic/run_lvs]: Circuit 1: replica_bitcell_array |Circuit 2: replica_bitcell_array +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Net: dummy_array_0/bl0_0_2 |Net: dummy_arraydummy_row_0/col_0_bitcell +[verify.magic/run_lvs]: nshort/(drain|source) = 2 | s8sram_cell_opt1a/bl0 = 1 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 3 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 3 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: dummy_array_0/bl0_0_3 |Net: dummy_arraydummy_row_0/col_1_bitcell +[verify.magic/run_lvs]: nshort/(drain|source) = 2 | s8sram_cell_opt1a/bl0 = 1 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 3 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 3 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: dummy_array_0/bl0_0_0 |Net: dummy_arraydummy_row_0/col_2_bitcell +[verify.magic/run_lvs]: nshort/(drain|source) = 2 | s8sram_cell_opt1a/bl0 = 1 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 3 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 3 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: dummy_array_0/bl0_0_1 |Net: dummy_arraydummy_row_0/col_3_bitcell +[verify.magic/run_lvs]: nshort/(drain|source) = 2 | s8sram_cell_opt1a/bl0 = 1 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 3 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 3 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: rbl_bl_0_0 |Net: bl_0_0 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 2 | s8sram_cell_opt1a/bl1 = 3 +[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 2 | s8sram_cell_opt1/bl1 = 2 +[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 3 | +[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 3 | +[verify.magic/run_lvs]: nshort/(drain|source) = 2 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: VSUBS |Net: bl_0_1 +[verify.magic/run_lvs]: nshort/bulk = 5 | s8sram_cell_opt1a/bl1 = 3 +[verify.magic/run_lvs]: s8sram_cell_opt1a/vnb = 14 | s8sram_cell_opt1/bl1 = 2 +[verify.magic/run_lvs]: s8sram_cell_opt1/vnb = 11 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: rbl_wl1_0_0 |Net: bl_0_2 +[verify.magic/run_lvs]: s8sram16x16_colend_p_cent/1 = 1 | s8sram_cell_opt1a/bl1 = 3 +[verify.magic/run_lvs]: s8sram_cell_opt1a/vgnd = 14 | s8sram_cell_opt1/bl1 = 2 +[verify.magic/run_lvs]: s8sram_cell_opt1a/vpwr = 14 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 4 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 4 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | +[verify.magic/run_lvs]: s8sram_wlstrap/1 = 1 | +[verify.magic/run_lvs]: s8sram16x16_wlstrap_p/1 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1/vgnd = 11 | +[verify.magic/run_lvs]: s8sram_cell_opt1/vpwr = 11 | +[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent/1 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | +[verify.magic/run_lvs]: s8sram16x16_corner/1 = 1 | +[verify.magic/run_lvs]: s8sram16x16_cornera/2 = 1 | +[verify.magic/run_lvs]: s8sram16x16_rowenda/1 = 1 | +[verify.magic/run_lvs]: s8sram16x16_rowenda/2 = 1 | +[verify.magic/run_lvs]: s8sram16x16_rowend/1 = 1 | +[verify.magic/run_lvs]: s8sram16x16_rowend/2 = 1 | +[verify.magic/run_lvs]: s8sram16x16_cornerb/1 = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: dummy_array_0/s8sram_cell_opt1a_0/vpb |Net: bl_0_3 +[verify.magic/run_lvs]: nshort/gate = 5 | s8sram_cell_opt1a/bl1 = 3 +[verify.magic/run_lvs]: s8sram16x16_colend_p_cent/2 = 1 | s8sram_cell_opt1/bl1 = 2 +[verify.magic/run_lvs]: s8sram16x16_colend_p_cent/3 = 1 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/vpb = 14 | +[verify.magic/run_lvs]: s8sram_cell_opt1/vpb = 11 | +[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent/2 = 1 | +[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent/3 = 1 | +[verify.magic/run_lvs]: s8sram16x16_corner/2 = 1 | +[verify.magic/run_lvs]: s8sram16x16_corner/3 = 1 | +[verify.magic/run_lvs]: s8sram16x16_cornera/1 = 1 | +[verify.magic/run_lvs]: s8sram16x16_cornera/3 = 1 | +[verify.magic/run_lvs]: s8sram16x16_cornerb/2 = 1 | +[verify.magic/run_lvs]: s8sram16x16_cornerb/3 = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /dummy_array_0/a_1674_61# |Net: br_0_0 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 3 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /dummy_array_0/a_1174_61# |Net: br_0_1 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 3 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /dummy_array_0/a_674_61# |Net: br_0_2 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 3 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /dummy_array_0/a_38_62# |Net: br_0_3 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 3 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_0/ |Net: vpwr +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1/vpwr = 3 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/vpwr = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_1/ |Net: vgnd +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1/vgnd = 3 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/vgnd = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_2/ |Net: rbl_bl_0_0 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1/bl0 = 3 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/bl0 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_3/ |Net: rbl_br_0_0 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1/bl1 = 3 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/bl1 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_4/ |Net: rbl_wl0_0_0 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1/wl0 = 1 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 4 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_5/ |Net: rbl_wl1_0_0 +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1/wl1 = 1 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/vpwr = 4 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_6/ |Net: dummy_arraydummy_row_0/vdd +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/vgnd = 4 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_7/ |Net: /bitcell_array/col_0_bitcell +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/bl0 = 2 +[verify.magic/run_lvs]: | s8sram_cell_opt1/bl0 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /replica_column_0/a_38_1421# |Net: /bitcell_array/col_1_bitcell +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/bl0 = 2 +[verify.magic/run_lvs]: | s8sram_cell_opt1/bl0 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /replica_column_0/a_38_789# |Net: /bitcell_array/col_2_bitcell +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/bl0 = 2 +[verify.magic/run_lvs]: | s8sram_cell_opt1/bl0 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /dummy_array_0/a_1538_220# |Net: /bitcell_array/col_3_bitcell +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | s8sram_cell_opt1a/bl0 = 2 +[verify.magic/run_lvs]: | s8sram_cell_opt1/bl0 = 2 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /dummy_array_0/a_1038_220# |Net: /bitcell_array/vdd +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | s8sram_cell_opt1a/vgnd = 8 +[verify.magic/run_lvs]: | s8sram_cell_opt1/vgnd = 8 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /dummy_array_0/a_538_220# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /dummy_array_0/a_38_220# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_0/ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_1/ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_2/ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_3/ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_4/ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_5/ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_6/ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_7/ |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /replica_column_0/a_38_1579# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /replica_column_0/a_38_947# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_0/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_1/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_2/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_3/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_4/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_5/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_6/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_7/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /replica_column_0/a_38_1737# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /replica_column_0/a_38_1105# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /replica_column_0/a_38_473# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_0/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_1/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_2/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_3/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_4/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_5/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_6/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_7/s |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /replica_column_0/a_38_1895# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /replica_column_0/a_38_1263# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: /replica_column_0/a_38_631# |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_3 +[verify.magic/run_lvs]: | s8sram_cell_opt1/vpwr = 4 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl1 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_1 +[verify.magic/run_lvs]: | s8sram_cell_opt1/vpwr = 4 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl1 = 1 +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_3 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl1 = 4 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_1 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl1 = 4 +[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 1 +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_2 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/vpwr = 4 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_0 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/vpwr = 4 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 1 +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_2 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 4 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl0 = 1 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_0 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 4 +[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl0 = 1 +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Net: wl1_0_1 |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 5 | +[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 5 | +[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: wl1_0_3 |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 5 | +[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 5 | +[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Net: wl1_0_0 |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 5 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 5 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Net: wl1_0_2 |(no matching net) +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 5 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 5 | +[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: DEVICE mismatches: Class fragments follow (with node fanout counts): +[verify.magic/run_lvs]: Circuit 1: replica_bitcell_array |Circuit 2: replica_bitcell_array +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Instance: s8_col_cap_array_0//s8sram16x16_ |(no matching instance) +[verify.magic/run_lvs]: (drain,source) = (12,12) | +[verify.magic/run_lvs]: gate = 40 | +[verify.magic/run_lvs]: bulk = 30 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8_col_cap_array_0//s8sram16x16_ |(no matching instance) +[verify.magic/run_lvs]: (drain,source) = (12,12) | +[verify.magic/run_lvs]: gate = 40 | +[verify.magic/run_lvs]: bulk = 30 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8_col_cap_array_0//s8sram16x16_ |(no matching instance) +[verify.magic/run_lvs]: (drain,source) = (12,12) | +[verify.magic/run_lvs]: gate = 40 | +[verify.magic/run_lvs]: bulk = 30 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8_col_cap_array_0//s8sram16x16_ |(no matching instance) +[verify.magic/run_lvs]: (drain,source) = (12,12) | +[verify.magic/run_lvs]: gate = 40 | +[verify.magic/run_lvs]: bulk = 30 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: replica_column_0//s8sram16x16_co |(no matching instance) +[verify.magic/run_lvs]: (drain,source) = (12,12) | +[verify.magic/run_lvs]: gate = 40 | +[verify.magic/run_lvs]: bulk = 30 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8_col_cap_array_0//s8sram16x16_ |(no matching instance) +[verify.magic/run_lvs]: 1 = 76 | +[verify.magic/run_lvs]: 2 = 40 | +[verify.magic/run_lvs]: 3 = 40 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: dummy_array_0//s8sram_wlstrap_0 |(no matching instance) +[verify.magic/run_lvs]: 1 = 76 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: dummy_array_0//s8sram16x16_wlstr |(no matching instance) +[verify.magic/run_lvs]: 1 = 76 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: replica_column_0//s8sram16x16_co |(no matching instance) +[verify.magic/run_lvs]: 1 = 76 | +[verify.magic/run_lvs]: 2 = 40 | +[verify.magic/run_lvs]: 3 = 40 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8_row_cap_array_0//s8sram16x16_ |(no matching instance) +[verify.magic/run_lvs]: 1 = 76 | +[verify.magic/run_lvs]: 2 = 40 | +[verify.magic/run_lvs]: 3 = 40 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8_row_cap_array_0//s8sram16x16_ |(no matching instance) +[verify.magic/run_lvs]: 1 = 40 | +[verify.magic/run_lvs]: 2 = 76 | +[verify.magic/run_lvs]: 3 = 40 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8_row_cap_array_0//s8sram16x16_ |(no matching instance) +[verify.magic/run_lvs]: 1 = 76 | +[verify.magic/run_lvs]: 2 = 76 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8_row_cap_array_0//s8sram16x16_ |(no matching instance) +[verify.magic/run_lvs]: 1 = 76 | +[verify.magic/run_lvs]: 2 = 76 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: s8_row_cap_array_0_0//s8sram16x1 |(no matching instance) +[verify.magic/run_lvs]: 1 = 76 | +[verify.magic/run_lvs]: 2 = 40 | +[verify.magic/run_lvs]: 3 = 40 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Instance: replica_column_0//s8sram_cell_op |Instance: replica_columnreplica_col_0/s8sr +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 5 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 76 | vgnd = 5 +[verify.magic/run_lvs]: wl0 = 76 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 76 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: replica_column_0//s8sram_cell_op |Instance: bitcell_array/s8sram_cell_opt1ro +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: replica_column_0//s8sram_cell_op |Instance: bitcell_array/s8sram_cell_opt1ro +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ro +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ro +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ro +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ro +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ro +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ro +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |(no matching instance) +[verify.magic/run_lvs]: bl0 = 12 | +[verify.magic/run_lvs]: bl1 = 12 | +[verify.magic/run_lvs]: vgnd = 76 | +[verify.magic/run_lvs]: vpwr = 76 | +[verify.magic/run_lvs]: vpb = 40 | +[verify.magic/run_lvs]: wl1 = 15 | +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |(no matching instance) +[verify.magic/run_lvs]: bl0 = 12 | +[verify.magic/run_lvs]: bl1 = 12 | +[verify.magic/run_lvs]: vgnd = 76 | +[verify.magic/run_lvs]: vpwr = 76 | +[verify.magic/run_lvs]: vpb = 40 | +[verify.magic/run_lvs]: wl1 = 15 | +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: (no matching instance) |Instance: replica_columnreplica_col_0/s8sr +[verify.magic/run_lvs]: | bl0 = 5 +[verify.magic/run_lvs]: | bl1 = 5 +[verify.magic/run_lvs]: | wl0 = 5 +[verify.magic/run_lvs]: | wl1 = 5 +[verify.magic/run_lvs]: | vpwr = 5 +[verify.magic/run_lvs]: | vgnd = 5 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: (no matching instance) |Instance: replica_columnreplica_col_0/s8sr +[verify.magic/run_lvs]: | bl0 = 5 +[verify.magic/run_lvs]: | bl1 = 5 +[verify.magic/run_lvs]: | wl0 = 5 +[verify.magic/run_lvs]: | wl1 = 5 +[verify.magic/run_lvs]: | vpwr = 5 +[verify.magic/run_lvs]: | vgnd = 5 +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Instance: replica_column_0//s8sram_cell_op |Instance: dummy_arraydummy_row_0/s8sram_ce +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 1 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 4 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: replica_column_0//s8sram_cell_op |Instance: dummy_arraydummy_row_0/s8sram_ce +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 1 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 4 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: dummy_arraydummy_row_0/s8sram_ce +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 1 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 4 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: dummy_arraydummy_row_0/s8sram_ce +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 1 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 4 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ar +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ar +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ar +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ar +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ar +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ar +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 15 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: dummy_array_0//s8sram_cell_opt1a |Instance: bitcell_array/s8sram_cell_opt1ar +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 76 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 76 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 76 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: dummy_array_0//s8sram_cell_opt1a |Instance: bitcell_array/s8sram_cell_opt1ar +[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 +[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 +[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 +[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 +[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 +[verify.magic/run_lvs]: wl1 = 76 | vgnd = 16 +[verify.magic/run_lvs]: wl0 = 76 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 76 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: dummy_array_0//s8sram_cell_opt1a |(no matching instance) +[verify.magic/run_lvs]: bl0 = 12 | +[verify.magic/run_lvs]: bl1 = 12 | +[verify.magic/run_lvs]: vgnd = 76 | +[verify.magic/run_lvs]: vpwr = 76 | +[verify.magic/run_lvs]: vpb = 40 | +[verify.magic/run_lvs]: wl1 = 76 | +[verify.magic/run_lvs]: wl0 = 76 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 76 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: Instance: dummy_array_0//s8sram_cell_opt1a |(no matching instance) +[verify.magic/run_lvs]: bl0 = 12 | +[verify.magic/run_lvs]: bl1 = 12 | +[verify.magic/run_lvs]: vgnd = 76 | +[verify.magic/run_lvs]: vpwr = 76 | +[verify.magic/run_lvs]: vpb = 40 | +[verify.magic/run_lvs]: wl1 = 76 | +[verify.magic/run_lvs]: wl0 = 76 | +[verify.magic/run_lvs]: vnb = 30 | +[verify.magic/run_lvs]: a_38_62# = 1 | +[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 76 | +[verify.magic/run_lvs]: a_38_220# = 1 | +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: (no matching instance) |Instance: replica_columnreplica_col_0/s8sr +[verify.magic/run_lvs]: | bl0 = 5 +[verify.magic/run_lvs]: | bl1 = 5 +[verify.magic/run_lvs]: | wl0 = 5 +[verify.magic/run_lvs]: | wl1 = 5 +[verify.magic/run_lvs]: | vpwr = 5 +[verify.magic/run_lvs]: | vgnd = 5 +[verify.magic/run_lvs]: | +[verify.magic/run_lvs]: (no matching instance) |Instance: replica_columnreplica_col_0/s8sr +[verify.magic/run_lvs]: | bl0 = 5 +[verify.magic/run_lvs]: | bl1 = 5 +[verify.magic/run_lvs]: | wl0 = 5 +[verify.magic/run_lvs]: | wl1 = 5 +[verify.magic/run_lvs]: | vpwr = 5 +[verify.magic/run_lvs]: | vgnd = 5 +[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- +[verify.magic/run_lvs]: Netlists do not match. +[verify.magic/run_lvs]: Netlists do not match. +ERROR: file magic.py: line 285: replica_bitcell_array LVS mismatch (results in /home/jesse/output/replica_bitcell_array.lvs.report) diff --git a/missing_pin.gds b/missing_pin.gds index 25df96f6f8225f45a3de16bfacd9df384fba6796..0bad623f596405237eb17edbd0c140b3f8fecd4a 100644 GIT binary patch literal 7442 zcmd6sX=q(V6vyW-? z#JUzmL=XhGd{Byt2&GCu#0{&0J5+JO4L4|Az^CHf>WQlce|o zxh0nzkb5Pb;?wZw^vD0LezGww(@?MBa^Fz8=wbdc zQPdeX66#EonQS`DY>cDi-n4Keu*Y3zmxczeU!J_nF8eOqWGn=0@sfWuhAi9+ex6e8 zpg$HW^c*$OJYK;UaM|E-9*HT7Ya=;Na3m1+lT>f=X5UpOLqrP{%o`r>NQ*WLZ>@goyV{3J z!vp2P?dd!|%l6&kwC{pO@g2+tFGb%e)!sNE-?P-WKgUb`1F7eW-COInGk!$88ZekH z_sVFIF(HcGP@ewmdgWqT5l> zO4Nb;2HK?_)xNTZz6EXi9eOZ&6o0RzR6CgKpKqnOUfxdeB={ztm1T4ogAZ}v3134(>Rmaxe#}SA zg#-ro;BN)~eigD@a|&fWFQor)zW682)5y0UWRh~m@+0FuVmv43x7e~9F4Ps`FhMm*2T`qC!F3Dg{OuR+dpwqL3Cs`*~3cz;WvVFEeVxFaal4*K=qV)fd7n@KKQcNk$Qy`Oyj zYO9}?uFRTGcLSx`L0`W$*Z(op{VDi&%+ar@)(0O;PS!hEAoVBJ4*LG3{{F7)9I@WP zOESMmFIhc)mZ&y~U&fAQ{GBCCta4McdQ*Y|vp!*3fZys$ z{VC}su2O8ZzdErVw1c^NuCB~SQtz*>YFGVaV`f#xy%Ja3J+~_Ig=gy%npV|lWaz~R z`KlzERh5k=bMiMNJ=?~msVO7uZJLZh`oG=Zog-)(*OcMW}jl1Qher9p^u03U` zYi=p;*z|!YgZt5A&x-O&*UE`0qx%x&4pk;2agv#B>P@4Wi;s+xY89sdmsG4I0B(eQ*J^M=*E5;8v_>pQcnhn5&1{gxB#3?TffzG%M8( zX7%107QSlbCb|aXn(C-_FjpV6BmWzyGZ^m#ak5aV9jvJjw~9W(tD#=0b}&~To`*WW zg+2g-GWbKJ>n9Fpa8PgBw_V>Q-;WU3LXZP6H8 za!NUDGs`0joY4nT+C6s=WiloQ!J}^{?eFgf8uYiWV5Fhyjx{qj@T1o-b9Ds zUy0uthw^tacujs+GGE*+`N^6wnwuXSSB&FHo=-TwlxhdF?Qwd>w;YEy&gJ;jaSE!v zYJ672Sj-<@D?0mb;a{nCFxNlpOFudOrc#mVe|jx(?{Npj3O+`j8)EeUHAw zcnlm_He)X&zy7%~mL124v6NOR7hk_RFUF#dCvRnrUSlk~K6rTyzZ3+M&>xP`Px7l$ z%T;<>zkU@lSnxQ?Jc&OrK7sdgLrS%SzFyilMhvEYl{x-%qbceb!zy$1Ew+D8H%b45 zhb3ot6ub-l;}~rhd%_#>{3P1wnCK2ywC@UAzSlnXHxv7r{jXFz==YEGudio)sAqjp zKc%fFOrWnHw*D8nXc7Cm?&I-XWc~qt`M)6Td)kRwq>Zg4+6+Cx4_uLG((sgSq}~ zw18cTOrnEP^n3#fboQ!~f2RI+S44Jx6J`CCY6q?Vao$=IukwEa_=H}vvHl>YSd7Z? z^pp7-$i3Mn)RcRG-3Ljv4_351qc1dBwcTf_xBD@v_NIKj-Jg+9_i4L-W52dkyVH-; z@?^ZqnbCdU*H%}a*`&g9#aLzZ!ZB+pR$gs?XU|;T86f9074nmM^D<5Iimq1 P?*BJ>Zp)0GI5vL+uw1`# literal 3328 zcmbW3OKgl$6vxl^oTjO&s)m{fTbeLUyoI7HkVrj(dQ6IvN?VN)8Y>&ZLc&5USXf9T zVnHI(g|(H14H6NtV1-2NtoWaE?wRjSXTA|`GV}Ys^WFbB_i^rnQVPR^R1CtxXDZNa zYNge*&VQzkFs-bqoEsi5t(q#WBI=5gjhnBp-ud$3kF^8S%kSSE+DFACU*D5Defh-M zv5|?B!{y1+c)2oqiQ*QbbXG`9C~XgE8TEEVq-E4`iYR`9XQSCiDV~E*1!@|(dq(8) z_{jObYSaOV+M7j<7Hib#Ik=OkO0zH4sIJvD`gjCgd5b22g)wcl(d?kK+Ud7R{H`oM zb!q(Iw(5;$2b=1{0oBK;>WyXxo9g3xs!yJ&-e`8PsXpyjeG8_AXU%AKQ1pM9wQ9ad zzPY3+pTNLczHD_Px54ry`lyi$do{8#zC#r3gU!+EfqqZw`~`E>U$m4c#B^2pUHwOn zRu63CPxE=Z`XVN>Dn8?pKk4^+z01sCH&;SGnESzB9?cH7ydG*Yvx|1w_@J5;o)H?- znPJ9*cz*;2%J4mi_JkLd__xx?{}J{d^lBC1ExaGXyJOmp_YzhHwhbo7558pNdSOxP z3-RduHHs(m9lq3fO!gOD%9yUl`yRx@{4u$>`nmpOK2VRDdZ>$6cELGl zn#-5E__9tAKfb1VquFPypBjCHIpMh!VveGxItN0t7xUvs2M`lQ$Zg=dHgvCgoy9H`}!j@PXdn5h4+zgWk$8izpw8XeW$mRyNZ@K#vJ`o7r(lnS-rv= zU4)3S%ZshOKq4@rfiGSBV9s?d% zW?_?#kJ0R)uh;Q)dWpwz5I2amJw^`fzKgz%sK zk70d8tqanL$>B=HwH?c<*)40n-F5s^a~N8;#&dI=bCYx2$ZdAT@AIIHS@_>MuD7KQ z)$Hw|91S0*+;+sHSzs3gLS+n ztHh&!Mzj+3bow`F|3>37z&ocUrmv~HHRo%(Eslkd`)*Esmy75Zaxvjtyxbrcg9jMt z_0+N;Jw8@)nOLtxmpO|Ezg}51J@}2 Mod (6) -bl_0_0 -> bl0 -br_0_0 -> bl1 -vdd -> wl0 -gnd -> wl1 - -> vpwr - -> vgnd - +[bitcell_base_array/__init__]: Creating dummy_array 1 x 4 From f4e6a8895bb3e775fbc58f4ad1c4df6a047c308d Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 30 Sep 2020 08:50:58 -0700 Subject: [PATCH 55/83] Update riscv unit test --- compiler/modules/bank.py | 8 ++++---- compiler/tests/50_riscv_func_test.py | 8 +++++--- compiler/tests/50_riscv_phys_test.py | 5 +++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 52cf9b8d..4a8c0950 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -374,15 +374,15 @@ class bank(design.design): port=port)) self.add_mod(self.port_address[port]) + total_cols = self.num_cols + self.num_spare_cols + try: local_array_size = OPTS.local_array_size except AttributeError: - #local_array_size = ceil(sqrt(self.num_cols + self.num_spare_cols)) - local_array_size = ceil(sqrt(self.num_cols + self.num_spare_cols)) + local_array_size = 0 if local_array_size > 0: # Find the even multiple that satisfies the fanout with equal sized local arrays - total_cols = self.num_cols + self.num_spare_cols num_lb = floor(total_cols / local_array_size) final_size = total_cols - num_lb * local_array_size cols = [local_array_size] * (num_lb - 1) @@ -393,7 +393,7 @@ class bank(design.design): rows=self.num_rows) else: self.bitcell_array = factory.create(module_type="replica_bitcell_array", - cols=self.num_cols + self.num_spare_cols, + cols=total_cols, rows=self.num_rows) self.add_mod(self.bitcell_array) diff --git a/compiler/tests/50_riscv_func_test.py b/compiler/tests/50_riscv_func_test.py index da2e3786..2a59c6e9 100755 --- a/compiler/tests/50_riscv_func_test.py +++ b/compiler/tests/50_riscv_func_test.py @@ -22,13 +22,15 @@ class riscv_func_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - OPTS.analytical_delay = False - OPTS.netlist_only = True - OPTS.trim_netlist = False + OPTS.num_rw_ports = 1 OPTS.num_w_ports = 0 OPTS.num_r_ports = 1 globals.setup_bitcell() + OPTS.analytical_delay = False + OPTS.netlist_only = True + OPTS.trim_netlist = False + OPTS.local_array_size = 16 # This is a hack to reload the characterizer __init__ with the spice version from importlib import reload diff --git a/compiler/tests/50_riscv_phys_test.py b/compiler/tests/50_riscv_phys_test.py index 4b51084f..87cb44cc 100755 --- a/compiler/tests/50_riscv_phys_test.py +++ b/compiler/tests/50_riscv_phys_test.py @@ -28,8 +28,9 @@ class riscv_phys_test(openram_test): OPTS.num_r_ports = 1 OPTS.num_w_ports = 0 globals.setup_bitcell() - OPTS.route_supplies=False - OPTS.perimeter_pins=False + OPTS.route_supplies = False + OPTS.perimeter_pins = False + OPTS.local_array_size = 16 c = sram_config(word_size=32, write_size=8, From 112d57d90afd7a16ca1d3093d9e6d92abfc82ca2 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 30 Sep 2020 12:39:40 -0700 Subject: [PATCH 56/83] Enable riscv tests --- compiler/modules/bank.py | 9 +++---- compiler/modules/write_driver_array.py | 24 ++++++++++-------- compiler/options.py | 3 +++ compiler/sram/sram_base.py | 35 +++++++++++--------------- compiler/sram/sram_config.py | 2 +- compiler/tests/50_riscv_func_test.py | 18 ++++++------- compiler/tests/50_riscv_phys_test.py | 9 +++---- 7 files changed, 47 insertions(+), 53 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 4a8c0950..41433e46 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -8,8 +8,8 @@ import debug import design from sram_factory import factory -from math import log, ceil, floor, sqrt -from tech import drc +from math import log, ceil, floor +from tech import drc, layer from vector import vector from globals import OPTS @@ -374,8 +374,6 @@ class bank(design.design): port=port)) self.add_mod(self.port_address[port]) - total_cols = self.num_cols + self.num_spare_cols - try: local_array_size = OPTS.local_array_size except AttributeError: @@ -383,6 +381,7 @@ class bank(design.design): if local_array_size > 0: # Find the even multiple that satisfies the fanout with equal sized local arrays + total_cols = self.num_cols + self.num_spare_cols num_lb = floor(total_cols / local_array_size) final_size = total_cols - num_lb * local_array_size cols = [local_array_size] * (num_lb - 1) @@ -393,7 +392,7 @@ class bank(design.design): rows=self.num_rows) else: self.bitcell_array = factory.create(module_type="replica_bitcell_array", - cols=total_cols, + cols=self.num_cols + self.num_spare_cols, rows=self.num_rows) self.add_mod(self.bitcell_array) diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index a5ee20f8..a2458f42 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -215,25 +215,27 @@ class write_driver_array(design.design): start_layer=pin.layer) if self.write_size: for bit in range(self.num_wmasks): - first_inst = self.driver_insts[bit * self.write_size] - first_en_pin = first_inst.get_pin(first_inst.mod.en_name) + inst = self.driver_insts[bit * self.write_size] + en_pin = inst.get_pin(inst.mod.en_name) + # Determine width of wmask modified en_pin with/without col mux + wmask_en_len = self.words_per_row * (self.write_size * self.driver_spacing) + if (self.words_per_row == 1): + en_gap = self.driver_spacing - en_pin.width() + else: + en_gap = self.driver_spacing - last_inst = self.driver_insts[(bit + 1) * self.write_size - 1] - last_en_pin = last_inst.get_pin(last_inst.mod.en_name) - - wmask_en_len = last_en_pin.rx() - first_en_pin.lx() self.add_layout_pin(text=self.en_name + "_{0}".format(bit), - layer=first_en_pin.layer, - offset=first_en_pin.ll(), - width=wmask_en_len, - height=first_en_pin.height()) + layer=en_pin.layer, + offset=en_pin.ll(), + width=wmask_en_len - en_gap, + height=en_pin.height()) for i in range(self.num_spare_cols): inst = self.driver_insts[self.word_size + i] en_pin = inst.get_pin(inst.mod.en_name) self.add_layout_pin(text=self.en_name + "_{0}".format(i + self.num_wmasks), layer="m1", - offset=en_pin.lr() + vector(-drc("minwidth_m1"), 0)) + offset=en_pin.lr() + vector(-drc("minwidth_m1"),0)) elif self.num_spare_cols and not self.write_size: # shorten enable rail to accomodate those for spare write drivers diff --git a/compiler/options.py b/compiler/options.py index 8de3b910..b9be3999 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -30,6 +30,9 @@ class options(optparse.Values): num_r_ports = 0 num_w_ports = 0 + # By default, use local arrays with a max fanout of 16 + #local_array_size = 16 + # Write mask size, default will be overwritten with word_size if not user specified write_size = None diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index fbefc2de..d18e1366 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -87,8 +87,8 @@ class sram_base(design, verilog, lef): for bit in range(self.word_size + self.num_spare_cols): self.add_pin("dout{0}[{1}]".format(port, bit), "OUTPUT") - self.add_pin("vdd", "POWER") - self.add_pin("gnd", "GROUND") + self.add_pin("vdd","POWER") + self.add_pin("gnd","GROUND") def add_global_pex_labels(self): """ @@ -118,19 +118,8 @@ class sram_base(design, verilog, lef): Q = [bank_offset[cell][0] + Q_offset[cell][0], bank_offset[cell][1] + Q_offset[cell][1]] Q_bar = [bank_offset[cell][0] + Q_bar_offset[cell][0], bank_offset[cell][1] + Q_bar_offset[cell][1]] OPTS.words_per_row = self.words_per_row - row = int(cell % (OPTS.num_words / self.words_per_row)) - col = int(cell / (OPTS.num_words)) - self.add_layout_pin_rect_center("bitcell_Q_b{}_r{}_c{}".format(bank_num, - row, - col, - storage_layer_name, - Q)) - - self.add_layout_pin_rect_center("bitcell_Q_bar_b{}_r{}_c{}".format(bank_num, - row, - col, - storage_layer_name, - Q_bar)) + self.add_layout_pin_rect_center("bitcell_Q_b{}_r{}_c{}".format(bank_num, int(cell % (OPTS.num_words / self.words_per_row)), int(cell / (OPTS.num_words))) , storage_layer_name, Q) + self.add_layout_pin_rect_center("bitcell_Q_bar_b{}_r{}_c{}".format(bank_num, int(cell % (OPTS.num_words / self.words_per_row)), int(cell / (OPTS.num_words))), storage_layer_name, Q_bar) for cell in range(len(bl_offsets)): col = bl_meta[cell][0][2] @@ -142,23 +131,27 @@ class sram_base(design, verilog, lef): col = br_meta[cell][0][2] for bitline in range(len(br_offsets[cell])): bitline_location = [float(bank_offset[cell][0]) + br_offsets[cell][bitline][0], float(bank_offset[cell][1]) + br_offsets[cell][bitline][1]] - br.append([bitline_location, br_meta[cell][bitline][3], col]) + br.append([bitline_location, br_meta[cell][bitline][3], col]) for i in range(len(bl)): - self.add_layout_pin_rect_center("bl{0}_{1}".format(bl[i][1], bl[i][2]), bitline_layer_name, bl[i][0]) + self.add_layout_pin_rect_center("bl{0}_{1}".format(bl[i][1], bl[i][2]), bitline_layer_name, bl[i][0]) for i in range(len(br)): - self.add_layout_pin_rect_center("br{0}_{1}".format(br[i][1], br[i][2]), bitline_layer_name, br[i][0]) + self.add_layout_pin_rect_center("br{0}_{1}".format(br[i][1], br[i][2]), bitline_layer_name, br[i][0]) # add pex labels for control logic - for i in range(len(self.control_logic_insts)): + for i in range (len(self.control_logic_insts)): instance = self.control_logic_insts[i] control_logic_offset = instance.offset for output in instance.mod.output_list: pin = instance.mod.get_pin(output) - pin.transform([0, 0], instance.mirror, instance.rotate) + pin.transform([0,0], instance.mirror, instance.rotate) offset = [control_logic_offset[0] + pin.center()[0], control_logic_offset[1] + pin.center()[1]] - self.add_layout_pin_rect_center("{0}{1}".format(pin.name, i), storage_layer_name, offset) + self.add_layout_pin_rect_center("{0}{1}".format(pin.name,i), storage_layer_name, offset) + + + + def create_netlist(self): """ Netlist creation """ diff --git a/compiler/sram/sram_config.py b/compiler/sram/sram_config.py index ee137e4a..fa70d730 100644 --- a/compiler/sram/sram_config.py +++ b/compiler/sram/sram_config.py @@ -25,7 +25,7 @@ class sram_config: # This will get over-written when we determine the organization self.words_per_row = words_per_row - self.compute_sizes() + self.compute_sizes() def set_local_config(self, module): """ Copy all of the member variables to the given module for convenience """ diff --git a/compiler/tests/50_riscv_func_test.py b/compiler/tests/50_riscv_func_test.py index 2a59c6e9..74c46bf7 100755 --- a/compiler/tests/50_riscv_func_test.py +++ b/compiler/tests/50_riscv_func_test.py @@ -8,35 +8,33 @@ # import unittest from testutils import * -import sys, os +import sys,os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug - -# @unittest.skip("SKIPPING 50_riscv_func_test") +#@unittest.skip("SKIPPING 50_riscv_func_test") class riscv_func_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - - OPTS.num_rw_ports = 1 - OPTS.num_w_ports = 0 - OPTS.num_r_ports = 1 - globals.setup_bitcell() OPTS.analytical_delay = False OPTS.netlist_only = True OPTS.trim_netlist = False OPTS.local_array_size = 16 + OPTS.num_rw_ports = 1 + OPTS.num_w_ports = 0 + OPTS.num_r_ports = 1 + globals.setup_bitcell() # This is a hack to reload the characterizer __init__ with the spice version from importlib import reload import characterizer reload(characterizer) - from characterizer import functional + from characterizer import functional, delay from sram_config import sram_config c = sram_config(word_size=32, write_size=8, @@ -56,7 +54,7 @@ class riscv_func_test(openram_test): corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail, error) + self.assertTrue(fail,error) globals.end_openram() diff --git a/compiler/tests/50_riscv_phys_test.py b/compiler/tests/50_riscv_phys_test.py index 87cb44cc..06b9fc6b 100755 --- a/compiler/tests/50_riscv_phys_test.py +++ b/compiler/tests/50_riscv_phys_test.py @@ -8,15 +8,14 @@ # import unittest from testutils import * -import sys, os +import sys,os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug - -# @unittest.skip("SKIPPING 50_riscv_phys_test") +#@unittest.skip("SKIPPING 50_riscv_phys_test") class riscv_phys_test(openram_test): def runTest(self): @@ -27,11 +26,11 @@ class riscv_phys_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 0 + OPTS.local_array_size = 16 globals.setup_bitcell() OPTS.route_supplies = False OPTS.perimeter_pins = False - OPTS.local_array_size = 16 - + c = sram_config(word_size=32, write_size=8, num_words=256, From 2b475670f749277e4d29cdbb2b7467e0cdab30de Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 30 Sep 2020 12:40:07 -0700 Subject: [PATCH 57/83] Check for failed result in functional simulation --- compiler/characterizer/delay.py | 8 +++---- compiler/characterizer/functional.py | 34 +++++++++++++++++----------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 273666cf..11235109 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -134,17 +134,17 @@ class delay(simulation): self.bitline_volt_meas = [] self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ZERO", - self.bl_name)) + self.bl_name)) self.bitline_volt_meas[-1].meta_str = sram_op.READ_ZERO self.bitline_volt_meas.append(voltage_at_measure("v_br_READ_ZERO", - self.br_name)) + self.br_name)) self.bitline_volt_meas[-1].meta_str = sram_op.READ_ZERO self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ONE", - self.bl_name)) + self.bl_name)) self.bitline_volt_meas[-1].meta_str = sram_op.READ_ONE self.bitline_volt_meas.append(voltage_at_measure("v_br_READ_ONE", - self.br_name)) + self.br_name)) self.bitline_volt_meas[-1].meta_str = sram_op.READ_ONE return self.bitline_volt_meas diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index 270c1a2b..3ecbe48d 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -229,17 +229,25 @@ class functional(simulation): sp_read_value = "" for bit in range(self.word_size + self.num_spare_cols): value = parse_spice_list("timing", "v{0}.{1}ck{2}".format(dout_port.lower(), bit, check)) - if value > self.v_high: - sp_read_value = "1" + sp_read_value - elif value < self.v_low: - sp_read_value = "0" + sp_read_value - else: - error ="FAILED: {0}_{1} value {2} at time {3}n does not fall within noise margins <{4} or >{5}.".format(dout_port, - bit, - value, - eo_period, - self.v_low, - self.v_high) + try: + value = float(value) + if value > self.v_high: + sp_read_value = "1" + sp_read_value + elif value < self.v_low: + sp_read_value = "0" + sp_read_value + else: + error ="FAILED: {0}_{1} value {2} at time {3}n does not fall within noise margins <{4} or >{5}.".format(dout_port, + bit, + value, + eo_period, + self.v_low, + self.v_high) + except ValueError: + error ="FAILED: {0}_{1} value {2} at time {3}n is not a float.".format(dout_port, + bit, + value, + eo_period) + return (0, error) self.read_results.append([sp_read_value, dout_port, eo_period, check]) @@ -348,8 +356,8 @@ class functional(simulation): # Write important signals to stim file self.sf.write("\n\n* Important signals for debug\n") - self.sf.write("* bl: {}\n".format(self.bl_name)) - self.sf.write("* br: {}\n".format(self.br_name)) + self.sf.write("* bl: {}\n".format(self.bl_name.format(port))) + self.sf.write("* br: {}\n".format(self.br_name.format(port))) self.sf.write("* s_en: {}\n".format(self.sen_name)) self.sf.write("* q: {}\n".format(self.q_name)) self.sf.write("* qbar: {}\n".format(self.qbar_name)) From bd125e2ed30a9e471eefe679dda1d45c9a0854e5 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 1 Oct 2020 07:17:16 -0700 Subject: [PATCH 58/83] Check for duplicate instance names. --- compiler/base/hierarchy_layout.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 0cbe6e8c..b565e424 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -211,6 +211,12 @@ class layout(): def add_inst(self, name, mod, offset=[0, 0], mirror="R0", rotate=0): """ Adds an instance of a mod to this module """ + # Contacts are not really instances, so skip them + if "contact" not in mod.name: + # Check that the instance name is unique + for inst in self.insts: + debug.check(name != inst.name, "Duplicate named instance in {0}: {1}".format(self.name, name)) + self.insts.append(geometry.instance(name, mod, offset, mirror, rotate)) debug.info(3, "adding instance {}".format(self.insts[-1])) # This is commented out for runtime reasons From 8ce23d7f1782a7eeca614437d98b97d8d8f20e0f Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 1 Oct 2020 07:17:32 -0700 Subject: [PATCH 59/83] Provide unique WL driver instance name --- compiler/modules/local_bitcell_array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index 80708dec..c07b4f1b 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -124,7 +124,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): self.wl_insts = [] self.driver_wordline_outputs = [] for port in self.all_ports: - self.wl_insts.append(self.add_inst(name="wl_driver", + self.wl_insts.append(self.add_inst(name="wl_driver{}".format(port), mod=self.wl_array)) temp = [] temp += [self.get_rbl_wordline_names(port)[port]] From b81cdab0d6ce3fd23f485f6625cd69029b18f4a6 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 1 Oct 2020 07:43:06 -0700 Subject: [PATCH 60/83] Use unique instance names for channel routes. --- compiler/base/hierarchy_layout.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index b565e424..133ecc9b 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -1035,7 +1035,7 @@ class layout(): """ import channel_route cr = channel_route.channel_route(netlist, offset, layer_stack, directions, vertical=True, parent=self) - self.add_inst("vc", cr) + self.add_inst(cr.name, cr) self.connect_inst([]) def create_horizontal_channel_route(self, netlist, offset, layer_stack, directions=None): @@ -1044,7 +1044,7 @@ class layout(): """ import channel_route cr = channel_route.channel_route(netlist, offset, layer_stack, directions, vertical=False, parent=self) - self.add_inst("hc", cr) + self.add_inst(cr.name, cr) self.connect_inst([]) def add_boundary(self, ll=vector(0, 0), ur=None): From d315ff18e55e08dc7743a0b7f8d3bd37eed5b0f4 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 1 Oct 2020 08:07:03 -0700 Subject: [PATCH 61/83] Add num_threads to options. PEP8 cleanup. --- compiler/characterizer/simulation.py | 2 +- compiler/characterizer/stimuli.py | 33 +++++++++++++++------------- compiler/options.py | 3 +++ 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index 51f99c03..4f045c82 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -414,7 +414,7 @@ class simulation(): self.sram.graph_exclude_addr_dff() self.sram.graph_exclude_data_dff() self.sram.graph_exclude_ctrl_dffs() - self.sram.bank.bitcell_array.graph_exclude_replica_col_bits() + self.sram.bank.bitcell_array.graph_exclude_replica_col_bits() def set_internal_spice_names(self): """Sets important names for characterization such as Sense amp enable and internal bit nets.""" diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index 90fd6213..0b2ecef4 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -230,7 +230,7 @@ class stimuli(): def gen_meas_value(self, meas_name, dout, t_intital, t_final): measure_string=".meas tran {0} AVG v({1}) FROM={2}n TO={3}n\n\n".format(meas_name, dout, t_intital, t_final) self.sf.write(measure_string) - + def write_control(self, end_time, runlvl=4): """ Write the control cards to run and end the simulation """ @@ -243,7 +243,7 @@ class stimuli(): reltol = 0.005 # 0.5% else: reltol = 0.001 # 0.1% - timestep = 10 #ps, was 5ps but ngspice was complaining the timestep was too small in certain tests. + timestep = 10 # ps, was 5ps but ngspice was complaining the timestep was too small in certain tests. # UIC is needed for ngspice to converge self.sf.write(".TRAN {0}p {1}n UIC\n".format(timestep,end_time)) @@ -271,7 +271,6 @@ class stimuli(): # end the stimulus file self.sf.write(".end\n\n") - def write_include(self, circuit): """Writes include statements, inputs are lists of model files""" @@ -291,13 +290,12 @@ class stimuli(): else: debug.error("Could not find spice model: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item)) - def write_supply(self): """ Writes supply voltage statements """ gnd_node_name = "0" self.sf.write("V{0} {0} {1} {2}\n".format(self.vdd_name, gnd_node_name, self.voltage)) - #Adding a commented out supply for simulators where gnd and 0 are not global grounds. + # Adding a commented out supply for simulators where gnd and 0 are not global grounds. self.sf.write("\n*Nodes gnd and 0 are the same global ground node in ngspice/hspice/xa. Otherwise, this source may be needed.\n") self.sf.write("*V{0} {0} {1} {2}\n".format(self.gnd_name, gnd_node_name, 0.0)) @@ -306,7 +304,7 @@ class stimuli(): temp_stim = "{0}stim.sp".format(OPTS.openram_temp) import datetime start_time = datetime.datetime.now() - debug.check(OPTS.spice_exe!="","No spice simulator has been found.") + debug.check(OPTS.spice_exe != "", "No spice simulator has been found.") if OPTS.spice_name == "xa": # Output the xa configurations here. FIXME: Move this to write it once. @@ -314,27 +312,32 @@ class stimuli(): xa_cfg.write("set_sim_level -level 7\n") xa_cfg.write("set_powernet_level 7 -node vdd\n") xa_cfg.close() - cmd = "{0} {1} -c {2}xa.cfg -o {2}xa -mt 2".format(OPTS.spice_exe, - temp_stim, - OPTS.openram_temp) + cmd = "{0} {1} -c {2}xa.cfg -o {2}xa -mt {3}".format(OPTS.spice_exe, + temp_stim, + OPTS.openram_temp, + OPTS.num_threads) valid_retcode=0 elif OPTS.spice_name == "hspice": # TODO: Should make multithreading parameter a configuration option - cmd = "{0} -mt 2 -i {1} -o {2}timing".format(OPTS.spice_exe, - temp_stim, - OPTS.openram_temp) + cmd = "{0} -mt {1} -i {2} -o {3}timing".format(OPTS.spice_exe, + OPTS.num_threads, + temp_stim, + OPTS.openram_temp) valid_retcode=0 else: # ngspice 27+ supports threading with "set num_threads=4" in the stimulus file or a .spiceinit # Measurements can't be made with a raw file set in ngspice # -r {2}timing.raw + ng_cfg = open("{}.spinit".format(OPTS.openram_temp), "w") + ng_cfg.write("set num_threads={}\n".format(OPTS.num_threads)) + ng_cfg.close() + cmd = "{0} -b -o {2}timing.lis {1}".format(OPTS.spice_exe, temp_stim, OPTS.openram_temp) # for some reason, ngspice-25 returns 1 when it only has acceptable warnings valid_retcode=1 - spice_stdout = open("{0}spice_stdout.log".format(OPTS.openram_temp), 'w') spice_stderr = open("{0}spice_stderr.log".format(OPTS.openram_temp), 'w') @@ -348,7 +351,7 @@ class stimuli(): debug.error("Spice simulation error: " + cmd, -1) else: end_time = datetime.datetime.now() - delta_time = round((end_time-start_time).total_seconds(),1) - debug.info(2,"*** Spice: {} seconds".format(delta_time)) + delta_time = round((end_time - start_time).total_seconds(), 1) + debug.info(2, "*** Spice: {} seconds".format(delta_time)) diff --git a/compiler/options.py b/compiler/options.py index b9be3999..2508a5b7 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -119,6 +119,9 @@ class options(optparse.Values): # For sky130, we need magic for filtering. magic_exe = None + # Number of threads to use + num_threads = 4 + # Should we print out the banner at startup print_banner = True From aaa36bf5cf428d2188d3d329cf7a863fe7eba4c6 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 1 Oct 2020 09:55:17 -0700 Subject: [PATCH 62/83] Default to 2 threads only --- compiler/options.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/options.py b/compiler/options.py index 2508a5b7..d28d3573 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -120,7 +120,7 @@ class options(optparse.Values): magic_exe = None # Number of threads to use - num_threads = 4 + num_threads = 2 # Should we print out the banner at startup print_banner = True From 18c8ad265eb9dcc3780287b29a6714ed13c01008 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 1 Oct 2020 09:55:34 -0700 Subject: [PATCH 63/83] Unique name for sram channel routes --- compiler/sram/sram_1bank.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index d35baf23..2dfd8096 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -414,7 +414,7 @@ class sram_1bank(sram_base): layer_stack=self.m1_stack, parent=self) if add_routes: - self.add_inst("hc", cr) + self.add_inst(cr.name, cr) self.connect_inst([]) else: self.col_addr_bus_size[port] = cr.height @@ -470,7 +470,7 @@ class sram_1bank(sram_base): layer_stack=layer_stack, parent=self) if add_routes: - self.add_inst("hc", cr) + self.add_inst(cr.name, cr) self.connect_inst([]) else: self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap @@ -482,7 +482,7 @@ class sram_1bank(sram_base): layer_stack=layer_stack, parent=self) if add_routes: - self.add_inst("hc", cr) + self.add_inst(cr.name, cr) self.connect_inst([]) else: self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap From b32c123dab8e3928801bed6f6f59473b7b6a86f1 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 1 Oct 2020 11:10:18 -0700 Subject: [PATCH 64/83] PEP8 cleanup. Un-hard-code bitcell layers. Remove dead variable. --- compiler/characterizer/simulation.py | 35 ++- compiler/sram/sram.py | 4 +- compiler/sram/sram_base.py | 70 +++-- compiler/tests/26_hspice_pex_pinv_test.py | 78 ++--- compiler/tests/26_ngspice_pex_pinv_test.py | 69 +++-- compiler/tests/26_pex_test.py | 319 --------------------- compiler/verify/magic.py | 66 ++--- 7 files changed, 168 insertions(+), 473 deletions(-) delete mode 100755 compiler/tests/26_pex_test.py diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index 4f045c82..ecb9adb8 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -51,23 +51,21 @@ class simulation(): self.load = tech.spice["dff_in_cap"] * 4 self.v_high = self.vdd_voltage - tech.spice["nom_threshold"] - self.v_low = tech.spice["nom_threshold"] + self.v_low = tech.spice["nom_threshold"] self.gnd_voltage = 0 def create_signal_names(self): self.addr_name = "a" self.din_name = "din" self.dout_name = "dout" - self.pins = self.gen_pin_names(port_signal_names=(self.addr_name,self.din_name,self.dout_name), - port_info=(len(self.all_ports),self.write_ports,self.read_ports), + self.pins = self.gen_pin_names(port_signal_names=(self.addr_name, self.din_name, self.dout_name), + port_info=(len(self.all_ports), self.write_ports, self.read_ports), abits=self.addr_size, dbits=self.word_size + self.num_spare_cols) debug.check(len(self.sram.pins) == len(self.pins), "Number of pins generated for characterization \ do not match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(self.sram.pins, - self.pins)) - #This is TODO once multiport control has been finalized. - #self.control_name = "CSB" + self.pins)) def set_stimulus_variables(self): # Clock signals @@ -96,7 +94,7 @@ class simulation(): def add_control_one_port(self, port, op): """Appends control signals for operation to a given port""" - #Determine values to write to port + # Determine values to write to port web_val = 1 csb_val = 1 if op == "read": @@ -406,7 +404,9 @@ class simulation(): return pin_names def add_graph_exclusions(self): - """Exclude portions of SRAM from timing graph which are not relevant""" + """ + Exclude portions of SRAM from timing graph which are not relevant + """ # other initializations can only be done during analysis when a bit has been selected # for testing. @@ -417,7 +417,9 @@ class simulation(): self.sram.bank.bitcell_array.graph_exclude_replica_col_bits() def set_internal_spice_names(self): - """Sets important names for characterization such as Sense amp enable and internal bit nets.""" + """ + Sets important names for characterization such as Sense amp enable and internal bit nets. + """ port = self.read_ports[0] if not OPTS.use_pex: @@ -458,11 +460,10 @@ class simulation(): self.sen_name = self.get_sen_name(self.graph.all_paths) debug.info(2, "s_en name = {}".format(self.sen_name)) - self.bl_name = "bl{0}_{1}".format(port, OPTS.word_size - 1) self.br_name = "br{0}_{1}".format(port, OPTS.word_size - 1) - debug.info(2, "bl name={}, br name={}".format(self.bl_name, self.br_name)) + debug.info(2, "bl name={}, br name={}".format(self.bl_name, self.br_name)) def get_sen_name(self, paths, assumed_port=None): """ @@ -481,7 +482,9 @@ class simulation(): return sen_name def create_graph(self): - """Creates timing graph to generate the timing paths for the SRAM output.""" + """ + Creates timing graph to generate the timing paths for the SRAM output. + """ self.sram.clear_exclude_bits() # Removes previous bit exclusions self.sram.graph_exclude_bits(self.wordline_row, self.bitline_column) @@ -492,7 +495,9 @@ class simulation(): self.sram.build_graph(self.graph, self.sram_instance_name, self.pins) def get_bl_name_search_exclusions(self): - """Gets the mods as a set which should be excluded while searching for name.""" + """ + Gets the mods as a set which should be excluded while searching for name. + """ # Exclude the RBL as it contains bitcells which are not in the main bitcell array # so it makes the search awkward @@ -519,7 +524,9 @@ class simulation(): return path_net_name def get_bl_name(self, paths, port): - """Gets the signal name associated with the bitlines in the bank.""" + """ + Gets the signal name associated with the bitlines in the bank. + """ cell_mod = factory.create(module_type=OPTS.bitcell) cell_bl = cell_mod.get_bl_name(port) diff --git a/compiler/sram/sram.py b/compiler/sram/sram.py index 6b5d117d..992919f0 100644 --- a/compiler/sram/sram.py +++ b/compiler/sram/sram.py @@ -67,7 +67,7 @@ class sram(): """Dump config file with all options. Include defaults and anything changed by input config.""" f = open(name, "w") - var_dict = dict((name, getattr(OPTS, name)) for name in dir(OPTS) if not name.startswith('__') and not callable(getattr(OPTS, name))) + var_dict = dict((name, getattr(OPTS, name)) for name in dir(OPTS) if not name.startswith('__') and not callable(getattr(OPTS, name))) for var_name, var_value in var_dict.items(): if isinstance(var_value, str): f.write(str(var_name) + " = " + "\"" + str(var_value) + "\"\n") @@ -156,4 +156,4 @@ class sram(): oname = OPTS.output_path + OPTS.output_name + "_extended.py" debug.print_raw("Extended Config: Writing to {0}".format(oname)) self.extended_config_write(oname) - print_time("Extended Config", datetime.datetime.now(), start_time) \ No newline at end of file + print_time("Extended Config", datetime.datetime.now(), start_time) diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index d18e1366..5f02ce56 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -15,9 +15,6 @@ from design import design from verilog import verilog from lef import lef from sram_factory import factory -from tech import drc -import numpy as np -import logical_effort class sram_base(design, verilog, lef): @@ -43,9 +40,6 @@ class sram_base(design, verilog, lef): if not self.num_spare_cols: self.num_spare_cols = 0 - # For logical effort delay calculations. - self.all_mods_except_control_done = False - def add_pins(self): """ Add pins for entire SRAM. """ @@ -87,14 +81,16 @@ class sram_base(design, verilog, lef): for bit in range(self.word_size + self.num_spare_cols): self.add_pin("dout{0}[{1}]".format(port, bit), "OUTPUT") - self.add_pin("vdd","POWER") - self.add_pin("gnd","GROUND") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") def add_global_pex_labels(self): """ Add pex labels at the sram level for spice analysis """ + + # add pex labels for bitcells for bank_num in range(len(self.bank_insts)): bank = self.bank_insts[bank_num] @@ -111,47 +107,62 @@ class sram_base(design, verilog, lef): bl = [] br = [] - storage_layer_name = "m1" - bitline_layer_name = "m2" + storage_layer_name = self.bitcell.get_pin("Q").layer + bitline_layer_name = self.bitcell.get_pin("bl").layer for cell in range(len(bank_offset)): - Q = [bank_offset[cell][0] + Q_offset[cell][0], bank_offset[cell][1] + Q_offset[cell][1]] - Q_bar = [bank_offset[cell][0] + Q_bar_offset[cell][0], bank_offset[cell][1] + Q_bar_offset[cell][1]] + Q = [bank_offset[cell][0] + Q_offset[cell][0], + bank_offset[cell][1] + Q_offset[cell][1]] + Q_bar = [bank_offset[cell][0] + Q_bar_offset[cell][0], + bank_offset[cell][1] + Q_bar_offset[cell][1]] OPTS.words_per_row = self.words_per_row - self.add_layout_pin_rect_center("bitcell_Q_b{}_r{}_c{}".format(bank_num, int(cell % (OPTS.num_words / self.words_per_row)), int(cell / (OPTS.num_words))) , storage_layer_name, Q) - self.add_layout_pin_rect_center("bitcell_Q_bar_b{}_r{}_c{}".format(bank_num, int(cell % (OPTS.num_words / self.words_per_row)), int(cell / (OPTS.num_words))), storage_layer_name, Q_bar) + row = int(cell % (OPTS.num_words / self.words_per_row)) + col = int(cell / (OPTS.num_words)) + self.add_layout_pin_rect_center("bitcell_Q_b{}_r{}_c{}".format(bank_num, + row, + col), + storage_layer_name, + Q) + self.add_layout_pin_rect_center("bitcell_Q_bar_b{}_r{}_c{}".format(bank_num, + row, + col), + storage_layer_name, + Q_bar) for cell in range(len(bl_offsets)): col = bl_meta[cell][0][2] for bitline in range(len(bl_offsets[cell])): - bitline_location = [float(bank_offset[cell][0]) + bl_offsets[cell][bitline][0], float(bank_offset[cell][1]) + bl_offsets[cell][bitline][1]] + bitline_location = [float(bank_offset[cell][0]) + bl_offsets[cell][bitline][0], + float(bank_offset[cell][1]) + bl_offsets[cell][bitline][1]] bl.append([bitline_location, bl_meta[cell][bitline][3], col]) for cell in range(len(br_offsets)): col = br_meta[cell][0][2] for bitline in range(len(br_offsets[cell])): - bitline_location = [float(bank_offset[cell][0]) + br_offsets[cell][bitline][0], float(bank_offset[cell][1]) + br_offsets[cell][bitline][1]] - br.append([bitline_location, br_meta[cell][bitline][3], col]) + bitline_location = [float(bank_offset[cell][0]) + br_offsets[cell][bitline][0], + float(bank_offset[cell][1]) + br_offsets[cell][bitline][1]] + br.append([bitline_location, br_meta[cell][bitline][3], col]) for i in range(len(bl)): - self.add_layout_pin_rect_center("bl{0}_{1}".format(bl[i][1], bl[i][2]), bitline_layer_name, bl[i][0]) + self.add_layout_pin_rect_center("bl{0}_{1}".format(bl[i][1], bl[i][2]), + bitline_layer_name, bl[i][0]) for i in range(len(br)): - self.add_layout_pin_rect_center("br{0}_{1}".format(br[i][1], br[i][2]), bitline_layer_name, br[i][0]) + self.add_layout_pin_rect_center("br{0}_{1}".format(br[i][1], br[i][2]), + bitline_layer_name, br[i][0]) # add pex labels for control logic - for i in range (len(self.control_logic_insts)): + for i in range(len(self.control_logic_insts)): instance = self.control_logic_insts[i] control_logic_offset = instance.offset for output in instance.mod.output_list: pin = instance.mod.get_pin(output) - pin.transform([0,0], instance.mirror, instance.rotate) - offset = [control_logic_offset[0] + pin.center()[0], control_logic_offset[1] + pin.center()[1]] - self.add_layout_pin_rect_center("{0}{1}".format(pin.name,i), storage_layer_name, offset) - - - - + pin.transform([0, 0], instance.mirror, instance.rotate) + offset = [control_logic_offset[0] + pin.center()[0], + control_logic_offset[1] + pin.center()[1]] + self.add_layout_pin_rect_center("{0}{1}".format(pin.name, i), + storage_layer_name, + offset) def create_netlist(self): """ Netlist creation """ @@ -370,10 +381,6 @@ class sram_base(design, verilog, lef): self.bank_count = 0 - # The control logic can resize itself based on the other modules. - # Requires all other modules added before control logic. - self.all_mods_except_control_done = True - c = reload(__import__(OPTS.control_logic)) self.mod_control_logic = getattr(c, OPTS.control_logic) @@ -619,6 +626,7 @@ class sram_base(design, verilog, lef): sp.write("* Column mux: {}:1\n".format(self.words_per_row)) sp.write("**************************************************\n") # This causes unit test mismatch + # sp.write("* Created: {0}\n".format(datetime.datetime.now())) # sp.write("* User: {0}\n".format(getpass.getuser())) # sp.write(".global {0} {1}\n".format(spice["vdd_name"], diff --git a/compiler/tests/26_hspice_pex_pinv_test.py b/compiler/tests/26_hspice_pex_pinv_test.py index b4b55cdb..96b2d108 100755 --- a/compiler/tests/26_hspice_pex_pinv_test.py +++ b/compiler/tests/26_hspice_pex_pinv_test.py @@ -9,8 +9,8 @@ Run regression tests/pex test on an extracted pinv to ensure pex functionality with HSPICE. """ import unittest -from testutils import header,openram_test -import sys,os +from testutils import header, openram_test +import sys, os sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS @@ -35,43 +35,43 @@ class hspice_pex_pinv_test(openram_test): # generate the pinv prev_purge_value = OPTS.purge_temp - OPTS.purge_temp = False # force set purge to false to save the sp file + # force set purge to false to save the sp file + OPTS.purge_temp = False debug.info(2, "Checking 1x size inverter") tx = pinv.pinv(name="pinv", size=1) - tempgds = "{0}{1}.gds".format(OPTS.openram_temp,tx.name) + tempgds = "{0}{1}.gds".format(OPTS.openram_temp, tx.name) tx.gds_write(tempgds) - tempsp = "{0}{1}.sp".format(OPTS.openram_temp,tx.name) + tempsp = "{0}{1}.sp".format(OPTS.openram_temp, tx.name) tx.sp_write(tempsp) - # make sure that the library simulation is successful\ - sp_delay = self.simulate_delay(test_module = tempsp, - top_level_name = tx.name) - if sp_delay is "Failed": + # make sure that the library simulation is successful + sp_delay = self.simulate_delay(test_module=tempsp, + top_level_name=tx.name) + if sp_delay == "Failed": self.fail('Library Spice module did not behave as expected') # now generate its pex file pex_file = self.run_pex(tx) - OPTS.purge_temp = prev_purge_value # restore the old purge value + OPTS.purge_temp = prev_purge_value # restore the old purge value # generate simulation for pex, make sure the simulation is successful - pex_delay = self.simulate_delay(test_module = pex_file, - top_level_name = tx.name) + pex_delay = self.simulate_delay(test_module=pex_file, + top_level_name=tx.name) # make sure the extracted spice simulated - if pex_delay is "Failed": + if pex_delay == "Failed": self.fail('Pex file did not behave as expected') # if pex data is bigger than original spice file then result is ok # However this may not always be true depending on the netlist provided # comment out for now - #debug.info(2,"pex_delay: {0}".format(pex_delay)) - #debug.info(2,"sp_delay: {0}".format(sp_delay)) + # debug.info(2,"pex_delay: {0}".format(pex_delay)) + # debug.info(2,"sp_delay: {0}".format(sp_delay)) - #assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\ - #.format(pex_delay,sp_delay) + # assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\ + # .format(pex_delay,sp_delay) globals.end_openram() def simulate_delay(self, test_module, top_level_name): - from characterizer import charutils from charutils import parse_spice_list # setup simulation sim_file = OPTS.openram_temp + "stim.sp" @@ -87,43 +87,43 @@ class hspice_pex_pinv_test(openram_test): from characterizer import measurements, stimuli corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) sim_file = open(sim_file, "w") - simulation = stimuli(sim_file,corner) + simulation = stimuli(sim_file, corner) # library files simulation.write_include(cir_file) # supply voltages - simulation.gen_constant(sig_name ="vdd", - v_val = tech.spice["nom_supply_voltage"]) - simulation.gen_constant(sig_name = "gnd", - v_val = "0v") + simulation.gen_constant(sig_name="vdd", + v_val=tech.spice["nom_supply_voltage"]) + simulation.gen_constant(sig_name="gnd", + v_val="0v") run_time = tech.spice["feasible_period"] * 4 # input voltage clk_period = tech.spice["feasible_period"] - simulation.gen_pwl(sig_name ="input", - clk_times = [clk_period,clk_period], - data_values = [1,0], - period = clk_period, - slew = 0.001*tech.spice["feasible_period"], - setup = 0) + simulation.gen_pwl(sig_name="input", + clk_times=[clk_period, clk_period], + data_values=[1, 0], + period=clk_period, + slew=0.001 * tech.spice["feasible_period"], + setup=0) # instantiation of simulated pinv - simulation.inst_model(pins = ["input", "output", "vdd", "gnd"], - model_name = top_module_name) + simulation.inst_model(pins=["input", "output", "vdd", "gnd"], + model_name=top_module_name) # delay measurement - delay_measure = measurements.delay_measure(measure_name = "pinv_delay", - trig_name = "input", - targ_name = "output", - trig_dir_str = "FALL", - targ_dir_str = "RISE", - has_port = False) + delay_measure = measurements.delay_measure(measure_name="pinv_delay", + trig_name="input", + targ_name="output", + trig_dir_str="FALL", + targ_dir_str="RISE", + has_port=False) trig_td = trag_td = 0.01 * run_time - rest_info = trig_td,trag_td,tech.spice["nom_supply_voltage"] + rest_info = trig_td, trag_td, tech.spice["nom_supply_voltage"] delay_measure.write_measure(simulation, rest_info) - simulation.write_control(end_time = run_time) + simulation.write_control(end_time=run_time) sim_file.close() return simulation diff --git a/compiler/tests/26_ngspice_pex_pinv_test.py b/compiler/tests/26_ngspice_pex_pinv_test.py index e6e0cfb2..e5dbe5db 100755 --- a/compiler/tests/26_ngspice_pex_pinv_test.py +++ b/compiler/tests/26_ngspice_pex_pinv_test.py @@ -34,43 +34,43 @@ class ngspice_pex_pinv_test(openram_test): # generate the pinv module prev_purge_value = OPTS.purge_temp - OPTS.purge_temp = False # force set purge to false to save the sp file + OPTS.purge_temp = False # force set purge to false to save the sp file debug.info(2, "Checking 1x size inverter") tx = pinv.pinv(name="pinv", size=1) - tempgds = "{0}{1}.gds".format(OPTS.openram_temp,tx.name) + tempgds = "{0}{1}.gds".format(OPTS.openram_temp, tx.name) tx.gds_write(tempgds) - tempsp = "{0}{1}.sp".format(OPTS.openram_temp,tx.name) + tempsp = "{0}{1}.sp".format(OPTS.openram_temp, tx.name) tx.sp_write(tempsp) # make sure that the library simulation is successful - sp_delay = self.simulate_delay(test_module = tempsp, - top_level_name = tx.name) - if sp_delay is "Failed": + sp_delay = self.simulate_delay(test_module=tempsp, + top_level_name=tx.name) + if sp_delay == "Failed": self.fail('Library Spice module did not behave as expected') # now generate its pex file pex_file = self.run_pex(tx) - OPTS.purge_temp = prev_purge_value # restore the old purge value + # restore the old purge value + OPTS.purge_temp = prev_purge_value # generate simulation for pex, make sure the simulation is successful - pex_delay = self.simulate_delay(test_module = pex_file, - top_level_name = tx.name) + pex_delay = self.simulate_delay(test_module=pex_file, + top_level_name=tx.name) # make sure the extracted spice simulated - if pex_delay is "Failed": + if pex_delay == "Failed": self.fail('Pex file did not behave as expected') # if pex data is bigger than original spice file then result is ok # However this may not always be true depending on the netlist provided # comment out for now - #debug.info(2,"pex_delay: {0}".format(pex_delay)) - #debug.info(2,"sp_delay: {0}".format(sp_delay)) + # debug.info(2,"pex_delay: {0}".format(pex_delay)) + # debug.info(2,"sp_delay: {0}".format(sp_delay)) - #assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\ - #.format(pex_delay,sp_delay) + # assert pex_delay > sp_delay, "pex delay {0} is smaller than sp_delay {1}"\ + # .format(pex_delay,sp_delay) globals.end_openram() def simulate_delay(self, test_module, top_level_name): - from characterizer import charutils from charutils import parse_spice_list # setup simulation sim_file = OPTS.openram_temp + "stim.sp" @@ -86,47 +86,46 @@ class ngspice_pex_pinv_test(openram_test): from characterizer import measurements, stimuli corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) sim_file = open(sim_file, "w") - simulation = stimuli(sim_file,corner) + simulation = stimuli(sim_file, corner) # library files simulation.write_include(cir_file) # supply voltages - simulation.gen_constant(sig_name ="vdd", - v_val = tech.spice["nom_supply_voltage"]) + simulation.gen_constant(sig_name="vdd", + v_val=tech.spice["nom_supply_voltage"]) # The scn4m_subm and ngspice combination will have a gnd source error: # "Fatal error: instance vgnd is a shorted VSRC" # However, remove gnd power for all techa pass for this test # simulation.gen_constant(sig_name = "gnd", # v_val = "0v") - run_time = tech.spice["feasible_period"] * 4 # input voltage clk_period = tech.spice["feasible_period"] - simulation.gen_pwl(sig_name ="input", - clk_times = [clk_period,clk_period], - data_values = [1,0], - period = clk_period, - slew = 0.001*tech.spice["feasible_period"], - setup = 0) + simulation.gen_pwl(sig_name="input", + clk_times=[clk_period, clk_period], + data_values=[1, 0], + period=clk_period, + slew=0.001 * tech.spice["feasible_period"], + setup=0) # instantiation of simulated pinv - simulation.inst_model(pins = ["input", "output", "vdd", "gnd"], - model_name = top_module_name) + simulation.inst_model(pins=["input", "output", "vdd", "gnd"], + model_name=top_module_name) # delay measurement - delay_measure = measurements.delay_measure(measure_name = "pinv_delay", - trig_name = "input", - targ_name = "output", - trig_dir_str = "FALL", - targ_dir_str = "RISE", - has_port = False) + delay_measure = measurements.delay_measure(measure_name="pinv_delay", + trig_name="input", + targ_name="output", + trig_dir_str="FALL", + targ_dir_str="RISE", + has_port=False) trig_td = trag_td = 0.01 * run_time - rest_info = trig_td,trag_td,tech.spice["nom_supply_voltage"] + rest_info = trig_td, trag_td, tech.spice["nom_supply_voltage"] delay_measure.write_measure(simulation, rest_info) - simulation.write_control(end_time = run_time) + simulation.write_control(end_time=run_time) sim_file.close() return simulation diff --git a/compiler/tests/26_pex_test.py b/compiler/tests/26_pex_test.py deleted file mode 100755 index 4eff7db5..00000000 --- a/compiler/tests/26_pex_test.py +++ /dev/null @@ -1,319 +0,0 @@ -#!/usr/bin/env python3 -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2019 Regents of the University of California and The Board -# of Regents for the Oklahoma Agricultural and Mechanical College -# (acting for and on behalf of Oklahoma State University) -# All rights reserved. -# -import unittest -from testutils import * -import sys,os -sys.path.append(os.getenv("OPENRAM_HOME")) -import globals -from globals import OPTS -from sram_factory import factory -import debug - -@unittest.skip("SKIPPING 26_pex_test") -class sram_func_test(openram_test): - - def runTest(self): - config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - globals.init_openram(config_file) - - OPTS.use_pex = True - - # This is a hack to reload the characterizer __init__ with the spice version - from importlib import reload - import characterizer - reload(characterizer) - from characterizer import setup_hold - if not OPTS.spice_exe: - debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) - - self.func_test(bank_num=1) - self.func_test(bank_num=2) - self.func_test(bank_num=4) - - globals.end_openram() - - def func_test(self, bank_num): - - import sram - import tech - - debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") - s = sram.sram(word_size=OPTS.word_size, - num_words=OPTS.num_words, - num_banks=OPTS.num_banks, - name="test_sram1") - - tempspice = OPTS.openram_temp + "temp.sp" - tempgds = OPTS.openram_temp + "temp.gds" - - s.sp_write(tempspice) - s.gds_write(tempgds) - - self.assertFalse(verify.run_drc(s.name, tempgds)) - self.assertFalse(verify.run_lvs(s.name, tempgds, tempspice)) - self.assertFalse(verify.run_pex(s.name, tempgds, - tempspice, output=OPTS.openram_temp + "temp_pex.sp")) - - import sp_file - stimulus_file = OPTS.openram_temp + "stimulus.sp" - a_stimulus = sp_file.sp_file(stimulus_file) - self.write_stimulus(a_stimulus) - - simulator_file = OPTS.openram_temp + "simulator.sp" - a_simulator = sp_file.sp_file(simulator_file) - self.write_simulator(a_simulator) - - result_file = OPTS.openram_temp + "result" - - import os - - if OPTS.spice_name == "hspice": - cmd = "hspice -mt 2 -i {0} > {1} ".format( - simulator_file, result_file) - else: - cmd = "ngspice -b -i {0} > {1} ".format( - simulator_file, result_file) - os.system(cmd) - - import re - sp_result = open(result_file, "r") - contents = sp_result.read() - key = "vr1" - val = re.search( - r"{0}(\s*)=(\s*)(\d*(.).*)(\s*)(from)".format(key), contents) - val = val.group(3) - value1 = float(self.convert_voltage_unit(val)) - - key = "vr2" - val = re.search( - r"{0}(\s*)=(\s*)(\d*(.).*)(\s*)(from)".format(key), contents) - val = val.group(3) - value2 = float(self.convert_voltage_unit(val)) - - self.assertTrue(round(value1) > 0.5 * tech.spice["supply_voltage"]) - self.assertTrue(round(value2) < 0.5 * tech.spice["supply_voltage"]) - - - - def convert_voltage_unit(self, string): - newstring = "" - for letter in string: - if letter == "m": - letter = "10e-3" - elif letter == "u": - letter = "10e-6" - else: - letter = letter - newstring = str(newstring) + str(letter) - return newstring - - def convert_time_unit(self, string): - newstring = "" - for letter in string: - if letter == "f": - letter = "10e-15" - elif letter == "p": - letter = "10e-12" - elif letter == "n": - letter = "10e-9" - elif letter == "u": - letter = "10e-6" - elif letter == "m": - letter = "10e-3" - else: - letter = letter - newstring = str(newstring) + str(letter) - return newstring - - def write_simulator(self, sim_file): - sim_file.write("\n") - import tech - time_step = tech.spice["clock_period"] - for model in tech.spice["fet_models"]: - sim_file.write(".inc " + str(model) + "\n") - sim_file.write(".inc stimulus.sp\n") - sim_file.write(".inc temp_pex.sp\n") - sim_file.write(".options post runlvl=6\n") - sim_file.write("\n") - - sim_file.write( - "Xsource DATA[0] ADDR[0] ADDR[1] ADDR[2] ADDR[3] CSb WEb WEb_inv OEb clk vdd vss source\n") - sim_file.write( - "Xsram DATA[0] ADDR[0] ADDR[1] ADDR[2] ADDR[3] CSb WEb OEb clk vdd vss test_sram1\n") - sim_file.write("\n") - - sim_file.write(".MEASURE TRAN vr1 AVG V(DATA[0]) FROM ={0}ns TO ={1}ns\n".format( - 4.5 * tech.spice["clock_period"], 5 * tech.spice["clock_period"])) - sim_file.write(".MEASURE TRAN vr2 AVG V(DATA[0]) FROM ={0}ns TO ={1}ns\n".format( - 9.5 * tech.spice["clock_period"], 10 * tech.spice["clock_period"])) - sim_file.write("\n") - - if OPTS.spice_name in ["hspice","xa"]: - sim_file.write(".probe v(x*.*)\n") - sim_file.write(".tran 0.1ns {0}ns\n".format( - 10 * tech.spice["clock_period"])) - sim_file.write(".end\n") - else: - sim_file.write( - ".meas tran DELAY1.0 TRIG v(clk) VAL=0.5 RISE=6 TARG v(DATA[0]) VAL=0.5 TD=0.5n RISE=1\n") - sim_file.write(".tran 0.1ns {0}ns\n".format( - 10 * tech.spice["clock_period"])) - sim_file.write(".control\n") - sim_file.write("run\n") - #sim_file.write("plot CSb WEb OEb \n") - #sim_file.write("plot clk DATA0 \n") - sim_file.write("quit\n") - sim_file.write(".endc\n") - sim_file.write(".end\n") - sim_file.file.close() - - def write_stimulus(self, sti_file): - import tech - import sp_file - sti_file.write( - ".subckt source DATA[0] ADDR[0] ADDR[1] ADDR[2] ADDR[3] CSb WEb WEb_inv OEb clk vdd vss\n") - - time_step = tech.spice["clock_period"] - - clk = sp_file.PWL(name="clk", port=["clk", "0"]) - for i in range(0, 11): - clk.write_pulse(i * time_step, time_step, "UP") - clk.write_to_sp(sti_file) - - WEB_inv = sp_file.PWL(name="WEb_inv", port=["WEb_inv", "0"]) - WEB = sp_file.PWL(name="WEB", port=["WEb", "0"]) - OEb = sp_file.PWL(name="OEb", port=["OEb", "0"]) - CSb = sp_file.PWL(name="CSb", port=["CSb", "0"]) - - # write - CSb.write_pulse(0.75 * time_step, time_step, "DN") - WEB.write_pulse(0.75 * time_step, time_step, "DN") - WEB_inv.write_pulse(0.75 * time_step, time_step, "UP") - CSb.write_pulse(1.75 * time_step, time_step, "DN") - WEB.write_pulse(1.75 * time_step, time_step, "DN") - WEB_inv.write_pulse(1.75 * time_step, time_step, "UP") - - # read - OEb.write_pulse(3.75 * time_step, time_step, "DN") - CSb.write_pulse(3.75 * time_step, time_step, "DN") - - # write - CSb.write_pulse(5.75 * time_step, time_step, "DN") - WEB.write_pulse(5.75 * time_step, time_step, "DN") - WEB_inv.write_pulse(5.75 * time_step, time_step, "UP") - CSb.write_pulse(6.75 * time_step, time_step, "DN") - WEB.write_pulse(6.75 * time_step, time_step, "DN") - WEB_inv.write_pulse(6.75 * time_step, time_step, "UP") - - # read - OEb.write_pulse(8.75 * time_step, time_step, "DN") - CSb.write_pulse(8.75 * time_step, time_step, "DN") - - CSb.write_to_sp(sti_file) - WEB.write_to_sp(sti_file) - WEB_inv.write_to_sp(sti_file) - OEb.write_to_sp(sti_file) - - sti_file.write("VA[0] A[0] 0 PWL(0n {0} {1}n {0} {2}n 0 {3}n 0 {4}n {0})\n".format(tech.spice["supply_voltage"], 8.875 * tech.spice[ - "clock_period"], 13.875 * tech.spice["clock_period"], 14.5 * tech.spice["clock_period"], 14.501 * tech.spice["clock_period"])) - sti_file.write("VA[1] A[1] 0 PWL(0n {0} {1}n {0} {2}n 0 {3}n 0 {4}n {0})\n".format(tech.spice["supply_voltage"], 8.875 * tech.spice[ - "clock_period"], 13.875 * tech.spice["clock_period"], 14.5 * tech.spice["clock_period"], 14.501 * tech.spice["clock_period"])) - sti_file.write("VA[2] A[2] 0 PWL(0n {0} {1}n {0} {2}n 0 {3}n 0 {4}n {0})\n".format(tech.spice["supply_voltage"], 8.875 * tech.spice[ - "clock_period"], 13.875 * tech.spice["clock_period"], 14.5 * tech.spice["clock_period"], 14.501 * tech.spice["clock_period"])) - sti_file.write("VA[3] A[3] 0 PWL(0n {0} {1}n {0} {2}n 0 {3}n 0 {4}n {0})\n".format(tech.spice["supply_voltage"], 8.875 * tech.spice[ - "clock_period"], 13.875 * tech.spice["clock_period"], 14.5 * tech.spice["clock_period"], 14.501 * tech.spice["clock_period"])) - - sti_file.write( - "xA[0]_buff A[0] ADDR[0]_inv ADDR[0] vdd vss test_buf\n") - sti_file.write( - "xA[1]_buff A[1] ADDR[1]_inv ADDR[1] vdd vss test_buf\n") - sti_file.write( - "xA[2]_buff A[2] ADDR[2]_inv ADDR[2] vdd vss test_buf\n") - sti_file.write( - "xA[3]_buff A[3] ADDR[3]_inv ADDR[3] vdd vss test_buf\n") - - VD_0 = sp_file.PWL(name="VD[0]", port=["D[0]", "0"]) - VD_0.write_pulse(0, 5 * time_step, "S1") - VD_0.write_pulse(5 * time_step, 5 * time_step, "S0") - VD_0.write_to_sp(sti_file) - - sti_file.write( - "xD[0]_buff D[0] DATA[0]_inv DATA[0]s vdd vss test_buf\n") - sti_file.write( - "xD[0]_gate DATA[0]s WEb WEb_inv DATA[0] vdd vss tran_gate\n") - sti_file.write("mp[0]_gate_vdd vdd write_v DATA[0] vdd " + str(tech.spice["pmos"]) + - " w=" + str(2 * tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - sti_file.write("mn[0]_gate_vss vss write_g DATA[0] vss " + str(tech.spice["nmos"]) + - " w=" + str(tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - - Vwrite_v = sp_file.PWL(name="write_v", port=["write_vs", "0"]) - Vwrite_v.write_pulse(0, 0.5 * time_step, "S1") - Vwrite_v.write_pulse(7.5 * time_step, time_step, "DN") - Vwrite_v.write_to_sp(sti_file) - sti_file.write( - "xwrite_v write_vs write_v_inv write_v vdd vss test_buf\n") - - Vwrite_g = sp_file.PWL(name="write_g", port=["write_gs", "0"]) - Vwrite_g.write_pulse(0, 0.5 * time_step, "S0") - Vwrite_g.write_pulse(3 * time_step, time_step, "UP") - Vwrite_g.write_to_sp(sti_file) - sti_file.write( - "xwrite_g write_gs write_g_inv write_g vdd vss test_buf\n") - - sti_file.write("Vdd vdd 0 DC " + - str(tech.spice["supply_voltage"]) + "\n") - sti_file.write("Vvss vss 0 DC 0\n") - sti_file.write(".ENDS source\n") - sti_file.write("\n") - - sti_file.write(".SUBCKT tran_gate in gate gate_inv out vdd vss\n") - sti_file.write("mp0 in gate out vdd " + str(tech.spice["pmos"]) + - " w=" + str(2 * tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - sti_file.write("mn0 in gate_inv out vss " + str(tech.spice["nmos"]) + - " w=" + str(tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - sti_file.write(".ENDS tran_gate\n") - sti_file.write("\n") - - sti_file.write(".SUBCKT test_buf in out_inv out_buf vdd vss\n") - sti_file.write("mpinv1 out_inv in vdd vdd " + str(tech.spice["pmos"]) + - " w=" + str(2 * tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - sti_file.write("mninv1 out_inv in vss vss " + str(tech.spice["nmos"]) + - " w=" + str(tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - sti_file.write("mpinv2 out_buf out_inv vdd vdd " + str(tech.spice["pmos"]) + - " w=" + str(2 * tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - sti_file.write("mninv2 out_buf out_inv vss vss " + str(tech.spice["nmos"]) + - " w=" + str(tech.parameter["min_tx_size"]) + "u" + - " l=" + str(tech.drc["minlength_channel"]) + "u" + - "\n") - sti_file.write(".ENDS test_buf\n") - sti_file.write("\n") - - sti_file.file.close() - - -# run the test from the command line -if __name__ == "__main__": - (OPTS, args) = globals.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 2343da26..1401d834 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -295,11 +295,8 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False): global num_pex_runs num_pex_runs += 1 - #debug.warning("PEX using magic not implemented.") - #return 1 os.chdir(OPTS.openram_temp) - from tech import drc if output == None: output = name + ".pex.netlist" @@ -312,17 +309,11 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False): # pex_fix did run the pex using a script while dev orignial method # use batch mode. # the dev old code using batch mode does not run and is split into functions - #pex_runset = write_batch_pex_rule(gds_name,name,sp_name,output) - pex_runset = write_script_pex_rule(gds_name,name,output) + pex_runset = write_script_pex_rule(gds_name, name, output) errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name) outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name) - # bash mode command from dev branch - #batch_cmd = "{0} -gui -pex {1}pex_runset -batch 2> {2} 1> {3}".format(OPTS.pex_exe, - # OPTS.openram_temp, - # errfile, - # outfile) script_cmd = "{0} 2> {1} 1> {2}".format(pex_runset, errfile, outfile) @@ -334,8 +325,8 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False): pex_nelist = open(output, 'r') s = pex_nelist.read() pex_nelist.close() - s = s.replace('pfet','p') - s = s.replace('nfet','n') + s = s.replace('pfet', 'p') + s = s.replace('nfet', 'n') f = open(output, 'w') f.write(s) f.close() @@ -345,12 +336,13 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False): results = f.readlines() f.close() out_errors = find_error(results) - debug.check(os.path.isfile(output),"Couldn't find PEX extracted output.") + debug.check(os.path.isfile(output), "Couldn't find PEX extracted output.") - correct_port(name,output,sp_name) + correct_port(name, output, sp_name) return out_errors -def write_batch_pex_rule(gds_name,name,sp_name,output): + +def write_batch_pex_rule(gds_name, name, sp_name, output): """ The dev branch old batch mode runset 2. magic can perform extraction with the following: @@ -394,7 +386,8 @@ def write_batch_pex_rule(gds_name,name,sp_name,output): f.close() return file -def write_script_pex_rule(gds_name,cell_name,output): + +def write_script_pex_rule(gds_name, cell_name, output): global OPTS run_file = OPTS.openram_temp + "run_pex.sh" f = open(run_file, "w") @@ -412,23 +405,24 @@ def write_script_pex_rule(gds_name,cell_name,output): pre = "#" else: pre = "" - f.write(pre+"extract\n".format(cell_name)) - f.write(pre+"ext2spice hierarchy off\n") - f.write(pre+"ext2spice format ngspice\n") - f.write(pre+"ext2spice renumber off\n") - f.write(pre+"ext2spice scale off\n") - f.write(pre+"ext2spice blackbox on\n") - f.write(pre+"ext2spice subcircuit top on\n") - f.write(pre+"ext2spice global off\n") - f.write(pre+"ext2spice {}\n".format(cell_name)) + f.write(pre + "extract\n") + f.write(pre + "ext2spice hierarchy off\n") + f.write(pre + "ext2spice format ngspice\n") + f.write(pre + "ext2spice renumber off\n") + f.write(pre + "ext2spice scale off\n") + f.write(pre + "ext2spice blackbox on\n") + f.write(pre + "ext2spice subcircuit top on\n") + f.write(pre + "ext2spice global off\n") + f.write(pre + "ext2spice {}\n".format(cell_name)) f.write("quit -noprompt\n") f.write("eof\n") - f.write("mv {0}.spice {1}\n".format(cell_name,output)) + f.write("mv {0}.spice {1}\n".format(cell_name, output)) f.close() os.system("chmod u+x {}".format(run_file)) return run_file + def find_error(results): # Errors begin with "ERROR:" test = re.compile("ERROR:") @@ -438,6 +432,7 @@ def find_error(results): out_errors = len(stdouterrors) return out_errors + def correct_port(name, output_file_name, ref_file_name): pex_file = open(output_file_name, "r") contents = pex_file.read() @@ -456,9 +451,9 @@ def correct_port(name, output_file_name, ref_file_name): for bank in range(OPTS.num_banks): for bank in range(OPTS.num_banks): row = int(OPTS.num_words / OPTS.words_per_row) - 1 - col = int(OPTS.word_size * OPTS.words_per_row) - 1 - bitcell_list += "bitcell_Q_b{0}_r{1}_c{2} ".format(bank,row,col) - bitcell_list += "bitcell_Q_bar_b{0}_r{1}_c{2} ".format(bank,row,col) + col = int(OPTS.word_size * OPTS.words_per_row) - 1 + bitcell_list += "bitcell_Q_b{0}_r{1}_c{2} ".format(bank, row, col) + bitcell_list += "bitcell_Q_bar_b{0}_r{1}_c{2} ".format(bank, row, col) for col in range(OPTS.word_size * OPTS.words_per_row): for port in range(OPTS.num_r_ports + OPTS.num_w_ports + OPTS.num_rw_ports): bitcell_list += "bl{0}_{1} ".format(bank, col) @@ -484,13 +479,18 @@ def correct_port(name, output_file_name, ref_file_name): # write the new pex file with info in the memory output_file = open(output_file_name, "w") output_file.write(part1) - output_file.write(circuit_title+'\n') + output_file.write(circuit_title + '\n') output_file.write(part2) output_file.close() + def print_drc_stats(): - debug.info(1,"DRC runs: {0}".format(num_drc_runs)) + debug.info(1, "DRC runs: {0}".format(num_drc_runs)) + + def print_lvs_stats(): - debug.info(1,"LVS runs: {0}".format(num_lvs_runs)) + debug.info(1, "LVS runs: {0}".format(num_lvs_runs)) + + def print_pex_stats(): - debug.info(1,"PEX runs: {0}".format(num_pex_runs)) + debug.info(1, "PEX runs: {0}".format(num_pex_runs)) From 1e24b780bb4b13e41a4b686606a624a18c781662 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 2 Oct 2020 13:32:52 -0700 Subject: [PATCH 65/83] Initial pex sram test. --- compiler/characterizer/delay.py | 184 +++++++++++++-------------- compiler/characterizer/functional.py | 2 +- compiler/characterizer/stimuli.py | 65 ++++------ compiler/sram/sram_base.py | 4 +- compiler/tests/testutils.py | 2 + compiler/verify/magic.py | 5 + 6 files changed, 128 insertions(+), 134 deletions(-) diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 11235109..6323a351 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -56,8 +56,14 @@ class delay(simulation): """ Create measurement names. The names themselves currently define the type of measurement """ self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"] - self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power", - "disabled_read0_power", "disabled_read1_power", "disabled_write0_power", "disabled_write1_power"] + self.power_meas_names = ["read0_power", + "read1_power", + "write0_power", + "write1_power", + "disabled_read0_power", + "disabled_read1_power", + "disabled_write0_power", + "disabled_write1_power"] # self.voltage_when_names = ["volt_bl", "volt_br"] # self.bitline_delay_names = ["delay_bl", "delay_br"] @@ -133,18 +139,18 @@ class delay(simulation): """ self.bitline_volt_meas = [] - self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ZERO", + self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ZERO", self.bl_name)) self.bitline_volt_meas[-1].meta_str = sram_op.READ_ZERO - self.bitline_volt_meas.append(voltage_at_measure("v_br_READ_ZERO", + self.bitline_volt_meas.append(voltage_at_measure("v_br_READ_ZERO", self.br_name)) self.bitline_volt_meas[-1].meta_str = sram_op.READ_ZERO - self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ONE", - self.bl_name)) + self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ONE", + self.bl_name)) self.bitline_volt_meas[-1].meta_str = sram_op.READ_ONE - self.bitline_volt_meas.append(voltage_at_measure("v_br_READ_ONE", - self.br_name)) + self.bitline_volt_meas.append(voltage_at_measure("v_br_READ_ONE", + self.br_name)) self.bitline_volt_meas[-1].meta_str = sram_op.READ_ONE return self.bitline_volt_meas @@ -174,16 +180,16 @@ class delay(simulation): self.dout_volt_meas = [] for meas in self.delay_meas: # Output voltage measures - self.dout_volt_meas.append(voltage_at_measure("v_{}".format(meas.name), - meas.targ_name_no_port)) + self.dout_volt_meas.append(voltage_at_measure("v_{}".format(meas.name), + meas.targ_name_no_port)) self.dout_volt_meas[-1].meta_str = meas.meta_str if not OPTS.use_pex: - self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name+"{}", "FALL", "RISE", measure_scale=1e9) + self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name + "{}", "FALL", "RISE", measure_scale=1e9) else: self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name, "FALL", "RISE", measure_scale=1e9) - self.sen_meas.meta_str = sram_op.READ_ZERO + self.sen_meas.meta_str = sram_op.READ_ZERO self.sen_meas.meta_add_delay = True return self.dout_volt_meas + [self.sen_meas] @@ -191,26 +197,26 @@ class delay(simulation): def create_read_bit_measures(self): """ Adds bit measurements for read0 and read1 cycles """ - self.read_bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]} + self.read_bit_meas = {bit_polarity.NONINVERTING: [], bit_polarity.INVERTING: []} meas_cycles = (sram_op.READ_ZERO, sram_op.READ_ONE) for cycle in meas_cycles: meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name) single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data) - for polarity,meas in single_bit_meas.items(): + for polarity, meas in single_bit_meas.items(): meas.meta_str = cycle self.read_bit_meas[polarity].append(meas) # Dictionary values are lists, reduce to a single list of measurements - return [meas for meas_list in self.read_bit_meas.values() for meas in meas_list] + return [meas for meas_list in self.read_bit_meas.values() for meas in meas_list] def create_write_bit_measures(self): """ Adds bit measurements for write0 and write1 cycles """ - self.write_bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]} + self.write_bit_meas = {bit_polarity.NONINVERTING: [], bit_polarity.INVERTING: []} meas_cycles = (sram_op.WRITE_ZERO, sram_op.WRITE_ONE) for cycle in meas_cycles: meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name) single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data) - for polarity,meas in single_bit_meas.items(): + for polarity, meas in single_bit_meas.items(): meas.meta_str = cycle self.write_bit_meas[polarity].append(meas) # Dictionary values are lists, reduce to a single list of measurements @@ -279,12 +285,8 @@ class delay(simulation): # instantiate the sram self.sf.write("\n* Instantiation of the SRAM\n") - if not OPTS.use_pex: - self.stim.inst_model(pins=self.pins, - model_name=self.sram.name) - else: - self.stim.inst_sram_pex(pins=self.pins, - model_name=self.sram.name) + self.stim.inst_model(pins=self.pins, + model_name=self.sram.name) self.sf.write("\n* SRAM output loads\n") for port in self.read_ports: @@ -320,7 +322,6 @@ class delay(simulation): self.gen_data() self.gen_addr() - # generate control signals self.sf.write("\n* Generation of control signals\n") self.gen_control() @@ -382,7 +383,7 @@ class delay(simulation): self.sf.write("\n* Generation of global clock signal\n") for port in self.all_ports: - self.stim.gen_constant(sig_name="CLK{0}".format(port), v_val=0) + self.stim.gen_constant(sig_name="CLK{0}".format(port), v_val=0) self.write_power_measures() @@ -433,7 +434,7 @@ class delay(simulation): # These measurements have there time further delayed to the neg. edge of the clock. if delay_obj.meta_add_delay: - meas_cycle_delay += self.period/2 + meas_cycle_delay += self.period / 2 return (meas_cycle_delay, meas_cycle_delay, self.vdd_voltage, port) @@ -442,7 +443,7 @@ class delay(simulation): # Return value is intended to match the power measure format: t_initial, t_final, port t_initial = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]] - t_final = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]+1] + t_final = self.cycle_times[self.measure_cycles[port][power_obj.meta_str] + 1] return (t_initial, t_final, port) @@ -455,7 +456,7 @@ class delay(simulation): # Measurement occurs slightly into the next period so we know that the value # "stuck" after the end of the period -> current period start + 1.25*period - at_time = meas_cycle+1.25*self.period + at_time = meas_cycle + 1.25 * self.period return (at_time, port) @@ -465,7 +466,7 @@ class delay(simulation): """ # Only checking 0 value reads for now. - t_trig = meas_cycle_delay = self.cycle_times[self.measure_cycles[port][sram_op.READ_ZERO]] + t_trig = self.cycle_times[self.measure_cycles[port][sram_op.READ_ZERO]] return (t_trig, self.vdd_voltage, port) @@ -480,7 +481,6 @@ class delay(simulation): measure_variant_inp_tuple = self.get_measure_variants(port, measure, "read") measure.write_measure(self.stim, measure_variant_inp_tuple) - def write_delay_measures_write_port(self, port): """ Write the measure statements to quantify the power results for a write port. @@ -513,7 +513,6 @@ class delay(simulation): self.sf.write("* Write ports {}\n".format(write_port)) self.write_delay_measures_write_port(write_port) - def write_power_measures(self): """ Write the measure statements to quantify the leakage power only. @@ -523,7 +522,7 @@ class delay(simulation): # add measure statements for power t_initial = self.period - t_final = 2*self.period + t_final = 2 * self.period self.stim.gen_meas_power(meas_name="leakage_power", t_initial=t_initial, t_final=t_final) @@ -543,7 +542,7 @@ class delay(simulation): while True: time_out -= 1 if (time_out <= 0): - debug.error("Timed out, could not find a feasible period.",2) + debug.error("Timed out, could not find a feasible period.", 2) # Write ports are assumed non-critical to timing, so the first available is used self.targ_write_ports = [self.write_ports[0]] @@ -589,7 +588,6 @@ class delay(simulation): feasible_delays[self.read_ports[0]] = self.find_feasible_period_one_port(self.read_ports[0]) previous_period = self.period - # Loops through all the ports checks if the feasible period works. Everything restarts it if does not. # Write ports do not produce delays which is why they are not included here. i = 1 @@ -614,7 +612,7 @@ class delay(simulation): include leakage of all cells. """ - debug.check(self.period > 0, "Target simulation period non-positive") + debug.check(self.period > 0, "Target simulation period non-positive") self.write_delay_stimulus() @@ -630,30 +628,29 @@ class delay(simulation): for port in self.targ_write_ports: if not self.check_bit_measures(self.write_bit_meas, port): - return(False,{}) + return(False, {}) - debug.info(2, "Checking write values for port {}".format(port)) + debug.info(2, "Checking write values for port {}".format(port)) write_port_dict = {} for measure in self.write_lib_meas: write_port_dict[measure.name] = measure.retrieve_measure(port=port) if not check_dict_values_is_float(write_port_dict): - debug.error("Failed to Measure Write Port Values:\n\t\t{0}".format(write_port_dict),1) + debug.error("Failed to Measure Write Port Values:\n\t\t{0}".format(write_port_dict), 1) result[port].update(write_port_dict) - for port in self.targ_read_ports: # First, check that the memory has the right values at the right times if not self.check_bit_measures(self.read_bit_meas, port): - return(False,{}) + return(False, {}) debug.info(2, "Checking read delay values for port {}".format(port)) # Check sen timing, then bitlines, then general measurements. if not self.check_sen_measure(port): - return (False,{}) + return (False, {}) if not self.check_read_debug_measures(port): - return (False,{}) + return (False, {}) # Check timing for read ports. Power is only checked if it was read correctly read_port_dict = {} @@ -661,26 +658,25 @@ class delay(simulation): read_port_dict[measure.name] = measure.retrieve_measure(port=port) if not self.check_valid_delays(read_port_dict): - return (False,{}) + return (False, {}) if not check_dict_values_is_float(read_port_dict): - debug.error("Failed to Measure Read Port Values:\n\t\t{0}".format(read_port_dict),1) + debug.error("Failed to Measure Read Port Values:\n\t\t{0}".format(read_port_dict), 1) result[port].update(read_port_dict) - return (True,result) + return (True, result) def check_sen_measure(self, port): """Checks that the sen occurred within a half-period""" sen_val = self.sen_meas.retrieve_measure(port=port) - debug.info(2,"s_en delay={}ns".format(sen_val)) + debug.info(2, "s_en delay={}ns".format(sen_val)) if self.sen_meas.meta_add_delay: - max_delay = self.period/2 + max_delay = self.period / 2 else: max_delay = self.period return not (type(sen_val) != float or sen_val > max_delay) - def check_read_debug_measures(self, port): """Debug measures that indicate special conditions.""" @@ -694,23 +690,23 @@ class delay(simulation): val = meas.retrieve_measure(port=port) if self.bl_name == meas.targ_name_no_port: bl_vals[meas.meta_str] = val - elif self.br_name == meas.targ_name_no_port: + elif self.br_name == meas.targ_name_no_port: br_vals[meas.meta_str] = val - debug.info(2,"{}={}".format(meas.name,val)) + debug.info(2, "{}={}".format(meas.name, val)) dout_success = True bl_success = False for meas in self.dout_volt_meas: val = meas.retrieve_measure(port=port) - debug.info(2,"{}={}".format(meas.name, val)) - debug.check(type(val)==float, "Error retrieving numeric measurement: {0} {1}".format(meas.name,val)) + debug.info(2, "{}={}".format(meas.name, val)) + debug.check(type(val)==float, "Error retrieving numeric measurement: {0} {1}".format(meas.name, val)) - if meas.meta_str == sram_op.READ_ONE and val < self.vdd_voltage*0.1: + if meas.meta_str == sram_op.READ_ONE and val < self.vdd_voltage * 0.1: dout_success = False debug.info(1, "Debug measurement failed. Value {}V was read on read 1 cycle.".format(val)) bl_success = self.check_bitline_meas(bl_vals[sram_op.READ_ONE], br_vals[sram_op.READ_ONE]) - elif meas.meta_str == sram_op.READ_ZERO and val > self.vdd_voltage*0.9: + elif meas.meta_str == sram_op.READ_ZERO and val > self.vdd_voltage * 0.9: dout_success = False debug.info(1, "Debug measurement failed. Value {}V was read on read 0 cycle.".format(val)) bl_success = self.check_bitline_meas(br_vals[sram_op.READ_ONE], bl_vals[sram_op.READ_ONE]) @@ -718,10 +714,9 @@ class delay(simulation): # If the bitlines have a correct value while the output does not then that is a # sen error. FIXME: there are other checks that can be done to solidfy this conclusion. if not dout_success and bl_success: - debug.error("Sense amp enable timing error. Increase the delay chain through the configuration file.",1) + debug.error("Sense amp enable timing error. Increase the delay chain through the configuration file.", 1) return dout_success - def check_bit_measures(self, bit_measures, port): """ @@ -732,29 +727,29 @@ class delay(simulation): for polarity, meas_list in bit_measures.items(): for meas in meas_list: val = meas.retrieve_measure(port=port) - debug.info(2,"{}={}".format(meas.name, val)) + debug.info(2, "{}={}".format(meas.name, val)) if type(val) != float: continue meas_cycle = meas.meta_str # Loose error conditions. Assume it's not metastable but account for noise during reads. if (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.NONINVERTING) or\ (meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.INVERTING): - success = val < self.vdd_voltage/2 + success = val < self.vdd_voltage / 2 elif (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.INVERTING) or\ (meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.NONINVERTING): - success = val > self.vdd_voltage/2 + success = val > self.vdd_voltage / 2 elif (meas_cycle == sram_op.WRITE_ZERO and polarity == bit_polarity.INVERTING) or\ (meas_cycle == sram_op.WRITE_ONE and polarity == bit_polarity.NONINVERTING): - success = val > self.vdd_voltage/2 + success = val > self.vdd_voltage / 2 elif (meas_cycle == sram_op.WRITE_ONE and polarity == bit_polarity.INVERTING) or\ (meas_cycle == sram_op.WRITE_ZERO and polarity == bit_polarity.NONINVERTING): - success = val < self.vdd_voltage/2 + success = val < self.vdd_voltage / 2 if not success: - debug.info(1,("Wrong value detected on probe bit during read/write cycle. " - "Check writes and control logic for bugs.\n measure={}, op={}, " - "bit_storage={}, V(bit)={}").format(meas.name, meas_cycle.name, polarity.name,val)) + debug.info(1, ("Wrong value detected on probe bit during read/write cycle. " + "Check writes and control logic for bugs.\n measure={}, op={}, " + "bit_storage={}, V(bit)={}").format(meas.name, meas_cycle.name, polarity.name, val)) - return success + return success def check_bitline_meas(self, v_discharged_bl, v_charged_bl): """ @@ -764,11 +759,11 @@ class delay(simulation): # The inputs looks at discharge/charged bitline rather than left or right (bl/br) # Performs two checks, discharging bitline is at least 10% away from vdd and there is a # 10% vdd difference between the bitlines. Both need to fail to be considered a s_en error. - min_dicharge = v_discharged_bl < self.vdd_voltage*0.9 - min_diff = (v_charged_bl - v_discharged_bl) > self.vdd_voltage*0.1 + min_dicharge = v_discharged_bl < self.vdd_voltage * 0.9 + min_diff = (v_charged_bl - v_discharged_bl) > self.vdd_voltage * 0.1 - debug.info(1,"min_dicharge={}, min_diff={}".format(min_dicharge,min_diff)) - return (min_dicharge and min_diff) + debug.info(1, "min_dicharge={}, min_diff={}".format(min_dicharge, min_diff)) + return (min_dicharge and min_diff) def run_power_simulation(self): """ @@ -779,20 +774,20 @@ class delay(simulation): self.write_power_stimulus(trim=False) self.stim.run_sim() leakage_power=parse_spice_list("timing", "leakage_power") - debug.check(leakage_power!="Failed","Could not measure leakage power.") - debug.info(1, "Leakage power of full array is {0} mW".format(leakage_power*1e3)) + debug.check(leakage_power!="Failed", "Could not measure leakage power.") + debug.info(1, "Leakage power of full array is {0} mW".format(leakage_power * 1e3)) # debug # sys.exit(1) self.write_power_stimulus(trim=True) self.stim.run_sim() trim_leakage_power=parse_spice_list("timing", "leakage_power") - debug.check(trim_leakage_power!="Failed","Could not measure leakage power.") - debug.info(1, "Leakage power of trimmed array is {0} mW".format(trim_leakage_power*1e3)) + debug.check(trim_leakage_power!="Failed", "Could not measure leakage power.") + debug.info(1, "Leakage power of trimmed array is {0} mW".format(trim_leakage_power * 1e3)) # For debug, you sometimes want to inspect each simulation. # key=raw_input("press return to continue") - return (leakage_power*1e3, trim_leakage_power*1e3) + return (leakage_power * 1e3, trim_leakage_power * 1e3) def check_valid_delays(self, result_dict): """ Check if the measurements are defined and if they are valid. """ @@ -802,30 +797,31 @@ class delay(simulation): delay_lh = result_dict["delay_lh"] slew_hl = result_dict["slew_hl"] slew_lh = result_dict["slew_lh"] - period_load_slew_str = "period {0} load {1} slew {2}".format(self.period,self.load, self.slew) + period_load_slew_str = "period {0} load {1} slew {2}".format(self.period, self.load, self.slew) # if it failed or the read was longer than a period if type(delay_hl)!=float or type(delay_lh)!=float or type(slew_lh)!=float or type(slew_hl)!=float: delays_str = "delay_hl={0} delay_lh={1}".format(delay_hl, delay_lh) - slews_str = "slew_hl={0} slew_lh={1}".format(slew_hl,slew_lh) - debug.info(2,"Failed simulation (in sec):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str, - delays_str, - slews_str)) + slews_str = "slew_hl={0} slew_lh={1}".format(slew_hl, slew_lh) + debug.info(2, "Failed simulation (in sec):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str, + delays_str, + slews_str)) return False delays_str = "delay_hl={0} delay_lh={1}".format(delay_hl, delay_lh) - slews_str = "slew_hl={0} slew_lh={1}".format(slew_hl,slew_lh) - half_period = self.period/2 # high-to-low delays start at neg. clk edge, so they need to be less than half_period + slews_str = "slew_hl={0} slew_lh={1}".format(slew_hl, slew_lh) + # high-to-low delays start at neg. clk edge, so they need to be less than half_period + half_period = self.period / 2 if abs(delay_hl)>half_period or abs(delay_lh)>self.period or abs(slew_hl)>half_period or abs(slew_lh)>self.period \ or delay_hl<0 or delay_lh<0 or slew_hl<0 or slew_lh<0: - debug.info(2,"UNsuccessful simulation (in ns):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str, - delays_str, - slews_str)) + debug.info(2, "UNsuccessful simulation (in ns):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str, + delays_str, + slews_str)) return False else: - debug.info(2,"Successful simulation (in ns):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str, - delays_str, - slews_str)) + debug.info(2, "Successful simulation (in ns):\n\t\t{0}\n\t\t{1}\n\t\t{2}".format(period_load_slew_str, + delays_str, + slews_str)) return True @@ -844,12 +840,12 @@ class delay(simulation): target_period = self.find_min_period_one_port(feasible_delays, port, lb_period, ub_period, target_period) # The min period of one port becomes the new lower bound. Reset the upper_bound. lb_period = target_period - ub_period = feasible_period + ub_period = feasible_period # Clear the target ports before leaving self.targ_read_ports = [] self.targ_write_ports = [] - return target_period + return target_period def find_min_period_one_port(self, feasible_delays, port, lb_period, ub_period, target_period): """ @@ -870,7 +866,7 @@ class delay(simulation): while True: time_out -= 1 if (time_out <= 0): - debug.error("Timed out, could not converge on minimum period.",2) + debug.error("Timed out, could not converge on minimum period.", 2) self.period = target_period debug.info(1, "MinPeriod Search Port {3}: {0}ns (ub: {1} lb: {2})".format(target_period, @@ -1077,7 +1073,6 @@ class delay(simulation): data_ones = "1" * self.word_size data_zeros = "0" * self.word_size wmask_ones = "1" * self.num_wmasks - wmask_zeroes = "0" * self.num_wmasks if self.t_current == 0: self.add_noop_all_ports("Idle cycle (no positive clock edge)") @@ -1132,7 +1127,6 @@ class delay(simulation): self.add_noop_clock_one_port(read_port) self.measure_cycles[read_port]["disabled_read1"] = len(self.cycle_times) - 1 - # This also ensures we will have a L->H transition on the next read self.add_read("R data 0 address {} to clear dout caps".format(inverse_address), inverse_address, @@ -1173,8 +1167,10 @@ class delay(simulation): # Get any available read/write port in case only a single write or read ports is being characterized. cur_read_port = self.get_available_port(get_read_port=True) cur_write_port = self.get_available_port(get_read_port=False) - debug.check(cur_read_port != None, "Characterizer requires at least 1 read port") - debug.check(cur_write_port != None, "Characterizer requires at least 1 write port") + debug.check(cur_read_port != None, + "Characterizer requires at least 1 read port") + debug.check(cur_write_port != None, + "Characterizer requires at least 1 write port") # Create test cycles for specified target ports. write_pos = 0 diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index 3ecbe48d..44c6d278 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -323,7 +323,7 @@ class functional(simulation): else: expected_value = self.word_size + self.num_spare_cols for i in range(expected_value - len(new_value)): - new_value = "0" + new_value + new_value = "0" + new_value # print("Binary Conversion: {} to {}".format(value, new_value)) return new_value diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index 0b2ecef4..da8e16f0 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -15,7 +15,6 @@ import tech import debug import subprocess import os -import sys import numpy as np from globals import OPTS @@ -40,32 +39,26 @@ class stimuli(): debug.info(2, "Not using spice library") self.device_models = tech.spice["fet_models"][self.process] - self.sram_name = "Xsram" - - def inst_sram(self, pins, inst_name): - """ Function to instatiate an SRAM subckt. """ - - self.sf.write("{} ".format(self.sram_name)) - for pin in self.sram_pins: - self.sf.write("{0} ".format(pin)) - self.sf.write("{0}\n".format(inst_name)) - def inst_model(self, pins, model_name): """ Function to instantiate a generic model with a set of pins """ - self.sf.write("X{0} ".format(model_name)) - for pin in pins: - self.sf.write("{0} ".format(pin)) - self.sf.write("{0}\n".format(model_name)) + + if OPTS.use_pex: + self.inst_pex_model(pins, model_name) + else: + self.sf.write("X{0} ".format(model_name)) + for pin in pins: + self.sf.write("{0} ".format(pin)) + self.sf.write("{0}\n".format(model_name)) - def inst_sram_pex(self, pins, model_name): + def inst_pex_model(self, pins, model_name): self.sf.write("X{0} ".format(model_name)) for pin in pins: self.sf.write("{0} ".format(pin)) for bank in range(OPTS.num_banks): row = int(OPTS.num_words / OPTS.words_per_row) - 1 - col = int(OPTS.word_size * OPTS.words_per_row) - 1 - self.sf.write("bitcell_Q_b{0}_r{1}_c{2} ".format(bank,row,col)) - self.sf.write("bitcell_Q_bar_b{0}_r{1}_c{2} ".format(bank,row,col)) + col = int(OPTS.word_size * OPTS.words_per_row) - 1 + self.sf.write("bitcell_Q_b{0}_r{1}_c{2} ".format(bank, row, col)) + self.sf.write("bitcell_Q_bar_b{0}_r{1}_c{2} ".format(bank, row, col)) # can't add all bitcells to top level due to ngspice max port count of 1005 # for row in range(int(OPTS.num_words / OPTS.words_per_row)): # for col in range(int(OPTS.word_size * OPTS.words_per_row)): @@ -76,7 +69,6 @@ class stimuli(): for port in range(OPTS.num_r_ports + OPTS.num_w_ports + OPTS.num_rw_ports): self.sf.write("bl{0}_{1} ".format(port, col)) self.sf.write("br{0}_{1} ".format(port, col)) - self.sf.write("s_en{0} ".format(bank)) self.sf.write("{0}\n".format(model_name)) @@ -94,14 +86,13 @@ class stimuli(): self.tx_length)) self.sf.write(".ENDS test_inv\n") - - def create_buffer(self, buffer_name, size=[1,3], beta=2.5): + def create_buffer(self, buffer_name, size=[1, 3], beta=2.5): """ Generates buffer for top level signals (only for sim purposes). Size is pair for PMOS, NMOS width multiple. """ - self.sf.write(".SUBCKT test_{2} in out {0} {1}\n".format(self.vdd_name, + self.sf.write(".SUBCKT test_{2} in out {0} {1}\n".format(self.vdd_name, self.gnd_name, buffer_name)) self.sf.write("mpinv1 out_inv in {0} {0} {1} w={2}u l={3}u\n".format(self.vdd_name, @@ -122,8 +113,6 @@ class stimuli(): self.tx_length)) self.sf.write(".ENDS test_{0}\n\n".format(buffer_name)) - - def gen_pulse(self, sig_name, v1, v2, offset, period, t_rise, t_fall): """ Generates a periodic signal with 50% duty cycle and slew rates. Period is measured @@ -140,7 +129,6 @@ class stimuli(): 0.5*period-0.5*t_rise-0.5*t_fall, period)) - def gen_pwl(self, sig_name, clk_times, data_values, period, slew, setup): """ Generate a PWL stimulus given a signal name and data values at each period. @@ -149,18 +137,22 @@ class stimuli(): to the initial value. """ # the initial value is not a clock time - debug.check(len(clk_times)==len(data_values),"Clock and data value lengths don't match. {0} clock values, {1} data values for {2}".format(len(clk_times), len(data_values), sig_name)) + str = "Clock and data value lengths don't match. {0} clock values, {1} data values for {2}" + debug.check(len(clk_times)==len(data_values), + str.format(len(clk_times), + len(data_values), + sig_name)) # shift signal times earlier for setup time - times = np.array(clk_times) - setup*period + times = np.array(clk_times) - setup * period values = np.array(data_values) * self.voltage half_slew = 0.5 * slew self.sf.write("* (time, data): {}\n".format(list(zip(clk_times, data_values)))) self.sf.write("V{0} {0} 0 PWL (0n {1}v ".format(sig_name, values[0])) - for i in range(1,len(times)): - self.sf.write("{0}n {1}v {2}n {3}v ".format(times[i]-half_slew, - values[i-1], - times[i]+half_slew, + for i in range(1, len(times)): + self.sf.write("{0}n {1}v {2}n {3}v ".format(times[i] - half_slew, + values[i - 1], + times[i] + half_slew, values[i])) self.sf.write(")\n") @@ -169,9 +161,9 @@ class stimuli(): self.sf.write("V{0} {0} 0 DC {1}\n".format(sig_name, v_val)) def get_inverse_voltage(self, value): - if value > 0.5*self.voltage: + if value > 0.5 * self.voltage: return 0 - elif value <= 0.5*self.voltage: + elif value <= 0.5 * self.voltage: return self.voltage else: debug.error("Invalid value to get an inverse of: {0}".format(value)) @@ -184,7 +176,6 @@ class stimuli(): else: debug.error("Invalid value to get an inverse of: {0}".format(value)) - def gen_meas_delay(self, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, trig_td, targ_td): """ Creates the .meas statement for the measurement of delay """ measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={4}n TARG v({5}) VAL={6} {7}=1 TD={8}n\n\n" @@ -246,7 +237,7 @@ class stimuli(): timestep = 10 # ps, was 5ps but ngspice was complaining the timestep was too small in certain tests. # UIC is needed for ngspice to converge - self.sf.write(".TRAN {0}p {1}n UIC\n".format(timestep,end_time)) + self.sf.write(".TRAN {0}p {1}n UIC\n".format(timestep, end_time)) self.sf.write(".TEMP {}\n".format(self.temperature)) if OPTS.spice_name == "ngspice": # ngspice sometimes has convergence problems if not using gear method @@ -260,7 +251,7 @@ class stimuli(): # create plots for all signals self.sf.write("* probe is used for hspice/xa, while plot is used in ngspice\n") if OPTS.debug_level>0: - if OPTS.spice_name in ["hspice","xa"]: + if OPTS.spice_name in ["hspice", "xa"]: self.sf.write(".probe V(*)\n") else: self.sf.write(".plot V(*)\n") diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 5f02ce56..351619bf 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -94,7 +94,7 @@ class sram_base(design, verilog, lef): # add pex labels for bitcells for bank_num in range(len(self.bank_insts)): bank = self.bank_insts[bank_num] - pex_data = bank.reverse_transformation_bitcell(bank.mod.bitcell.name) + pex_data = bank.reverse_transformation_bitcell(self.bitcell.name) bank_offset = pex_data[0] # offset bank relative to sram Q_offset = pex_data[1] # offset of storage relative to bank @@ -107,7 +107,7 @@ class sram_base(design, verilog, lef): bl = [] br = [] - storage_layer_name = self.bitcell.get_pin("Q").layer + storage_layer_name = "m1" bitline_layer_name = self.bitcell.get_pin("bl").layer for cell in range(len(bank_offset)): diff --git a/compiler/tests/testutils.py b/compiler/tests/testutils.py index a8da9fb4..9188a4f9 100644 --- a/compiler/tests/testutils.py +++ b/compiler/tests/testutils.py @@ -82,6 +82,8 @@ class openram_test(unittest.TestCase): output = OPTS.openram_temp + a.name + ".pex.netlist" tempspice = "{0}{1}.sp".format(OPTS.openram_temp, a.name) tempgds = "{0}{1}.gds".format(OPTS.openram_temp, a.name) + + a.gds_write(tempgds) import verify result=verify.run_pex(a.name, tempgds, tempspice, output=output, final_verification=False) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 1401d834..ece741cd 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -406,6 +406,10 @@ def write_script_pex_rule(gds_name, cell_name, output): else: pre = "" f.write(pre + "extract\n") + f.write(pre + "ext2sim labels on\n") + f.write(pre + "ext2sim\n") + f.write(pre + "extresist simplify off\n") + f.write(pre + "extresist all\n") f.write(pre + "ext2spice hierarchy off\n") f.write(pre + "ext2spice format ngspice\n") f.write(pre + "ext2spice renumber off\n") @@ -413,6 +417,7 @@ def write_script_pex_rule(gds_name, cell_name, output): f.write(pre + "ext2spice blackbox on\n") f.write(pre + "ext2spice subcircuit top on\n") f.write(pre + "ext2spice global off\n") + f.write(pre + "ext2spice extresist on\n") f.write(pre + "ext2spice {}\n".format(cell_name)) f.write("quit -noprompt\n") f.write("eof\n") From a62b82128c521676a834c9b9a5ea96c0e47fe082 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 2 Oct 2020 13:33:58 -0700 Subject: [PATCH 66/83] Skip riscv func test because too slow --- compiler/tests/50_riscv_func_test.py | 9 +++++---- compiler/tests/50_riscv_phys_test.py | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/tests/50_riscv_func_test.py b/compiler/tests/50_riscv_func_test.py index 74c46bf7..0d9825e6 100755 --- a/compiler/tests/50_riscv_func_test.py +++ b/compiler/tests/50_riscv_func_test.py @@ -8,14 +8,15 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug -#@unittest.skip("SKIPPING 50_riscv_func_test") + +@unittest.skip("SKIPPING 50_riscv_func_test") class riscv_func_test(openram_test): def runTest(self): @@ -34,7 +35,7 @@ class riscv_func_test(openram_test): from importlib import reload import characterizer reload(characterizer) - from characterizer import functional, delay + from characterizer import functional from sram_config import sram_config c = sram_config(word_size=32, write_size=8, @@ -54,7 +55,7 @@ class riscv_func_test(openram_test): corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) f = functional(s.s, tempspice, corner) (fail, error) = f.run() - self.assertTrue(fail,error) + self.assertTrue(fail, error) globals.end_openram() diff --git a/compiler/tests/50_riscv_phys_test.py b/compiler/tests/50_riscv_phys_test.py index 06b9fc6b..724131dd 100755 --- a/compiler/tests/50_riscv_phys_test.py +++ b/compiler/tests/50_riscv_phys_test.py @@ -8,13 +8,14 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + #@unittest.skip("SKIPPING 50_riscv_phys_test") class riscv_phys_test(openram_test): From 1fc404060774223b282d953da1e9877a54c73111 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 2 Oct 2020 14:54:12 -0700 Subject: [PATCH 67/83] Add pand4 and pnand4 --- compiler/pgates/pand4.py | 165 ++++++++++++++ compiler/pgates/pnand3.py | 1 - compiler/pgates/pnand4.py | 372 +++++++++++++++++++++++++++++++ compiler/tests/04_pand2_test.py | 4 +- compiler/tests/04_pand3_test.py | 4 +- compiler/tests/04_pand4_test.py | 39 ++++ compiler/tests/04_pnand4_test.py | 42 ++++ 7 files changed, 622 insertions(+), 5 deletions(-) create mode 100644 compiler/pgates/pand4.py create mode 100644 compiler/pgates/pnand4.py create mode 100755 compiler/tests/04_pand4_test.py create mode 100755 compiler/tests/04_pnand4_test.py diff --git a/compiler/pgates/pand4.py b/compiler/pgates/pand4.py new file mode 100644 index 00000000..54d2890e --- /dev/null +++ b/compiler/pgates/pand4.py @@ -0,0 +1,165 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import debug +from vector import vector +import pgate +from sram_factory import factory + + +class pand4(pgate.pgate): + """ + This is a simple buffer used for driving loads. + """ + def __init__(self, name, size=1, height=None, vertical=False, add_wells=True): + debug.info(1, "Creating pand4 {}".format(name)) + self.add_comment("size: {}".format(size)) + + self.vertical = vertical + self.size = size + + # Creates the netlist and layout + super().__init__(name, height, add_wells) + + def create_netlist(self): + self.add_pins() + self.create_modules() + self.create_insts() + + def create_modules(self): + # Shield the cap, but have at least a stage effort of 4 + self.nand = factory.create(module_type="pnand4", + height=self.height, + add_wells=self.vertical) + + # Add the well tap to the inverter because when stacked + # vertically it is sometimes narrower + self.inv = factory.create(module_type="pdriver", + size_list=[self.size], + height=self.height, + add_wells=self.add_wells) + + self.add_mod(self.nand) + self.add_mod(self.inv) + + def create_layout(self): + if self.vertical: + self.height = 2 * self.nand.height + self.width = max(self.nand.width, self.inv.width) + else: + self.width = self.nand.width + self.inv.width + + self.place_insts() + self.add_wires() + self.add_layout_pins() + self.route_supply_rails() + self.add_boundary() + self.DRC_LVS() + + def add_pins(self): + self.add_pin("A", "INPUT") + self.add_pin("B", "INPUT") + self.add_pin("C", "INPUT") + self.add_pin("D", "INPUT") + self.add_pin("Z", "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def create_insts(self): + self.nand_inst = self.add_inst(name="pand4_nand", + mod=self.nand) + self.connect_inst(["A", "B", "C", "D", "zb_int", "vdd", "gnd"]) + + self.inv_inst = self.add_inst(name="pand4_inv", + mod=self.inv) + self.connect_inst(["zb_int", "Z", "vdd", "gnd"]) + + def place_insts(self): + # Add NAND to the right + self.nand_inst.place(offset=vector(0, 0)) + + if self.vertical: + # Add INV above + self.inv_inst.place(offset=vector(self.inv.width, + 2 * self.nand.height), + mirror="XY") + else: + # Add INV to the right + self.inv_inst.place(offset=vector(self.nand_inst.rx(), 0)) + + def route_supply_rails(self): + """ Add vdd/gnd rails to the top, (middle), and bottom. """ + self.add_layout_pin_rect_center(text="gnd", + layer=self.route_layer, + offset=vector(0.5 * self.width, 0), + width=self.width) + + # Second gnd of the inverter gate + if self.vertical: + self.add_layout_pin_rect_center(text="gnd", + layer=self.route_layer, + offset=vector(0.5 * self.width, self.height), + width=self.width) + + if self.vertical: + # Shared between two gates + y_offset = 0.5 * self.height + else: + y_offset = self.height + self.add_layout_pin_rect_center(text="vdd", + layer=self.route_layer, + offset=vector(0.5 * self.width, y_offset), + width=self.width) + + def add_wires(self): + # nand Z to inv A + z1_pin = self.nand_inst.get_pin("Z") + a2_pin = self.inv_inst.get_pin("A") + if self.vertical: + route_layer = "m2" + self.add_via_stack_center(offset=z1_pin.center(), + from_layer=z1_pin.layer, + to_layer=route_layer) + self.add_zjog(route_layer, + z1_pin.uc(), + a2_pin.bc(), + "V") + self.add_via_stack_center(offset=a2_pin.center(), + from_layer=a2_pin.layer, + to_layer=route_layer) + else: + route_layer = self.route_layer + mid1_point = vector(z1_pin.cx(), a2_pin.cy()) + self.add_path(route_layer, + [z1_pin.center(), mid1_point, a2_pin.center()]) + + def add_layout_pins(self): + pin = self.inv_inst.get_pin("Z") + self.add_layout_pin_rect_center(text="Z", + layer=pin.layer, + offset=pin.center(), + width=pin.width(), + height=pin.height()) + + for pin_name in ["A", "B", "C"]: + pin = self.nand_inst.get_pin(pin_name) + self.add_layout_pin_rect_center(text=pin_name, + layer=pin.layer, + offset=pin.center(), + width=pin.width(), + height=pin.height()) + + def analytical_delay(self, corner, slew, load=0.0): + """ Calculate the analytical delay of DFF-> INV -> INV """ + nand_delay = self.nand.analytical_delay(corner, + slew=slew, + load=self.inv.input_load()) + inv_delay = self.inv.analytical_delay(corner, + slew=nand_delay.slew, + load=load) + return nand_delay + inv_delay + diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index efcbe369..db5a1f28 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -133,7 +133,6 @@ class pnand3(pgate.pgate): # This is the extra space needed to ensure DRC rules # to the active contacts nmos = factory.create(module_type="ptx", tx_type="nmos") - extra_contact_space = max(-nmos.get_pin("D").by(), 0) def create_ptx(self): """ diff --git a/compiler/pgates/pnand4.py b/compiler/pgates/pnand4.py new file mode 100644 index 00000000..ba909dce --- /dev/null +++ b/compiler/pgates/pnand4.py @@ -0,0 +1,372 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import pgate +import debug +from tech import drc, parameter, spice +from vector import vector +import logical_effort +from sram_factory import factory +from globals import OPTS +import contact + + +class pnand4(pgate.pgate): + """ + This module generates gds of a parametrically sized 4-input nand. + This model use ptx to generate a 4-input nand within a cetrain height. + """ + def __init__(self, name, size=1, height=None, add_wells=True): + """ Creates a cell for a simple 3 input nand """ + + debug.info(2, + "creating pnand4 structure {0} with size of {1}".format(name, + size)) + self.add_comment("size: {}".format(size)) + + # We have trouble pitch matching a 3x sizes to the bitcell... + # If we relax this, we could size this better. + self.size = size + self.nmos_size = 2 * size + self.pmos_size = parameter["beta"] * size + self.nmos_width = self.nmos_size * drc("minwidth_tx") + self.pmos_width = self.pmos_size * drc("minwidth_tx") + + # FIXME: Allow these to be sized + debug.check(size == 1, + "Size 1 pnand4 is only supported now.") + self.tx_mults = 1 + + if OPTS.tech_name == "sky130": + self.nmos_width = self.nearest_bin("nmos", self.nmos_width) + self.pmos_width = self.nearest_bin("pmos", self.pmos_width) + + # Creates the netlist and layout + super().__init__(name, height, add_wells) + + def add_pins(self): + """ Adds pins for spice netlist """ + pin_list = ["A", "B", "C", "D", "Z", "vdd", "gnd"] + dir_list = ["INPUT", "INPUT", "INPUT", "INPUT", "OUTPUT", "POWER", "GROUND"] + self.add_pin_list(pin_list, dir_list) + + def create_netlist(self): + self.add_pins() + self.add_ptx() + self.create_ptx() + + def create_layout(self): + """ Calls all functions related to the generation of the layout """ + + self.setup_layout_constants() + self.place_ptx() + if self.add_wells: + self.add_well_contacts() + self.route_inputs() + self.route_output() + self.determine_width() + self.route_supply_rails() + self.connect_rails() + self.extend_wells() + self.add_boundary() + + def add_ptx(self): + """ Create the PMOS and NMOS transistors. """ + self.nmos_center = factory.create(module_type="ptx", + width=self.nmos_width, + mults=self.tx_mults, + tx_type="nmos", + add_source_contact="active", + add_drain_contact="active") + self.add_mod(self.nmos_center) + + self.nmos_right = factory.create(module_type="ptx", + width=self.nmos_width, + mults=self.tx_mults, + tx_type="nmos", + add_source_contact="active", + add_drain_contact=self.route_layer) + self.add_mod(self.nmos_right) + + self.nmos_left = factory.create(module_type="ptx", + width=self.nmos_width, + mults=self.tx_mults, + tx_type="nmos", + add_source_contact=self.route_layer, + add_drain_contact="active") + self.add_mod(self.nmos_left) + + self.pmos_left = factory.create(module_type="ptx", + width=self.pmos_width, + mults=self.tx_mults, + tx_type="pmos", + add_source_contact=self.route_layer, + add_drain_contact=self.route_layer) + self.add_mod(self.pmos_left) + + self.pmos_center = factory.create(module_type="ptx", + width=self.pmos_width, + mults=self.tx_mults, + tx_type="pmos", + add_source_contact=self.route_layer, + add_drain_contact=self.route_layer) + self.add_mod(self.pmos_center) + + self.pmos_right = factory.create(module_type="ptx", + width=self.pmos_width, + mults=self.tx_mults, + tx_type="pmos", + add_source_contact=self.route_layer, + add_drain_contact=self.route_layer) + self.add_mod(self.pmos_right) + + def setup_layout_constants(self): + """ Pre-compute some handy layout parameters. """ + + # Compute the overlap of the source and drain pins + self.ptx_offset = self.pmos_left.get_pin("D").center() - self.pmos_left.get_pin("S").center() + + # This is the extra space needed to ensure DRC rules + # to the active contacts + nmos = factory.create(module_type="ptx", tx_type="nmos") + extra_contact_space = max(-nmos.get_pin("D").by(), 0) + + def create_ptx(self): + """ + Create the PMOS and NMOS in the netlist. + """ + + self.pmos1_inst = self.add_inst(name="pnand4_pmos1", + mod=self.pmos_left) + self.connect_inst(["vdd", "A", "Z", "vdd"]) + + self.pmos2_inst = self.add_inst(name="pnand4_pmos2", + mod=self.pmos_center) + self.connect_inst(["Z", "B", "vdd", "vdd"]) + + self.pmos3_inst = self.add_inst(name="pnand4_pmos3", + mod=self.pmos_center) + self.connect_inst(["Z", "C", "vdd", "vdd"]) + + self.pmos4_inst = self.add_inst(name="pnand4_pmos4", + mod=self.pmos_right) + self.connect_inst(["Z", "D", "vdd", "vdd"]) + + self.nmos1_inst = self.add_inst(name="pnand4_nmos1", + mod=self.nmos_left) + self.connect_inst(["Z", "D", "net1", "gnd"]) + + self.nmos2_inst = self.add_inst(name="pnand4_nmos2", + mod=self.nmos_center) + self.connect_inst(["net1", "C", "net2", "gnd"]) + + self.nmos3_inst = self.add_inst(name="pnand4_nmos3", + mod=self.nmos_center) + self.connect_inst(["net2", "B", "net3", "gnd"]) + + self.nmos4_inst = self.add_inst(name="pnand4_nmos4", + mod=self.nmos_right) + self.connect_inst(["net3", "A", "gnd", "gnd"]) + + def place_ptx(self): + """ + Place the PMOS and NMOS in the layout at the upper-most + and lowest position to provide maximum routing in channel + """ + + pmos1_pos = vector(self.pmos_left.active_offset.x, + self.height - self.pmos_left.active_height - self.top_bottom_space) + self.pmos1_inst.place(pmos1_pos) + + pmos2_pos = pmos1_pos + self.ptx_offset + self.pmos2_inst.place(pmos2_pos) + + pmos3_pos = pmos2_pos + self.ptx_offset + self.pmos3_inst.place(pmos3_pos) + + self.pmos4_pos = pmos3_pos + self.ptx_offset + self.pmos4_inst.place(self.pmos4_pos) + + nmos1_pos = vector(self.pmos_left.active_offset.x, + self.top_bottom_space) + self.nmos1_inst.place(nmos1_pos) + + nmos2_pos = nmos1_pos + self.ptx_offset + self.nmos2_inst.place(nmos2_pos) + + nmos3_pos = nmos2_pos + self.ptx_offset + self.nmos3_inst.place(nmos3_pos) + + self.nmos4_pos = nmos3_pos + self.ptx_offset + self.nmos4_inst.place(self.nmos4_pos) + + def add_well_contacts(self): + """ Add n/p well taps to the layout and connect to supplies """ + + self.add_nwell_contact(self.pmos_right, + self.pmos4_pos + vector(self.m1_pitch, 0)) + self.add_pwell_contact(self.nmos_right, + self.nmos4_pos + vector(self.m1_pitch, 0)) + + def connect_rails(self): + """ Connect the nmos and pmos to its respective power rails """ + + self.connect_pin_to_rail(self.nmos1_inst, "S", "gnd") + + self.connect_pin_to_rail(self.pmos1_inst, "S", "vdd") + + self.connect_pin_to_rail(self.pmos2_inst, "D", "vdd") + + self.connect_pin_to_rail(self.pmos4_inst, "D", "vdd") + + def route_inputs(self): + """ Route the A and B and C inputs """ + + # We can use this pitch because the contacts and overlap won't be adjacent + pmos_drain_bottom = self.pmos1_inst.get_pin("D").by() + self.output_yoffset = pmos_drain_bottom - 0.5 * self.route_layer_width - self.route_layer_space + + bottom_pin = self.nmos1_inst.get_pin("D") + # active contact metal to poly contact metal spacing + active_contact_to_poly_contact = bottom_pin.uy() + self.m1_space + 0.5 * contact.poly_contact.second_layer_height + # active diffusion to poly contact spacing + # doesn't use nmos uy because that is calculated using offset + poly height + active_top = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height + active_to_poly_contact = active_top + self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height + active_to_poly_contact2 = active_top + self.poly_contact_to_gate + 0.5 * self.route_layer_width + self.inputA_yoffset = max(active_contact_to_poly_contact, + active_to_poly_contact, + active_to_poly_contact2) + + apin = self.route_input_gate(self.pmos1_inst, + self.nmos1_inst, + self.inputA_yoffset, + "A", + position="left") + + self.inputB_yoffset = self.inputA_yoffset + self.m3_pitch + bpin = self.route_input_gate(self.pmos2_inst, + self.nmos2_inst, + self.inputB_yoffset, + "B", + position="center") + + self.inputC_yoffset = self.inputB_yoffset + self.m3_pitch + cpin = self.route_input_gate(self.pmos3_inst, + self.nmos3_inst, + self.inputC_yoffset, + "C", + position="right") + + self.inputD_yoffset = self.inputC_yoffset + self.m3_pitch + cpin = self.route_input_gate(self.pmos4_inst, + self.nmos4_inst, + self.inputD_yoffset, + "D", + position="right") + + if OPTS.tech_name == "sky130": + self.add_enclosure([apin, bpin, cpin], "npc", drc("npc_enclose_poly")) + + def route_output(self): + """ Route the Z output """ + + # PMOS1 drain + pmos1_pin = self.pmos1_inst.get_pin("D") + # PMOS3 drain + pmos3_pin = self.pmos3_inst.get_pin("D") + # NMOS3 drain + nmos4_pin = self.nmos4_inst.get_pin("D") + + out_offset = vector(nmos4_pin.cx() + self.route_layer_pitch, + self.output_yoffset) + + # Go up to metal2 for ease on all output pins + # self.add_via_center(layers=self.m1_stack, + # offset=pmos1_pin.center(), + # directions=("V", "V")) + # self.add_via_center(layers=self.m1_stack, + # offset=pmos3_pin.center(), + # directions=("V", "V")) + # self.add_via_center(layers=self.m1_stack, + # offset=nmos3_pin.center(), + # directions=("V", "V")) + + # # Route in the A input track (top track) + # mid_offset = vector(nmos3_pin.center().x, self.inputA_yoffset) + # self.add_path("m1", [pmos1_pin.center(), mid_offset, nmos3_pin.uc()]) + + # This extends the output to the edge of the cell + # self.add_via_center(layers=self.m1_stack, + # offset=mid_offset) + + top_left_pin_offset = pmos1_pin.center() + top_right_pin_offset = pmos3_pin.center() + bottom_pin_offset = nmos4_pin.center() + + # PMOS1 to output + self.add_path(self.route_layer, [top_left_pin_offset, + vector(top_left_pin_offset.x, out_offset.y), + out_offset]) + # PMOS4 to output + self.add_path(self.route_layer, [top_right_pin_offset, + vector(top_right_pin_offset.x, out_offset.y), + out_offset]) + # NMOS4 to output + mid2_offset = vector(out_offset.x, bottom_pin_offset.y) + self.add_path(self.route_layer, + [bottom_pin_offset, mid2_offset], + width=nmos4_pin.height()) + mid3_offset = vector(out_offset.x, nmos4_pin.by()) + self.add_path(self.route_layer, [mid3_offset, out_offset]) + + self.add_layout_pin_rect_center(text="Z", + layer=self.route_layer, + offset=out_offset) + + def analytical_power(self, corner, load): + """Returns dynamic and leakage power. Results in nW""" + c_eff = self.calculate_effective_capacitance(load) + freq = spice["default_event_frequency"] + power_dyn = self.calc_dynamic_power(corner, c_eff, freq) + power_leak = spice["nand4_leakage"] + + total_power = self.return_power(power_dyn, power_leak) + return total_power + + def calculate_effective_capacitance(self, load): + """Computes effective capacitance. Results in fF""" + c_load = load + # In fF + c_para = spice["min_tx_drain_c"] * (self.nmos_size / parameter["min_tx_size"]) + transition_prob = 0.1094 + return transition_prob * (c_load + c_para) + + def input_load(self): + """Return the relative input capacitance of a single input""" + return self.nmos_size + self.pmos_size + + def get_stage_effort(self, cout, inp_is_rise=True): + """ + Returns an object representing the parameters for delay in tau units. + Optional is_rise refers to the input direction rise/fall. + Input inverted by this stage. + """ + parasitic_delay = 3 + return logical_effort.logical_effort(self.name, + self.size, + self.input_load(), + cout, + parasitic_delay, + not inp_is_rise) + + def build_graph(self, graph, inst_name, port_nets): + """ + Adds edges based on inputs/outputs. + Overrides base class function. + """ + self.add_graph_edges(graph, port_nets) diff --git a/compiler/tests/04_pand2_test.py b/compiler/tests/04_pand2_test.py index f7e5f304..077c180e 100755 --- a/compiler/tests/04_pand2_test.py +++ b/compiler/tests/04_pand2_test.py @@ -8,13 +8,13 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS -from sram_factory import factory import debug + class pand2_test(openram_test): def runTest(self): diff --git a/compiler/tests/04_pand3_test.py b/compiler/tests/04_pand3_test.py index e58f1ee9..4817601e 100755 --- a/compiler/tests/04_pand3_test.py +++ b/compiler/tests/04_pand3_test.py @@ -8,13 +8,13 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS -from sram_factory import factory import debug + class pand3_test(openram_test): def runTest(self): diff --git a/compiler/tests/04_pand4_test.py b/compiler/tests/04_pand4_test.py new file mode 100755 index 00000000..f7dd329d --- /dev/null +++ b/compiler/tests/04_pand4_test.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +import debug + + +class pand4_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + global verify + import verify + + import pand4 + + debug.info(2, "Testing pand4 gate 4x") + a = pand4.pand4(name="pand4x4", size=4) + self.local_check(a) + + globals.end_openram() + +# instantiate a copdsay of the class to actually run the test +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_pnand4_test.py b/compiler/tests/04_pnand4_test.py new file mode 100755 index 00000000..d2c64a5b --- /dev/null +++ b/compiler/tests/04_pnand4_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class pnand4_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + debug.info(2, "Checking 4-input nand gate") + tx = factory.create(module_type="pnand4", size=1) + self.local_check(tx) + + # debug.info(2, "Checking 3-input nand gate") + # tx = factory.create(module_type="pnand3", size=1, add_wells=False) + # # Only DRC because well contacts will fail LVS + # self.local_drc_check(tx) + + globals.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From 64cc620440e656323f98bf7738d136b00c8c73ca Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 2 Oct 2020 14:55:10 -0700 Subject: [PATCH 68/83] Add sram pex test --- compiler/tests/26_sram_pex_test.py | 58 ++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100755 compiler/tests/26_sram_pex_test.py diff --git a/compiler/tests/26_sram_pex_test.py b/compiler/tests/26_sram_pex_test.py new file mode 100755 index 00000000..7736e379 --- /dev/null +++ b/compiler/tests/26_sram_pex_test.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class sram_pex_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + OPTS.analytical_delay = False + OPTS.use_pex = True + + # This is a hack to reload the characterizer __init__ with the spice version + from importlib import reload + import characterizer + reload(characterizer) + from characterizer import functional + from sram_config import sram_config + c = sram_config(word_size=4, + num_words=32, + num_banks=1) + c.words_per_row=2 + c.recompute_sizes() + debug.info(1, "Functional test for sram with " + "{} bit words, {} words, {} words per row, {} banks".format(c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) + s = factory.create(module_type="sram", sram_config=c) + tempspice = self.run_pex(s) + + corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) + f = functional(s.s, tempspice, corner) + (fail, error) = f.run() + self.assertTrue(fail, error) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From f8146e3f699537516eae7981876bab7a1c422777 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 2 Oct 2020 15:52:09 -0700 Subject: [PATCH 69/83] Add decoder4x16 --- compiler/modules/hierarchical_predecode.py | 11 ++++++++--- compiler/modules/hierarchical_predecode4x16.py | 16 ++++++++-------- compiler/pgates/pand4.py | 2 +- .../tests/06_hierarchical_predecode4x16_test.py | 5 +++-- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index 9c34735d..504b3771 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -44,7 +44,7 @@ class hierarchical_predecode(design.design): def add_modules(self): """ Add the INV and AND gate modules """ - debug.check(self.number_of_inputs < 4, + debug.check(self.number_of_inputs <= 4, "Invalid number of predecode inputs: {}".format(self.number_of_inputs)) if self.column_decoder: @@ -203,6 +203,7 @@ class hierarchical_predecode(design.design): pin = top_and_gate.get_pin("D") else: debug.error("Too many inputs for predecoder.", -1) + y_offset = pin.cy() in_pin = "in_{}".format(num) a_pin = "A_{}".format(num) @@ -283,10 +284,14 @@ class hierarchical_predecode(design.design): if self.number_of_inputs == 2: gate_lst = ["A", "B"] - else: + elif self.number_of_inputs == 3: gate_lst = ["A", "B", "C"] + elif self.number_of_inputs == 4: + gate_lst = ["A", "B", "C", "D"] + else: + debug.error("Invalid number of nand inputs for decode", -1) - # this will connect pins A,B or A,B,C + # this will connect pins A,B or A,B,C or A,B,C,D for rail_pin, gate_pin in zip(index_lst, gate_lst): pin = self.and_inst[k].get_pin(gate_pin) pin_pos = pin.center() diff --git a/compiler/modules/hierarchical_predecode4x16.py b/compiler/modules/hierarchical_predecode4x16.py index 3b423fde..93dbc4ea 100644 --- a/compiler/modules/hierarchical_predecode4x16.py +++ b/compiler/modules/hierarchical_predecode4x16.py @@ -32,14 +32,14 @@ class hierarchical_predecode4x16(hierarchical_predecode): ["in_0", "inbar_1", "in_2", "inbar_3", "out_5", "vdd", "gnd"], ["inbar_0", "in_1", "in_2", "inbar_3", "out_6", "vdd", "gnd"], ["in_0", "in_1", "in_2", "inbar_3", "out_7", "vdd", "gnd"], - ["inbar_0", "inbar_1", "inbar_2", "in_3", "out_0", "vdd", "gnd"], - ["in_0", "inbar_1", "inbar_2", "in_3", "out_1", "vdd", "gnd"], - ["inbar_0", "in_1", "inbar_2", "in_3", "out_2", "vdd", "gnd"], - ["in_0", "in_1", "inbar_2", "in_3", "out_3", "vdd", "gnd"], - ["inbar_0", "inbar_1", "in_2", "in_3", "out_4", "vdd", "gnd"], - ["in_0", "inbar_1", "in_2", "in_3", "out_5", "vdd", "gnd"], - ["inbar_0", "in_1", "in_2", "in_3", "out_6", "vdd", "gnd"], - ["in_0", "in_1", "in_2", "in_3", "out_7", "vdd", "gnd"] ] + ["inbar_0", "inbar_1", "inbar_2", "in_3", "out_8", "vdd", "gnd"], + ["in_0", "inbar_1", "inbar_2", "in_3", "out_9", "vdd", "gnd"], + ["inbar_0", "in_1", "inbar_2", "in_3", "out_10", "vdd", "gnd"], + ["in_0", "in_1", "inbar_2", "in_3", "out_11", "vdd", "gnd"], + ["inbar_0", "inbar_1", "in_2", "in_3", "out_12", "vdd", "gnd"], + ["in_0", "inbar_1", "in_2", "in_3", "out_13", "vdd", "gnd"], + ["inbar_0", "in_1", "in_2", "in_3", "out_14", "vdd", "gnd"], + ["in_0", "in_1", "in_2", "in_3", "out_15", "vdd", "gnd"] ] self.create_and_array(connections) diff --git a/compiler/pgates/pand4.py b/compiler/pgates/pand4.py index 54d2890e..021ccf6c 100644 --- a/compiler/pgates/pand4.py +++ b/compiler/pgates/pand4.py @@ -145,7 +145,7 @@ class pand4(pgate.pgate): width=pin.width(), height=pin.height()) - for pin_name in ["A", "B", "C"]: + for pin_name in ["A", "B", "C", "D"]: pin = self.nand_inst.get_pin(pin_name) self.add_layout_pin_rect_center(text=pin_name, layer=pin.layer, diff --git a/compiler/tests/06_hierarchical_predecode4x16_test.py b/compiler/tests/06_hierarchical_predecode4x16_test.py index b4ebda38..7ded6144 100755 --- a/compiler/tests/06_hierarchical_predecode4x16_test.py +++ b/compiler/tests/06_hierarchical_predecode4x16_test.py @@ -8,14 +8,15 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug -@unittest.skip("SKIPPING hierarchical_predecode4x16_test") + +# @unittest.skip("SKIPPING hierarchical_predecode4x16_test") class hierarchical_predecode4x16_test(openram_test): def runTest(self): From c06b02e6fcf9a89257885c498b8e8fb981864608 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 5 Oct 2020 08:56:51 -0700 Subject: [PATCH 70/83] Rename single_level_column_mux to just column_mux --- ...el_column_mux_array.py => column_mux_array.py} | 4 ++-- compiler/options.py | 4 ++-- .../{single_level_column_mux.py => column_mux.py} | 5 ++--- compiler/tests/04_and4_dec_test.py | 4 ++-- ...rw_1r_test.py => 04_column_mux_1rw_1r_test.py} | 8 ++++---- ...ell_test.py => 04_column_mux_pbitcell_test.py} | 9 ++++----- ...l_column_mux_test.py => 04_column_mux_test.py} | 6 +++--- ...test.py => 07_column_mux_array_1rw_1r_test.py} | 15 ++++++++------- ...st.py => 07_column_mux_array_pbitcell_test.py} | 14 +++++++------- ..._array_test.py => 07_column_mux_array_test.py} | 9 +++++---- 10 files changed, 39 insertions(+), 39 deletions(-) rename compiler/modules/{single_level_column_mux_array.py => column_mux_array.py} (98%) rename compiler/pgates/{single_level_column_mux.py => column_mux.py} (98%) rename compiler/tests/{04_single_level_column_mux_1rw_1r_test.py => 04_column_mux_1rw_1r_test.py} (79%) rename compiler/tests/{04_single_level_column_mux_pbitcell_test.py => 04_column_mux_pbitcell_test.py} (79%) rename compiler/tests/{04_single_level_column_mux_test.py => 04_column_mux_test.py} (87%) rename compiler/tests/{07_single_level_column_mux_array_1rw_1r_test.py => 07_column_mux_array_1rw_1r_test.py} (65%) rename compiler/tests/{07_single_level_column_mux_array_pbitcell_test.py => 07_column_mux_array_pbitcell_test.py} (69%) rename compiler/tests/{07_single_level_column_mux_array_test.py => 07_column_mux_array_test.py} (77%) diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/column_mux_array.py similarity index 98% rename from compiler/modules/single_level_column_mux_array.py rename to compiler/modules/column_mux_array.py index 1be0b378..87e750cf 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/column_mux_array.py @@ -14,7 +14,7 @@ from globals import OPTS from tech import cell_properties -class single_level_column_mux_array(design.design): +class column_mux_array(design.design): """ Dynamically generated column mux array. Array of column mux to read the bitlines through the 6T. @@ -89,7 +89,7 @@ class single_level_column_mux_array(design.design): self.add_pin("gnd") def add_modules(self): - self.mux = factory.create(module_type="single_level_column_mux", + self.mux = factory.create(module_type="column_mux", bitcell_bl=self.bitcell_bl, bitcell_br=self.bitcell_br) self.add_mod(self.mux) diff --git a/compiler/options.py b/compiler/options.py index b9be3999..7f86a64f 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -143,7 +143,7 @@ class options(optparse.Values): bitcell_array = "bitcell_array" bitcell = "bitcell" buf_dec = "pbuf" - column_mux_array = "single_level_column_mux_array" + column_mux_array = "column_mux_array" control_logic = "control_logic" decoder = "hierarchical_decoder" delay_chain = "delay_chain" @@ -152,7 +152,7 @@ class options(optparse.Values): inv_dec = "pinv" nand2_dec = "pnand2" nand3_dec = "pnand3" - nand4_dec = "pnand4" # Not available right now + nand4_dec = "pnand4" precharge_array = "precharge_array" ptx = "ptx" replica_bitline = "replica_bitline" diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/column_mux.py similarity index 98% rename from compiler/pgates/single_level_column_mux.py rename to compiler/pgates/column_mux.py index 4873e6fc..20616115 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/column_mux.py @@ -10,14 +10,13 @@ import debug from tech import drc, layer from vector import vector from sram_factory import factory -import logical_effort from globals import OPTS -class single_level_column_mux(pgate.pgate): +class column_mux(pgate.pgate): """ This module implements the columnmux bitline cell used in the design. - Creates a single columnmux cell with the given integer size relative + Creates a single column mux cell with the given integer size relative to minimum size. Default is 8x. Per Samira and Hodges-Jackson book: Column-mux transistors driven by the decoder must be sized for optimal speed diff --git a/compiler/tests/04_and4_dec_test.py b/compiler/tests/04_and4_dec_test.py index ffd7788a..aa163160 100755 --- a/compiler/tests/04_and4_dec_test.py +++ b/compiler/tests/04_and4_dec_test.py @@ -8,7 +8,7 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS @@ -16,7 +16,7 @@ from sram_factory import factory import debug -@unittest.skip("SKIPPING 04_and4_dec_test") +# @unittest.skip("SKIPPING 04_and4_dec_test") class and4_dec_test(openram_test): def runTest(self): diff --git a/compiler/tests/04_single_level_column_mux_1rw_1r_test.py b/compiler/tests/04_column_mux_1rw_1r_test.py similarity index 79% rename from compiler/tests/04_single_level_column_mux_1rw_1r_test.py rename to compiler/tests/04_column_mux_1rw_1r_test.py index a7e79e9b..7825e081 100755 --- a/compiler/tests/04_single_level_column_mux_1rw_1r_test.py +++ b/compiler/tests/04_column_mux_1rw_1r_test.py @@ -8,7 +8,7 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS @@ -16,7 +16,7 @@ from sram_factory import factory import debug -class single_level_column_mux_1rw_1r_test(openram_test): +class column_mux_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -28,11 +28,11 @@ class single_level_column_mux_1rw_1r_test(openram_test): globals.setup_bitcell() debug.info(2, "Checking column mux port 0") - tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0") + tx = factory.create(module_type="column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0") self.local_check(tx) debug.info(2, "Checking column mux port 1") - tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl1", bitcell_br="br1") + tx = factory.create(module_type="column_mux", tx_size=8, bitcell_bl="bl1", bitcell_br="br1") self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_single_level_column_mux_pbitcell_test.py b/compiler/tests/04_column_mux_pbitcell_test.py similarity index 79% rename from compiler/tests/04_single_level_column_mux_pbitcell_test.py rename to compiler/tests/04_column_mux_pbitcell_test.py index 18ab631f..a7a93403 100755 --- a/compiler/tests/04_single_level_column_mux_pbitcell_test.py +++ b/compiler/tests/04_column_mux_pbitcell_test.py @@ -8,16 +8,15 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug -#@unittest.skip("SKIPPING 04_driver_test") -class single_level_column_mux_pbitcell_test(openram_test): +class column_mux_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -31,12 +30,12 @@ class single_level_column_mux_pbitcell_test(openram_test): factory.reset() debug.info(2, "Checking column mux for pbitcell (innermost connections)") - tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0") + tx = factory.create(module_type="column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0") self.local_check(tx) factory.reset() debug.info(2, "Checking column mux for pbitcell (outermost connections)") - tx = factory.create(module_type="single_level_column_mux",tx_size=8, bitcell_bl="bl2", bitcell_br="br2") + tx = factory.create(module_type="column_mux",tx_size=8, bitcell_bl="bl2", bitcell_br="br2") self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_single_level_column_mux_test.py b/compiler/tests/04_column_mux_test.py similarity index 87% rename from compiler/tests/04_single_level_column_mux_test.py rename to compiler/tests/04_column_mux_test.py index 20dfe968..a10603ee 100755 --- a/compiler/tests/04_single_level_column_mux_test.py +++ b/compiler/tests/04_column_mux_test.py @@ -8,7 +8,7 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS @@ -16,7 +16,7 @@ from sram_factory import factory import debug -class single_level_column_mux_test(openram_test): +class column_mux_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -24,7 +24,7 @@ class single_level_column_mux_test(openram_test): # check single level column mux in single port debug.info(2, "Checking column mux") - tx = factory.create(module_type="single_level_column_mux", tx_size=8) + tx = factory.create(module_type="column_mux", tx_size=8) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/07_single_level_column_mux_array_1rw_1r_test.py b/compiler/tests/07_column_mux_array_1rw_1r_test.py similarity index 65% rename from compiler/tests/07_single_level_column_mux_array_1rw_1r_test.py rename to compiler/tests/07_column_mux_array_1rw_1r_test.py index 209133aa..10c96092 100755 --- a/compiler/tests/07_single_level_column_mux_array_1rw_1r_test.py +++ b/compiler/tests/07_column_mux_array_1rw_1r_test.py @@ -14,7 +14,8 @@ from globals import OPTS from sram_factory import factory import debug -class single_level_column_mux_test(openram_test): + +class column_mux_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -26,27 +27,27 @@ class single_level_column_mux_test(openram_test): globals.setup_bitcell() debug.info(1, "Testing sample for 2-way column_mux_array port 0") - a = factory.create(module_type="single_level_column_mux_array", columns=8, word_size=4, bitcell_bl="bl0", bitcell_br="br0") + a = factory.create(module_type="column_mux_array", columns=8, word_size=4, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 2-way column_mux_array port 1") - a = factory.create(module_type="single_level_column_mux_array", columns=8, word_size=4, bitcell_bl="bl1", bitcell_br="br1") + a = factory.create(module_type="column_mux_array", columns=8, word_size=4, bitcell_bl="bl1", bitcell_br="br1") self.local_check(a) debug.info(1, "Testing sample for 4-way column_mux_array port 0") - a = factory.create(module_type="single_level_column_mux_array", columns=8, word_size=2, bitcell_bl="bl0", bitcell_br="br0") + a = factory.create(module_type="column_mux_array", columns=8, word_size=2, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 4-way column_mux_array port 1") - a = factory.create(module_type="single_level_column_mux_array", columns=8, word_size=2, bitcell_bl="bl1", bitcell_br="br1") + a = factory.create(module_type="column_mux_array", columns=8, word_size=2, bitcell_bl="bl1", bitcell_br="br1") self.local_check(a) debug.info(1, "Testing sample for 8-way column_mux_array port 0") - a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=2, bitcell_bl="bl0", bitcell_br="br0") + a = factory.create(module_type="column_mux_array", columns=16, word_size=2, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 8-way column_mux_array port 1") - a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=2, bitcell_bl="bl1", bitcell_br="br1") + a = factory.create(module_type="column_mux_array", columns=16, word_size=2, bitcell_bl="bl1", bitcell_br="br1") self.local_check(a) globals.end_openram() diff --git a/compiler/tests/07_single_level_column_mux_array_pbitcell_test.py b/compiler/tests/07_column_mux_array_pbitcell_test.py similarity index 69% rename from compiler/tests/07_single_level_column_mux_array_pbitcell_test.py rename to compiler/tests/07_column_mux_array_pbitcell_test.py index 663ff075..0a089bb9 100755 --- a/compiler/tests/07_single_level_column_mux_array_pbitcell_test.py +++ b/compiler/tests/07_column_mux_array_pbitcell_test.py @@ -7,19 +7,19 @@ # All rights reserved. # from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug -class single_level_column_mux_pbitcell_test(openram_test): + +class column_mux_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - import single_level_column_mux_array # check single level column mux array in multi-port OPTS.bitcell = "pbitcell" @@ -29,19 +29,19 @@ class single_level_column_mux_pbitcell_test(openram_test): factory.reset() debug.info(1, "Testing sample for 2-way column_mux_array in multi-port") - a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0") + a = factory.create(module_type="column_mux_array", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 4-way column_mux_array in multi-port") - a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0") + a = factory.create(module_type="column_mux_array", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)") - a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0") + a = factory.create(module_type="column_mux_array", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)") - a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2", column_offset=3) + a = factory.create(module_type="column_mux_array", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2", column_offset=3) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/07_single_level_column_mux_array_test.py b/compiler/tests/07_column_mux_array_test.py similarity index 77% rename from compiler/tests/07_single_level_column_mux_array_test.py rename to compiler/tests/07_column_mux_array_test.py index c0476a4f..f32c2773 100755 --- a/compiler/tests/07_single_level_column_mux_array_test.py +++ b/compiler/tests/07_column_mux_array_test.py @@ -14,22 +14,23 @@ from globals import OPTS from sram_factory import factory import debug -class single_level_column_mux_test(openram_test): + +class column_mux_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) debug.info(1, "Testing sample for 2-way column_mux_array") - a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8) + a = factory.create(module_type="column_mux_array", columns=16, word_size=8) self.local_check(a) debug.info(1, "Testing sample for 4-way column_mux_array") - a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=4) + a = factory.create(module_type="column_mux_array", columns=16, word_size=4) self.local_check(a) debug.info(1, "Testing sample for 8-way column_mux_array") - a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4) + a = factory.create(module_type="column_mux_array", columns=32, word_size=4) self.local_check(a) globals.end_openram() From 4a58f09c1cdedb4220214aac9d964e3dbd352182 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 5 Oct 2020 10:52:56 -0700 Subject: [PATCH 71/83] Use 4x16 decoder with dual port bitcell in tests. --- compiler/custom/and4_dec.py | 2 +- compiler/modules/hierarchical_decoder.py | 127 +++++++++++++++--- compiler/pgates/pnand4.py | 11 +- compiler/tests/04_pnand4_test.py | 5 - .../tests/06_hierarchical_decoder_test.py | 14 +- 5 files changed, 124 insertions(+), 35 deletions(-) diff --git a/compiler/custom/and4_dec.py b/compiler/custom/and4_dec.py index 9c68f78b..211e4ce4 100644 --- a/compiler/custom/and4_dec.py +++ b/compiler/custom/and4_dec.py @@ -122,7 +122,7 @@ class and4_dec(design.design): width=pin.width(), height=pin.height()) - for pin_name in ["A", "B", "C"]: + for pin_name in ["A", "B", "C", "D"]: pin = self.nand_inst.get_pin(pin_name) self.add_layout_pin_rect_center(text=pin_name, layer=pin.layer, diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 21aa1c89..51a77bc6 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -24,13 +24,14 @@ class hierarchical_decoder(design.design): self.pre2x4_inst = [] self.pre3x8_inst = [] + self.pre4x16_inst = [] b = factory.create(module_type="bitcell") self.cell_height = b.height self.num_outputs = num_outputs self.num_inputs = math.ceil(math.log(self.num_outputs, 2)) - (self.no_of_pre2x4, self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs) + (self.no_of_pre2x4, self.no_of_pre3x8, self.no_of_pre4x16)=self.determine_predecodes(self.num_inputs) self.create_netlist() if not OPTS.netlist_only: @@ -86,25 +87,37 @@ class hierarchical_decoder(design.design): height=self.cell_height) self.add_mod(self.pre3_8) + self.pre4_16 = factory.create(module_type="hierarchical_predecode4x16", + height=self.cell_height) + self.add_mod(self.pre4_16) + def determine_predecodes(self, num_inputs): - """ Determines the number of 2:4 pre-decoder and 3:8 pre-decoder - needed based on the number of inputs """ + """ + Determines the number of 2:4, 3:8 and 4:16 pre-decoders + needed based on the number of inputs + """ if (num_inputs == 2): - return (1, 0) + return (1, 0, 0) elif (num_inputs == 3): - return(0, 1) + return(0, 1, 0) elif (num_inputs == 4): - return(2, 0) + return(2, 0, 0) elif (num_inputs == 5): - return(1, 1) + return(1, 1, 0) elif (num_inputs == 6): - return(3, 0) + return(3, 0, 0) elif (num_inputs == 7): - return(2, 1) + return(2, 1, 0) elif (num_inputs == 8): - return(1, 2) + return(1, 2, 0) elif (num_inputs == 9): - return(0, 3) + return(0, 3, 0) + elif (num_inputs == 10): + return(0, 2, 1) + elif (num_inputs == 11): + return(0, 1, 2) + elif (num_inputs == 12): + return(0, 0, 3) else: debug.error("Invalid number of inputs for hierarchical decoder", -1) @@ -131,12 +144,19 @@ class hierarchical_decoder(design.design): index = index + 1 self.predec_groups.append(lines) + for i in range(self.no_of_pre4x16): + lines = [] + for j in range(16): + lines.append(index) + index = index + 1 + self.predec_groups.append(lines) + def setup_layout_constants(self): """ Calculate the overall dimensions of the hierarchical decoder """ # If we have 4 or fewer rows, the predecoder is the decoder itself if self.num_inputs>=4: - self.total_number_of_predecoder_outputs = 4 * self.no_of_pre2x4 + 8 * self.no_of_pre3x8 + self.total_number_of_predecoder_outputs = 4 * self.no_of_pre2x4 + 8 * self.no_of_pre3x8 + 16 * self.no_of_pre4x16 else: self.total_number_of_predecoder_outputs = 0 debug.error("Not enough rows ({}) for a hierarchical decoder. Non-hierarchical not supported yet.".format(self.num_inputs), @@ -144,17 +164,20 @@ class hierarchical_decoder(design.design): # Calculates height and width of pre-decoder, # FIXME: Update with 4x16 - if self.no_of_pre3x8 > 0 and self.no_of_pre2x4 > 0: - self.predecoder_width = max(self.pre3_8.width, self.pre2_4.width) - elif self.no_of_pre3x8 > 0: - self.predecoder_width = self.pre3_8.width - else: - self.predecoder_width = self.pre2_4.width + self.predecoder_width = 0 + if self.no_of_pre2x4 > 0: + self.predecoder_width = max(self.predecoder_width, self.pre2_4.width) + if self.no_of_pre3x8 > 0: + self.predecoder_width = max(self.predecoder_width, self.pre3_8.width) + if self.no_of_pre4x16 > 0: + self.predecoder_width = max(self.predecoder_width, self.pre4_16.width) # How much space between each predecoder self.predecoder_spacing = 2 * self.and2.height - self.predecoder_height = self.pre2_4.height * self.no_of_pre2x4 + self.pre3_8.height * self.no_of_pre3x8 \ - + (self.no_of_pre2x4 + self.no_of_pre3x8 - 1) * self.predecoder_spacing + self.predecoder_height = self.pre2_4.height * self.no_of_pre2x4 \ + + self.pre3_8.height * self.no_of_pre3x8 \ + + self.pre4_16.height * self.no_of_pre4x16 \ + + (self.no_of_pre2x4 + self.no_of_pre3x8 + self.no_of_pre4x16 - 1) * self.predecoder_spacing # Inputs to cells are on input layer # Outputs from cells are on output layer @@ -192,6 +215,8 @@ class hierarchical_decoder(design.design): min_x = min(min_x, self.pre2x4_inst[0].lx()) if self.no_of_pre3x8 > 0: min_x = min(min_x, self.pre3x8_inst[0].lx()) + if self.no_of_pre4x16 > 0: + min_x = min(min_x, self.pre4x16_inst[0].lx()) input_offset=vector(min_x - self.input_routing_width, 0) input_bus_names = ["addr_{0}".format(i) for i in range(self.num_inputs)] @@ -232,6 +257,20 @@ class hierarchical_decoder(design.design): self.route_input_bus(decoder_offset, input_offset) + for pre_num in range(self.no_of_pre4x16): + for i in range(4): + index = pre_num * 4 + i + self.no_of_pre3x8 * 3 + self.no_of_pre2x4 * 2 + + input_pos = self.input_bus["addr_{}".format(index)].center() + + in_name = "in_{}".format(i) + decoder_pin = self.pre4x16_inst[pre_num].get_pin(in_name) + + decoder_offset = decoder_pin.center() + input_offset = input_pos.scale(1, 0) + decoder_offset.scale(0, 1) + + self.route_input_bus(decoder_offset, input_offset) + def route_input_bus(self, input_offset, output_offset): """ Route a vertical M2 coordinate to another @@ -267,6 +306,9 @@ class hierarchical_decoder(design.design): for i in range(self.no_of_pre3x8): self.create_pre3x8(i) + for i in range(self.no_of_pre4x16): + self.create_pre4x16(i) + def create_pre2x4(self, num): """ Add a 2x4 predecoder to the left of the origin """ @@ -305,6 +347,24 @@ class hierarchical_decoder(design.design): mod=self.pre3_8)) self.connect_inst(pins) + def create_pre4x16(self, num): + """ Add 4x16 predecoder to the left of the origin and above any 3x8 decoders """ + # If we had 2x4 predecodes, those are used as the lower + # decode output bits + in_index_offset = num * 4 + self.no_of_pre3x8 * 3 + self.no_of_pre2x4 * 2 + out_index_offset = num * 16 + self.no_of_pre3x8 * 8 + self.no_of_pre2x4 * 4 + + pins = [] + for input_index in range(4): + pins.append("addr_{0}".format(input_index + in_index_offset)) + for output_index in range(16): + pins.append("out_{0}".format(output_index + out_index_offset)) + pins.extend(["vdd", "gnd"]) + + self.pre4x16_inst.append(self.add_inst(name="pre4x16_{0}".format(num), + mod=self.pre4_16)) + self.connect_inst(pins) + def place_pre_decoder(self): """ Creates pre-decoder and places labels input address [A] """ @@ -314,11 +374,16 @@ class hierarchical_decoder(design.design): for i in range(self.no_of_pre3x8): self.place_pre3x8(i) + for i in range(self.no_of_pre4x16): + self.place_pre4x16(i) + self.predecode_height = 0 if self.no_of_pre2x4 > 0: self.predecode_height = self.pre2x4_inst[-1].uy() if self.no_of_pre3x8 > 0: self.predecode_height = self.pre3x8_inst[-1].uy() + if self.no_of_pre4x16 > 0: + self.predecode_height = self.pre4x16_inst[-1].uy() def place_pre2x4(self, num): """ Place 2x4 predecoder to the left of the origin """ @@ -333,6 +398,14 @@ class hierarchical_decoder(design.design): offset = vector(-self.pre3_8.width, height) self.pre3x8_inst[num].place(offset) + def place_pre4x16(self, num): + """ Place 3x8 predecoder to the left of the origin and above any 2x4 decoders """ + height = self.no_of_pre2x4 * (self.pre2_4.height + self.predecoder_spacing) \ + + self.no_of_pre3x8 * (self.pre3_8.height + self.predecoder_spacing) \ + + num * (self.pre4_16.height + self.predecoder_spacing) + offset = vector(-self.pre4_16.width, height) + self.pre4x16_inst[num].place(offset) + def create_row_decoder(self): """ Create the row-decoder by placing AND2/AND3 and Inverters and add the primary decoder output pins. """ @@ -468,7 +541,17 @@ class hierarchical_decoder(design.design): x_offset = self.pre3x8_inst[pre_num].rx() + self.output_layer_pitch y_offset = self.pre3x8_inst[pre_num].by() + i * self.cell_height self.route_predecode_bus_inputs(predecode_name, pin, x_offset, y_offset) - + + # FIXME: convert to connect_bus + for pre_num in range(self.no_of_pre4x16): + for i in range(16): + predecode_name = "predecode_{}".format(pre_num * 16 + i + self.no_of_pre3x8 * 8 + self.no_of_pre2x4 * 4) + out_name = "out_{}".format(i) + pin = self.pre4x16_inst[pre_num].get_pin(out_name) + x_offset = self.pre4x16_inst[pre_num].rx() + self.output_layer_pitch + y_offset = self.pre4x16_inst[pre_num].by() + i * self.cell_height + self.route_predecode_bus_inputs(predecode_name, pin, x_offset, y_offset) + def route_bus_to_decoder(self): """ Use the self.predec_groups to determine the connections to the decoder AND gates. @@ -559,7 +642,7 @@ class hierarchical_decoder(design.design): start_layer=supply_pin.layer) # Copy the pins from the predecoders - for pre in self.pre2x4_inst + self.pre3x8_inst: + for pre in self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst: for pin_name in ["vdd", "gnd"]: self.copy_layout_pin(pre, pin_name) diff --git a/compiler/pgates/pnand4.py b/compiler/pgates/pnand4.py index ba909dce..5a812799 100644 --- a/compiler/pgates/pnand4.py +++ b/compiler/pgates/pnand4.py @@ -133,7 +133,6 @@ class pnand4(pgate.pgate): # This is the extra space needed to ensure DRC rules # to the active contacts nmos = factory.create(module_type="ptx", tx_type="nmos") - extra_contact_space = max(-nmos.get_pin("D").by(), 0) def create_ptx(self): """ @@ -248,29 +247,29 @@ class pnand4(pgate.pgate): "A", position="left") - self.inputB_yoffset = self.inputA_yoffset + self.m3_pitch + self.inputB_yoffset = self.inputA_yoffset + self.m1_pitch bpin = self.route_input_gate(self.pmos2_inst, self.nmos2_inst, self.inputB_yoffset, "B", position="center") - self.inputC_yoffset = self.inputB_yoffset + self.m3_pitch + self.inputC_yoffset = self.inputB_yoffset + self.m1_pitch cpin = self.route_input_gate(self.pmos3_inst, self.nmos3_inst, self.inputC_yoffset, "C", position="right") - self.inputD_yoffset = self.inputC_yoffset + self.m3_pitch - cpin = self.route_input_gate(self.pmos4_inst, + self.inputD_yoffset = self.inputC_yoffset + self.m1_pitch + dpin = self.route_input_gate(self.pmos4_inst, self.nmos4_inst, self.inputD_yoffset, "D", position="right") if OPTS.tech_name == "sky130": - self.add_enclosure([apin, bpin, cpin], "npc", drc("npc_enclose_poly")) + self.add_enclosure([apin, bpin, cpin, dpin], "npc", drc("npc_enclose_poly")) def route_output(self): """ Route the Z output """ diff --git a/compiler/tests/04_pnand4_test.py b/compiler/tests/04_pnand4_test.py index d2c64a5b..8eb1b4ba 100755 --- a/compiler/tests/04_pnand4_test.py +++ b/compiler/tests/04_pnand4_test.py @@ -26,11 +26,6 @@ class pnand4_test(openram_test): tx = factory.create(module_type="pnand4", size=1) self.local_check(tx) - # debug.info(2, "Checking 3-input nand gate") - # tx = factory.create(module_type="pnand3", size=1, add_wells=False) - # # Only DRC because well contacts will fail LVS - # self.local_drc_check(tx) - globals.end_openram() diff --git a/compiler/tests/06_hierarchical_decoder_test.py b/compiler/tests/06_hierarchical_decoder_test.py index e2b34cba..42bc38cd 100755 --- a/compiler/tests/06_hierarchical_decoder_test.py +++ b/compiler/tests/06_hierarchical_decoder_test.py @@ -8,19 +8,26 @@ # import unittest from testutils import * -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals from globals import OPTS from sram_factory import factory import debug + class hierarchical_decoder_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) + # Use the 2 port cell since it is usually bigger/easier + OPTS.bitcell = "bitcell_1rw_1r" + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + # Checks 2x4 and 2-input NAND decoder debug.info(1, "Testing 16 row sample for hierarchical_decoder") a = factory.create(module_type="hierarchical_decoder", num_outputs=16) @@ -50,6 +57,11 @@ class hierarchical_decoder_test(openram_test): debug.info(1, "Testing 512 row sample for hierarchical_decoder") a = factory.create(module_type="hierarchical_decoder", num_outputs=512) self.local_check(a) + + # Checks 3 x 4x16 and 4-input NAND decoder + debug.info(1, "Testing 4096 row sample for hierarchical_decoder") + a = factory.create(module_type="hierarchical_decoder", num_outputs=4096) + self.local_check(a) globals.end_openram() From 5246d0a93ba845a4a7f3db5fe89de5d61eaf807d Mon Sep 17 00:00:00 2001 From: jcirimel Date: Mon, 5 Oct 2020 12:10:44 -0700 Subject: [PATCH 72/83] track s8 customs modules --- compiler/custom/s8_col_cap_array.py | 136 +++++++++++++++++++++++ compiler/custom/s8_dummy_bitcell.py | 52 +++++++++ compiler/custom/s8_row_cap_array.py | 166 ++++++++++++++++++++++++++++ compiler/custom/s8_row_end.py | 34 ++++++ 4 files changed, 388 insertions(+) create mode 100644 compiler/custom/s8_col_cap_array.py create mode 100644 compiler/custom/s8_dummy_bitcell.py create mode 100644 compiler/custom/s8_row_cap_array.py create mode 100644 compiler/custom/s8_row_end.py diff --git a/compiler/custom/s8_col_cap_array.py b/compiler/custom/s8_col_cap_array.py new file mode 100644 index 00000000..9b275fbd --- /dev/null +++ b/compiler/custom/s8_col_cap_array.py @@ -0,0 +1,136 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California +# All rights reserved. +# +import design +from sram_factory import factory +from globals import OPTS +from tech import cell_properties + + +class s8_col_cap_array(design.design): + """ + Generate a dummy row/column for the replica array. + """ + def __init__(self, rows, cols, location, column_offset=0, mirror=0, name=""): + super().__init__(name) + self.rows = rows + self.cols = cols + self.location = location + self.column_offset = column_offset + self.mirror = mirror + self.no_instances = True + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + def create_netlist(self): + """ Create and connect the netlist """ + self.add_modules() + self.add_pins() + self.create_instances() + + def create_layout(self): + + self.place_array("col_cap_r{0}_c{1}", self.mirror) + self.add_layout_pins() + self.add_boundary() + self.DRC_LVS() + + def add_modules(self): + """ Add the modules used in this design """ + if self.location == "top": + self.colend1 = factory.create(module_type="s8_col_end", version = "colend") + self.add_mod(self.colend1) + self.colend2 = factory.create(module_type="s8_col_end", version = "colend_p_cent") + self.add_mod(self.colend2) + elif self.location == "bottom": + self.colend1 = factory.create(module_type="s8_col_end", version = "colenda") + self.add_mod(self.colend1) + self.colend2 = factory.create(module_type="s8_col_end", version = "colenda_p_cent") + self.add_mod(self.colend2) + + self.cell = factory.create(module_type="s8_bitcell", version = "opt1") + + def create_instances(self): + """ Create the module instances used in this design """ + self.cell_inst = {} + self.array_layout = [] + alternate_bitcell = 0 + for col in range((self.cols * 2 )-1): + row_layout = [] + name="rca_{0}".format(col) + # Top/bottom cell are always dummy cells. + # Regular array cells are replica cells (>left_rbl and left_rbl and 0): + + if alternate_bitcell == 0: + row_layout.append(self.rowend1) + self.cell_inst[row]=self.add_inst(name=name, mod=self.rowend1) + #self.connect_inst(self.get_bitcell_pins(row, 0)) + alternate_bitcell = 1 + + else: + row_layout.append(self.rowend2) + self.cell_inst[row]=self.add_inst(name=name,mod=self.rowend2) + #self.connect_inst(self.get_bitcell_pins(row, 0)) + alternate_bitcell = 0 + + elif (row == 0): + row_layout.append(self.bottom_corner) + self.cell_inst[row]=self.add_inst(name=name, mod=self.bottom_corner) + #self.connect_inst(self.get_bitcell_pins_col_cap(row, 0)) + + elif (row == self.rows - 1): + row_layout.append(self.top_corner) + self.cell_inst[row]=self.add_inst(name=name, mod=self.top_corner) + #self.connect_inst(self.get_bitcell_pins_col_cap(row, 0)) + + + self.array_layout.append(row_layout) + + + def get_bitcell_pins(self, row, col): + """ + Creates a list of connections in the bitcell, + indexed by column and row, for instance use in bitcell_array + """ + + pin_name = cell_properties.bitcell.cell_1rw1r.pin + bitcell_pins = ["{0}_{1}".format(pin_name.wl0, row), + "{0}_{1}".format(pin_name.wl1, row), + "gnd"] + + return bitcell_pins + + def place_array(self, name_template, row_offset=0): + self.width = 0 + self.height = 0 + + for inst in self.insts: + self.height += inst.height + if inst.width > self.width: + self.width = inst.width + yoffset = 0.0 + + for row in range(0, len(self.array_layout)): + xoffset = 0.0 + for col in range(0, len(self.array_layout[row])): + inst = self.insts[col + row*len(self.array_layout[row])] + inst.place(offset=[xoffset, yoffset]) + xoffset += inst.width + yoffset += inst.height + + + + def add_pins(self): + for row in range(self.rows-2): + for port in self.all_ports: + self.add_pin("wl_{}_{}".format(port, row), "INPUT") + for row in range(self.rows-2): + for port in self.all_ports: + self.add_pin("wl0_{}_{}".format(port, row), "OUTPUT") + self.add_pin("wl1_{}_{}".format(port, row), "OUTPUT") + self.add_pin("vpwr", "POWER") + self.add_pin("vgnd", "GROUND") + + def add_layout_pins(self): + """ Add the layout pins """ + return + row_list = self.cell.get_all_wl_names() + + for row in range(1, self.row_size - 1): + for cell_row in row_list: + wl_pin = self.cell_inst[row, 0].get_pin(cell_row) + self.add_layout_pin(text=cell_row + "_{0}".format(row), + layer=wl_pin.layer, + offset=wl_pin.ll().scale(0, 1), + width=self.width, + height=wl_pin.height()) + + # Add vdd/gnd via stacks + for row in range(1, self.row_size - 1): + for col in range(self.column_size): + inst = self.cell_inst[row, col] + for pin_name in ["vdd", "gnd"]: + for pin in inst.get_pins(pin_name): + self.add_power_pin(name=pin.name, + loc=pin.center(), + start_layer=pin.layer) + diff --git a/compiler/custom/s8_row_end.py b/compiler/custom/s8_row_end.py new file mode 100644 index 00000000..e9902397 --- /dev/null +++ b/compiler/custom/s8_row_end.py @@ -0,0 +1,34 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# + +import debug +import design +import utils +from globals import OPTS +from tech import parameter, drc, layer, GDS + +class s8_row_end(design.design): + + + def __init__(self, version, name=""): + super().__init__(name) + pin_names = [] + type_list = [] + + if version == "rowend": + self.name = "s8sram16x16_rowend" + elif version == "rowenda": + self.name = "s8sram16x16_rowenda" + else: + debug.error("Invalid type for row_end", -1) + design.design.__init__(self, name=self.name) + (self.width, self.height) = utils.get_libcell_size(self.name, + GDS["unit"], + layer["mem"], + "s8sram16x16_rowend_ce\x00") + pin_map = utils.get_libcell_pins(pin_names, self.name, GDS["unit"]) From 9fe63585690343935e5d802386b9cd966553dc70 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 5 Oct 2020 13:50:04 -0700 Subject: [PATCH 73/83] Change .spinit to .spiceinit --- compiler/characterizer/stimuli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index da8e16f0..785b2b3b 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -319,7 +319,7 @@ class stimuli(): # ngspice 27+ supports threading with "set num_threads=4" in the stimulus file or a .spiceinit # Measurements can't be made with a raw file set in ngspice # -r {2}timing.raw - ng_cfg = open("{}.spinit".format(OPTS.openram_temp), "w") + ng_cfg = open("{}.spiceinit".format(OPTS.openram_temp), "w") ng_cfg.write("set num_threads={}\n".format(OPTS.num_threads)) ng_cfg.close() From c4952ca8be89fb47253560dab4475be88d5348f5 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 5 Oct 2020 13:51:20 -0700 Subject: [PATCH 74/83] Skip full sram pex test too slow --- compiler/tests/26_sram_pex_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/tests/26_sram_pex_test.py b/compiler/tests/26_sram_pex_test.py index 7736e379..5a3253de 100755 --- a/compiler/tests/26_sram_pex_test.py +++ b/compiler/tests/26_sram_pex_test.py @@ -16,6 +16,7 @@ from sram_factory import factory import debug +@unittest.skip("SKIPPING 26_sram_pex_test") class sram_pex_test(openram_test): def runTest(self): From cb35c0aff41d159272573613ebbdcd67afafcb0d Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 5 Oct 2020 15:49:00 -0700 Subject: [PATCH 75/83] Add command line -j option for number of threads. --- compiler/globals.py | 5 +++++ compiler/options.py | 1 + 2 files changed, 6 insertions(+) diff --git a/compiler/globals.py b/compiler/globals.py index dd4ac177..e1bb8661 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -55,6 +55,11 @@ def parse_args(): action="store_false", help="Disable all LVS/DRC checks", dest="check_lvsdrc"), + optparse.make_option("-j", "--threads", + action="store", + type="int", + help="Specify the number of threads (default: 2)", + dest="num_threads"), optparse.make_option("-v", "--verbose", action="count", diff --git a/compiler/options.py b/compiler/options.py index 632cd34f..2221f85f 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -9,6 +9,7 @@ import optparse import getpass import os + class options(optparse.Values): """ Class for holding all of the OpenRAM options. All From a145a37cf7df99289e13d2be3829c32679db8f3c Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 5 Oct 2020 15:56:12 -0700 Subject: [PATCH 76/83] PEP8 fixes in regress.py --- compiler/tests/regress.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/tests/regress.py b/compiler/tests/regress.py index 3fd5d6eb..383ef8fa 100755 --- a/compiler/tests/regress.py +++ b/compiler/tests/regress.py @@ -9,7 +9,7 @@ import re import unittest -import sys,os +import sys, os sys.path.append(os.getenv("OPENRAM_HOME")) import globals @@ -47,12 +47,12 @@ suite = unittest.TestSuite() load = unittest.defaultTestLoader.loadTestsFromModule suite.addTests(map(load, modules)) -test_runner = unittest.TextTestRunner(verbosity=2,stream=sys.stderr) +test_runner = unittest.TextTestRunner(verbosity=2, stream=sys.stderr) test_result = test_runner.run(suite) import verify verify.print_drc_stats() verify.print_lvs_stats() -verify.print_pex_stats() +verify.print_pex_stats() sys.exit(not test_result.wasSuccessful()) From 13e2a9f5f7b77398163d4bba69004c83a7e6db2d Mon Sep 17 00:00:00 2001 From: jcirimel Date: Tue, 6 Oct 2020 05:11:15 -0700 Subject: [PATCH 77/83] fix missed self.left_rbl refactor --- compiler/modules/replica_bitcell_array.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 834497a5..ec27ba32 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -166,7 +166,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): cols=1, column_offset=0, rows=self.row_size + self.extra_rows, - mirror=(self.left_rbl + 1) % 2) + mirror=(self.rbl[0] + 1) % 2) self.add_mod(self.row_cap_left) self.row_cap_right = factory.create(module_type=row_cap_module_type, @@ -177,7 +177,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): # + right replica column(s) column_offset = 1 + len(self.left_rbl) + self.column_size + self.rbl[0], rows=self.row_size + self.extra_rows, - mirror=(self.left_rbl + 1) %2) + mirror=(self.rbl[0] + 1) %2) self.add_mod(self.row_cap_right) else: # Dummy Row or Col Cap, depending on bitcell array properties From ba432669a1e98b40507687738b2c6f41b3f1bd98 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 6 Oct 2020 16:25:44 -0700 Subject: [PATCH 78/83] Add various riscv examples --- .../example_configs/riscv-freepdk45-8kbyte.py | 26 +++++++++++++++++++ .../riscv-scn4m_subm-16kbyte.py | 26 +++++++++++++++++++ .../riscv-scn4m_subm-1kbyte.py | 24 +++++++++++++++++ .../riscv-scn4m_subm-2kbyte.py | 24 +++++++++++++++++ .../riscv-scn4m_subm-32kbyte.py | 26 +++++++++++++++++++ .../riscv-scn4m_subm-4kbyte.py | 24 +++++++++++++++++ .../riscv-scn4m_subm-8kbyte.py | 26 +++++++++++++++++++ .../example_configs/riscv-sky130-1kbyte.py | 26 +++++++++++++++++++ .../example_configs/riscv-sky130-2kbyte.py | 26 +++++++++++++++++++ .../example_configs/riscv-sky130-4kbyte.py | 26 +++++++++++++++++++ 10 files changed, 254 insertions(+) create mode 100644 compiler/example_configs/riscv-freepdk45-8kbyte.py create mode 100644 compiler/example_configs/riscv-scn4m_subm-16kbyte.py create mode 100644 compiler/example_configs/riscv-scn4m_subm-1kbyte.py create mode 100644 compiler/example_configs/riscv-scn4m_subm-2kbyte.py create mode 100644 compiler/example_configs/riscv-scn4m_subm-32kbyte.py create mode 100644 compiler/example_configs/riscv-scn4m_subm-4kbyte.py create mode 100644 compiler/example_configs/riscv-scn4m_subm-8kbyte.py create mode 100644 compiler/example_configs/riscv-sky130-1kbyte.py create mode 100644 compiler/example_configs/riscv-sky130-2kbyte.py create mode 100644 compiler/example_configs/riscv-sky130-4kbyte.py diff --git a/compiler/example_configs/riscv-freepdk45-8kbyte.py b/compiler/example_configs/riscv-freepdk45-8kbyte.py new file mode 100644 index 00000000..b0ebf764 --- /dev/null +++ b/compiler/example_configs/riscv-freepdk45-8kbyte.py @@ -0,0 +1,26 @@ +word_size = 32 +num_words = 2048 +write_size = 8 + +local_array_size = 32 + +num_rw_ports = 1 +num_r_ports = 1 +num_w_ports = 0 + +tech_name = "freepdk45" +nominal_corners_only = True + +route_supplies = False +check_lvsdrc = False +perimeter_pins = False +#netlist_only = True +#analytical_delay = False +output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) +output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) diff --git a/compiler/example_configs/riscv-scn4m_subm-16kbyte.py b/compiler/example_configs/riscv-scn4m_subm-16kbyte.py new file mode 100644 index 00000000..befe49fb --- /dev/null +++ b/compiler/example_configs/riscv-scn4m_subm-16kbyte.py @@ -0,0 +1,26 @@ +word_size = 32 +num_words = 4096 +write_size = 8 + +local_array_size = 32 + +num_rw_ports = 1 +num_r_ports = 1 +num_w_ports = 0 + +tech_name = "scn4m_subm" +nominal_corners_only = True + +route_supplies = False +check_lvsdrc = False +perimeter_pins = False +#netlist_only = True +#analytical_delay = False +output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) +output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) diff --git a/compiler/example_configs/riscv-scn4m_subm-1kbyte.py b/compiler/example_configs/riscv-scn4m_subm-1kbyte.py new file mode 100644 index 00000000..1ab9f5fe --- /dev/null +++ b/compiler/example_configs/riscv-scn4m_subm-1kbyte.py @@ -0,0 +1,24 @@ +word_size = 32 +num_words = 256 +write_size = 8 + +num_rw_ports = 1 +num_r_ports = 1 +num_w_ports = 0 + +tech_name = "scn4m_subm" +nominal_corners_only = True + +route_supplies = True +check_lvsdrc = True +perimeter_pins = True +#netlist_only = True +#analytical_delay = False +output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) +output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) diff --git a/compiler/example_configs/riscv-scn4m_subm-2kbyte.py b/compiler/example_configs/riscv-scn4m_subm-2kbyte.py new file mode 100644 index 00000000..267e31ef --- /dev/null +++ b/compiler/example_configs/riscv-scn4m_subm-2kbyte.py @@ -0,0 +1,24 @@ +word_size = 32 +num_words = 512 +write_size = 8 + +num_rw_ports = 1 +num_r_ports = 1 +num_w_ports = 0 + +tech_name = "scn4m_subm" +nominal_corners_only = True + +route_supplies = True +check_lvsdrc = True +perimeter_pins = True +#netlist_only = True +#analytical_delay = False +output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) +output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) diff --git a/compiler/example_configs/riscv-scn4m_subm-32kbyte.py b/compiler/example_configs/riscv-scn4m_subm-32kbyte.py new file mode 100644 index 00000000..98cb8808 --- /dev/null +++ b/compiler/example_configs/riscv-scn4m_subm-32kbyte.py @@ -0,0 +1,26 @@ +word_size = 32 +num_words = 8192 +write_size = 8 + +local_array_size = 32 + +num_rw_ports = 1 +num_r_ports = 1 +num_w_ports = 0 + +tech_name = "scn4m_subm" +nominal_corners_only = True + +route_supplies = False +check_lvsdrc = False +perimeter_pins = False +#netlist_only = True +#analytical_delay = False +output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) +output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) diff --git a/compiler/example_configs/riscv-scn4m_subm-4kbyte.py b/compiler/example_configs/riscv-scn4m_subm-4kbyte.py new file mode 100644 index 00000000..87cf4a71 --- /dev/null +++ b/compiler/example_configs/riscv-scn4m_subm-4kbyte.py @@ -0,0 +1,24 @@ +word_size = 32 +num_words = 1024 +write_size = 8 + +num_rw_ports = 1 +num_r_ports = 1 +num_w_ports = 0 + +tech_name = "scn4m_subm" +nominal_corners_only = True + +route_supplies = True +check_lvsdrc = True +perimeter_pins = True +#netlist_only = True +#analytical_delay = False +output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) +output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) diff --git a/compiler/example_configs/riscv-scn4m_subm-8kbyte.py b/compiler/example_configs/riscv-scn4m_subm-8kbyte.py new file mode 100644 index 00000000..8b1715ff --- /dev/null +++ b/compiler/example_configs/riscv-scn4m_subm-8kbyte.py @@ -0,0 +1,26 @@ +word_size = 32 +num_words = 2048 +write_size = 8 + +local_array_size = 32 + +num_rw_ports = 1 +num_r_ports = 1 +num_w_ports = 0 + +tech_name = "scn4m_subm" +nominal_corners_only = True + +route_supplies = False +check_lvsdrc = False +perimeter_pins = False +#netlist_only = True +#analytical_delay = False +output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) +output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) diff --git a/compiler/example_configs/riscv-sky130-1kbyte.py b/compiler/example_configs/riscv-sky130-1kbyte.py new file mode 100644 index 00000000..c4a298d2 --- /dev/null +++ b/compiler/example_configs/riscv-sky130-1kbyte.py @@ -0,0 +1,26 @@ +word_size = 32 +num_words = 256 +write_size = 8 + +local_array_size = 16 + +num_rw_ports = 1 +num_r_ports = 1 +num_w_ports = 0 + +tech_name = "sky130" +nominal_corners_only = True + +route_supplies = True +check_lvsdrc = True +perimeter_pins = True +#netlist_only = True +#analytical_delay = False +output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) +output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) diff --git a/compiler/example_configs/riscv-sky130-2kbyte.py b/compiler/example_configs/riscv-sky130-2kbyte.py new file mode 100644 index 00000000..d50d532e --- /dev/null +++ b/compiler/example_configs/riscv-sky130-2kbyte.py @@ -0,0 +1,26 @@ +word_size = 32 +num_words = 512 +write_size = 8 + +local_array_size = 16 + +num_rw_ports = 1 +num_r_ports = 1 +num_w_ports = 0 + +tech_name = "sky130" +nominal_corners_only = True + +route_supplies = True +check_lvsdrc = True +perimeter_pins = True +#netlist_only = True +#analytical_delay = False +output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) +output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) diff --git a/compiler/example_configs/riscv-sky130-4kbyte.py b/compiler/example_configs/riscv-sky130-4kbyte.py new file mode 100644 index 00000000..2d870e88 --- /dev/null +++ b/compiler/example_configs/riscv-sky130-4kbyte.py @@ -0,0 +1,26 @@ +word_size = 32 +num_words = 1024 +write_size = 8 + +local_array_size = 16 + +num_rw_ports = 1 +num_r_ports = 1 +num_w_ports = 0 + +tech_name = "sky130" +nominal_corners_only = True + +route_supplies = True +check_lvsdrc = True +perimeter_pins = True +#netlist_only = True +#analytical_delay = False +output_path = "macros/sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) +output_name = "sram_1rw1r_{0}_{1}_{2}_{3}".format(word_size, + num_words, + write_size, + tech_name) From 27d921d2db130ff8de90cf8e5366562279681079 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 6 Oct 2020 16:26:35 -0700 Subject: [PATCH 79/83] Fix run-time bug for duplicate instance check --- compiler/base/hierarchy_layout.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 133ecc9b..e4830226 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -37,6 +37,7 @@ class layout(): self.height = None self.bounding_box = None self.insts = [] # Holds module/cell layout instances + self.inst_names = set() # Set of names to check for duplicates self.objs = [] # Holds all other objects (labels, geometries, etc) self.pin_map = {} # Holds name->pin_layout map for all pins self.visited = [] # List of modules we have already visited @@ -214,9 +215,9 @@ class layout(): # Contacts are not really instances, so skip them if "contact" not in mod.name: # Check that the instance name is unique - for inst in self.insts: - debug.check(name != inst.name, "Duplicate named instance in {0}: {1}".format(self.name, name)) - + debug.check(name not in self.inst_names, "Duplicate named instance in {0}: {1}".format(self.name, name)) + + self.inst_names.add(name) self.insts.append(geometry.instance(name, mod, offset, mirror, rotate)) debug.info(3, "adding instance {}".format(self.insts[-1])) # This is commented out for runtime reasons From c2629edc1b0cfe3cf5570dc50667b0b711ac609f Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 6 Oct 2020 16:27:02 -0700 Subject: [PATCH 80/83] Allow 16-way column mux --- compiler/modules/bank.py | 3 ++ compiler/modules/port_address.py | 4 +- compiler/modules/replica_column.py | 6 ++- compiler/sram/sram.py | 14 +++--- compiler/sram/sram_config.py | 74 +++++++++++++++--------------- 5 files changed, 53 insertions(+), 48 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 41433e46..a1c6c251 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -533,6 +533,9 @@ class bank(design.design): elif self.col_addr_size == 3: self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", height=self.dff.height) + elif self.col_addr_size == 4: + self.column_decoder = factory.create(module_type="hierarchical_predecode4x16", + height=self.dff.height) else: # No error checking before? debug.error("Invalid column decoder?", -1) diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index f7e85afd..8146e7b6 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -79,8 +79,8 @@ class port_address(design.design): self.copy_power_pins(inst, "vdd") self.copy_power_pins(inst, "gnd") - rbl_vdd_pin = self.rbl_driver_inst.get_pin("vdd") - self.add_power_pin("vdd", rbl_vdd_pin.lc()) + for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"): + self.add_power_pin("vdd", rbl_vdd_pin.center()) def route_pins(self): for row in range(self.addr_size): diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index dafe51e6..6d084261 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -221,8 +221,10 @@ class replica_column(bitcell_base_array): bitcell_pins = [] for port in self.all_ports: bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))]) - bitcell_pins.append("vdd") - bitcell_pins.append("gnd") + if len(self.edge_cell.get_pins("vdd")) > 0: + bitcell_pins.append("vdd") + if len(self.edge_cell.get_pins("gnd")) > 0: + bitcell_pins.append("gnd") return bitcell_pins diff --git a/compiler/sram/sram.py b/compiler/sram/sram.py index 992919f0..63d971f3 100644 --- a/compiler/sram/sram.py +++ b/compiler/sram/sram.py @@ -79,13 +79,6 @@ class sram(): """ Save all the output files while reporting time to do it as well. """ if not OPTS.netlist_only: - # Create a LEF physical model - start_time = datetime.datetime.now() - lefname = OPTS.output_path + self.s.name + ".lef" - debug.print_raw("LEF: Writing to {0}".format(lefname)) - self.lef_write(lefname) - print_time("LEF", datetime.datetime.now(), start_time) - # Write the layout start_time = datetime.datetime.now() gdsname = OPTS.output_path + self.s.name + ".gds" @@ -93,6 +86,13 @@ class sram(): self.gds_write(gdsname) print_time("GDS", datetime.datetime.now(), start_time) + # Create a LEF physical model + start_time = datetime.datetime.now() + lefname = OPTS.output_path + self.s.name + ".lef" + debug.print_raw("LEF: Writing to {0}".format(lefname)) + self.lef_write(lefname) + print_time("LEF", datetime.datetime.now(), start_time) + # Save the spice file start_time = datetime.datetime.now() spname = OPTS.output_path + self.s.name + ".sp" diff --git a/compiler/sram/sram_config.py b/compiler/sram/sram_config.py index fa70d730..573e7514 100644 --- a/compiler/sram/sram_config.py +++ b/compiler/sram/sram_config.py @@ -6,15 +6,15 @@ # All rights reserved. # import debug -from math import log,sqrt,ceil -from importlib import reload +from math import log, sqrt, ceil from globals import OPTS from sram_factory import factory + class sram_config: """ This is a structure that is used to hold the SRAM configuration options. """ - def __init__(self, word_size, num_words, write_size = None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=0): + def __init__(self, word_size, num_words, write_size=None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=0): self.word_size = word_size self.num_words = num_words self.write_size = write_size @@ -25,7 +25,7 @@ class sram_config: # This will get over-written when we determine the organization self.words_per_row = words_per_row - self.compute_sizes() + self.compute_sizes() def set_local_config(self, module): """ Copy all of the member variables to the given module for convenience """ @@ -34,31 +34,31 @@ class sram_config: # Copy all the variables to the local module for member in members: - setattr(module,member,getattr(self,member)) + setattr(module, member, getattr(self, member)) def compute_sizes(self): """ Computes the organization of the memory using bitcell size by trying to make it square.""" bitcell = factory.create(module_type="bitcell") - - debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.") + debug.check(self.num_banks in [1, 2, 4], + "Valid number of banks are 1 , 2 and 4.") - self.num_words_per_bank = self.num_words/self.num_banks - self.num_bits_per_bank = self.word_size*self.num_words_per_bank + self.num_words_per_bank = self.num_words / self.num_banks + self.num_bits_per_bank = self.word_size * self.num_words_per_bank # If this was hard coded, don't dynamically compute it! if not self.words_per_row: # Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry) - self.bank_area = bitcell.width*bitcell.height*self.num_bits_per_bank + self.bank_area = bitcell.width * bitcell.height * self.num_bits_per_bank self.bank_side_length = sqrt(self.bank_area) # Estimate the words per row given the height of the bitcell and the square side length - self.tentative_num_cols = int(self.bank_side_length/bitcell.width) + self.tentative_num_cols = int(self.bank_side_length / bitcell.width) self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size) # Estimate the number of rows given the tentative words per row - self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row*self.word_size) + self.tentative_num_rows = self.num_bits_per_bank / (self.words_per_row * self.word_size) self.words_per_row = self.amend_words_per_row(self.tentative_num_rows, self.words_per_row) self.recompute_sizes() @@ -70,57 +70,57 @@ class sram_config: SRAM for testing. """ - debug.info(1,"Recomputing with words per row: {}".format(self.words_per_row)) + debug.info(1, "Recomputing with words per row: {}".format(self.words_per_row)) # If the banks changed - self.num_words_per_bank = self.num_words/self.num_banks - self.num_bits_per_bank = self.word_size*self.num_words_per_bank + self.num_words_per_bank = self.num_words / self.num_banks + self.num_bits_per_bank = self.word_size * self.num_words_per_bank # Fix the number of columns and rows - self.num_cols = int(self.words_per_row*self.word_size) - self.num_rows_temp = int(self.num_words_per_bank/self.words_per_row) + self.num_cols = int(self.words_per_row * self.word_size) + self.num_rows_temp = int(self.num_words_per_bank / self.words_per_row) self.num_rows = self.num_rows_temp + self.num_spare_rows - debug.info(1,"Rows: {} Cols: {}".format(self.num_rows_temp,self.num_cols)) + debug.info(1, "Rows: {} Cols: {}".format(self.num_rows_temp, self.num_cols)) # Compute the address and bank sizes self.row_addr_size = ceil(log(self.num_rows, 2)) self.col_addr_size = int(log(self.words_per_row, 2)) self.bank_addr_size = self.col_addr_size + self.row_addr_size self.addr_size = self.bank_addr_size + int(log(self.num_banks, 2)) - debug.info(1,"Row addr size: {}".format(self.row_addr_size) + debug.info(1, "Row addr size: {}".format(self.row_addr_size) + " Col addr size: {}".format(self.col_addr_size) + " Bank addr size: {}".format(self.bank_addr_size)) - - def estimate_words_per_row(self,tentative_num_cols, word_size): + def estimate_words_per_row(self, tentative_num_cols, word_size): """ This provides a heuristic rounded estimate for the number of words per row. """ + tentative_column_ways = tentative_num_cols / word_size + column_mux_sizes = [1, 2, 4, 8, 16] + # If we are double, we may want a larger column mux + if tentative_column_ways > 2 * column_mux_sizes[-1]: + debug.warning("Extremely large number of columns for 16-way maximum column mux.") - if tentative_num_cols < 1.5*word_size: - return 1 - elif tentative_num_cols < 3*word_size: - return 2 - elif tentative_num_cols < 6*word_size: - return 4 - else: - if tentative_num_cols > 16*word_size: - debug.warning("Reaching column mux size limit. Consider increasing above 8-way.") - return 8 + closest_way = min(column_mux_sizes, key=lambda x: abs(x - tentative_column_ways)) - def amend_words_per_row(self,tentative_num_rows, words_per_row): + return closest_way + + def amend_words_per_row(self, tentative_num_rows, words_per_row): """ This picks the number of words per row more accurately by limiting it to a minimum and maximum. """ # Recompute the words per row given a hard max if(not OPTS.is_unit_test and tentative_num_rows > 512): - debug.check(tentative_num_rows*words_per_row <= 2048, "Number of words exceeds 2048") - return int(words_per_row*tentative_num_rows/512) + debug.check(tentative_num_rows * words_per_row <= 4096, + "Number of words exceeds 2048") + return int(words_per_row * tentative_num_rows / 512) + # Recompute the words per row given a hard min - if(not OPTS.is_unit_test and tentative_num_rows < 16): - debug.check(tentative_num_rows*words_per_row >= 16, "Minimum number of rows is 16, but given {0}".format(tentative_num_rows)) - return int(words_per_row*tentative_num_rows/16) + if (not OPTS.is_unit_test and tentative_num_rows < 16): + debug.check(tentative_num_rows * words_per_row >= 16, + "Minimum number of rows is 16, but given {0}".format(tentative_num_rows)) + return int(words_per_row * tentative_num_rows / 16) return words_per_row From 483f6b187cd0723d196c4ef651013570cdba367a Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 6 Oct 2020 16:47:32 -0700 Subject: [PATCH 81/83] RBL driver supply location differs for sky130 and other techs --- compiler/modules/port_address.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 8146e7b6..e416eb43 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -80,8 +80,11 @@ class port_address(design.design): self.copy_power_pins(inst, "gnd") for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"): - self.add_power_pin("vdd", rbl_vdd_pin.center()) - + if OPTS.tech_name == "sky130": + self.add_power_pin("vdd", rbl_vdd_pin.center()) + else: + self.add_power_pin("vdd", rbl_vdd_pin.lc()) + def route_pins(self): for row in range(self.addr_size): decoder_name = "addr_{}".format(row) From d40c3588ed0cb29e8e94e6caff6617d3c12874c5 Mon Sep 17 00:00:00 2001 From: jcirimel Date: Thu, 8 Oct 2020 03:34:16 -0700 Subject: [PATCH 82/83] no wl for col end --- compiler/base/custom_cell_properties.py | 5 +- compiler/custom/s8_bitcell.py | 15 +- compiler/custom/s8_col_cap_array.py | 1 + compiler/custom/s8_col_end.py | 4 +- compiler/custom/s8_dummy_bitcell.py | 10 +- compiler/custom/s8_row_cap_array.py | 5 +- compiler/modules/bitcell_base_array.py | 20 +- compiler/modules/dummy_array.py | 2 +- compiler/modules/replica_bitcell_array.py | 139 +- compiler/modules/replica_column.py | 6 +- compiler/tests/missing_pin.gds | Bin 3328 -> 8520 bytes compiler/tests/sram_1b_16_1rw_sky130.log | 1759 +-------------------- missing_pin.gds | Bin 7442 -> 8520 bytes sram_0.05/sram_16_16_sky130_0.05.log | 204 +-- sram_1b_16_1rw_sky130.log | 5 +- 15 files changed, 99 insertions(+), 2076 deletions(-) diff --git a/compiler/base/custom_cell_properties.py b/compiler/base/custom_cell_properties.py index a5d40463..2e21c1ec 100644 --- a/compiler/base/custom_cell_properties.py +++ b/compiler/base/custom_cell_properties.py @@ -45,8 +45,7 @@ class _bitcell: cell_s8_6t = _cell({'bl' : 'bl0', 'br' : 'bl1', - 'wl0': 'wl0', - 'wl1': 'wl1'}) + 'wl': 'wl'}) cell_6t = _cell({'bl' : 'bl', 'br' : 'br', @@ -181,4 +180,4 @@ class cell_properties(): if ports == "{}R_{}W_{}RW".format(OPTS.num_r_ports, OPTS.num_w_ports, OPTS.num_rw_ports): use_custom_arrangement = True break - return use_custom_arrangement \ No newline at end of file + return use_custom_arrangement diff --git a/compiler/custom/s8_bitcell.py b/compiler/custom/s8_bitcell.py index 2905924a..fff3a6b8 100644 --- a/compiler/custom/s8_bitcell.py +++ b/compiler/custom/s8_bitcell.py @@ -27,11 +27,11 @@ class s8_bitcell(bitcell_base.bitcell_base): pin_names = ["bl0", "bl1", "wl0", "wl1", "vpwr", "vgnd"] type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT", "POWER", "GROUND"] else: - pin_names = [props.bitcell.cell_6t.pin.bl, - props.bitcell.cell_6t.pin.br, - props.bitcell.cell_6t.pin.wl, - props.bitcell.cell_6t.pin.vdd, - props.bitcell.cell_6t.pin.gnd] + pin_names = [props.bitcell.cell_s8_6t.pin.bl, + props.bitcell.cell_s8_6t.pin.br, + props.bitcell.cell_s8_6t.pin.wl, + "vpwr", + "vgnd"] type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] storage_nets = ['Q', 'Q_bar'] @@ -61,15 +61,12 @@ class s8_bitcell(bitcell_base.bitcell_base): layer["mem"], "s8sram_cell\x00") - - #debug.check(OPTS.tech_name != "sky130", "sky130 does not yet support single port cells") - def get_all_wl_names(self): """ Creates a list of all wordline pin names """ if props.compare_ports(props.bitcell.split_wl): row_pins = ["wl0", "wl1"] else: - row_pins = [props.bitcell.s8_sp.pin.wl] + row_pins = [props.bitcell.cell_s8_6t.pin.wl] return row_pins def get_all_bitline_names(self): diff --git a/compiler/custom/s8_col_cap_array.py b/compiler/custom/s8_col_cap_array.py index 9b275fbd..3fb00a20 100644 --- a/compiler/custom/s8_col_cap_array.py +++ b/compiler/custom/s8_col_cap_array.py @@ -21,6 +21,7 @@ class s8_col_cap_array(design.design): self.column_offset = column_offset self.mirror = mirror self.no_instances = True + self.all_wordline_names = [] self.create_netlist() if not OPTS.netlist_only: self.create_layout() diff --git a/compiler/custom/s8_col_end.py b/compiler/custom/s8_col_end.py index 827692f0..5c9c4b92 100644 --- a/compiler/custom/s8_col_end.py +++ b/compiler/custom/s8_col_end.py @@ -21,8 +21,8 @@ class s8_col_end(design.design): type_list = [] if version == "colend": - self.name = "s8sram16x16_colenda" - structure = "s8sram16x16_colenda\x00" + self.name = "s8sram16x16_colend" + structure = "s8sram16x16_colend" elif version == "colend_p_cent": self.name = "s8sram16x16_colend_p_cent" structure = "s8sram16x16_colend_p_cent\x00" diff --git a/compiler/custom/s8_dummy_bitcell.py b/compiler/custom/s8_dummy_bitcell.py index fd2e407a..c6880638 100644 --- a/compiler/custom/s8_dummy_bitcell.py +++ b/compiler/custom/s8_dummy_bitcell.py @@ -24,11 +24,11 @@ class s8_dummy_bitcell(bitcell_base.bitcell_base): pin_names = ["bl", "br", "wl0", "wl1", "vdd", "gnd"] type_list = ["OUTPUT", "OUTPUT", "INPUT", "INPUT" , "POWER", "GROUND"] else: - pin_names = [props.bitcell.cell_6t.pin.bl, - props.bitcell.cell_6t.pin.br, - props.bitcell.cell_6t.pin.wl, - props.bitcell.cell_6t.pin.vdd, - props.bitcell.cell_6t.pin.gnd] + pin_names = [props.bitcell.cell_s8_6t.pin.bl, + props.bitcell.cell_s8_6t.pin.br, + props.bitcell.cell_s8_6t.pin.wl, + "vpwr", + "vgnd"] diff --git a/compiler/custom/s8_row_cap_array.py b/compiler/custom/s8_row_cap_array.py index da673f93..ab3dce1c 100644 --- a/compiler/custom/s8_row_cap_array.py +++ b/compiler/custom/s8_row_cap_array.py @@ -130,10 +130,9 @@ class s8_row_cap_array(design.design): def add_pins(self): - for row in range(self.rows): + for row in range(self.rows - 2): for port in self.all_ports: - self.add_pin("wl0_{}_{}".format(port, row), "OUTPUT") - self.add_pin("wl1_{}_{}".format(port, row), "OUTPUT") + self.add_pin("wl_{}_{}".format(port, row), "OUTPUT") self.add_pin("vpwr", "POWER") self.add_pin("vgnd", "GROUND") diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index 99eca707..ffc3bb0f 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -56,31 +56,29 @@ class bitcell_base_array(design.design): # def get_all_wordline_names(self, prefix=""): # return [prefix + x for x in self.all_wordline_names] - def create_all_wordline_names(self): - for row in range(self.row_size): + def create_all_wordline_names(self, remove_wordline = 0): + for row in range(self.row_size - remove_wordline): for port in self.all_ports: if not cell_properties.compare_ports(cell_properties.bitcell.split_wl): self.wordline_names[port].append("wl_{0}_{1}".format(port, row)) else: self.wordline_names[port].append("wl0_{0}_{1}".format(port, row)) self.wordline_names[port].append("wl1_{0}_{1}".format(port, row)) + self.all_wordline_names = [x for sl in zip(*self.wordline_names) for x in sl] - + def add_pins(self): + for bl_name in self.get_bitline_names(): + self.add_pin(bl_name, "INOUT") + for wl_name in self.get_wordline_names(): + self.add_pin(wl_name, "INPUT") if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - for bl_name in self.get_bitline_names(): - self.add_pin(bl_name, "INOUT") - for wl_name in self.get_wordline_names(): - self.add_pin(wl_name, "INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") else: - for bl_name in self.get_bitline_names(): - self.add_pin(bl_name, "INOUT") - for wl_name in self.get_wordline_names(): - self.add_pin(wl_name, "INPUT") self.add_pin("vpwr", "POWER") self.add_pin("vgnd", "GROUND") + def get_bitcell_pins(self, row, col): """ Creates a list of connections in the bitcell, indexed by column and row, for instance use in bitcell_array """ diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py index 39579b12..3a7a2ec0 100644 --- a/compiler/modules/dummy_array.py +++ b/compiler/modules/dummy_array.py @@ -98,7 +98,7 @@ class dummy_array(bitcell_base_array): height=self.height) wl_names = self.cell.get_all_wl_names() - if not props.compare_ports(props.bitcell_array.use_custom_cell_arrangement): + if not props.compare_ports(props.bitcell.split_wl): for row in range(self.row_size): for port in self.all_ports: wl_pin = self.cell_inst[row, 0].get_pin(wl_names[port]) diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index ec27ba32..816a5391 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -267,96 +267,74 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): for port in self.all_ports: for bit in self.all_ports: - if not cell_properties.compare_ports(cell_properties.bitcell.split_wl): + #if not cell_properties.compare_ports(cell_properties.bitcell.split_wl): self.rbl_wordline_names[port].append("rbl_wl_{0}_{1}".format(port, bit)) if bit != port: self.gnd_wordline_names.append("rbl_wl_{0}_{1}".format(port, bit)) - else: - self.rbl_wordline_names[port].append("rbl_wl0_{0}_{1}".format(port, bit)) - self.rbl_wordline_names[port].append("rbl_wl1_{0}_{1}".format(port, bit)) - if bit != port: - self.gnd_wordline_names.append("rbl0_wl_{0}_{1}".format(port, bit)) - self.gnd_wordline_names.append("rbl1_wl_{0}_{1}".format(port, bit)) + #else: + # self.rbl_wordline_names[port].append("rbl_wl0_{0}_{1}".format(port, bit)) + # self.rbl_wordline_names[port].append("rbl_wl1_{0}_{1}".format(port, bit)) + # if bit != port: + # self.gnd_wordline_names.append("rbl0_wl_{0}_{1}".format(port, bit)) + # self.gnd_wordline_names.append("rbl1_wl_{0}_{1}".format(port, bit)) self.all_rbl_wordline_names = [x for sl in self.rbl_wordline_names for x in sl] self.wordline_names = self.bitcell_array.wordline_names self.all_wordline_names = self.bitcell_array.all_wordline_names + + # All wordlines including dummy and RBL + self.replica_array_wordline_names = [] if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - - # All wordlines including dummy and RBL - self.replica_array_wordline_names = [] self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap.get_wordline_names())) - for bit in range(self.rbl[0]): - self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[bit]]) - self.replica_array_wordline_names.extend(self.all_wordline_names) - for bit in range(self.rbl[1]): - self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[self.rbl[0] + bit]]) + for bit in range(self.rbl[0]): + self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[bit]]) + self.replica_array_wordline_names.extend(self.all_wordline_names) + for bit in range(self.rbl[1]): + self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[self.rbl[0] + bit]]) + if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap.get_wordline_names())) - for port in range(self.rbl[0]): - self.add_pin(self.rbl_wordline_names[port][port], "INPUT") - self.add_pin_list(self.all_wordline_names, "INPUT") - for port in range(self.rbl[0], self.rbl[0] + self.rbl[1]): - self.add_pin(self.rbl_wordline_names[port][port], "INPUT") - else: - # All wordlines including dummy and RBL - self.replica_array_wordline_names = [] - self.replica_array_wordline_names.extend(["gnd"] * 2) - for bit in range(self.rbl[0]): - self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[bit]]) - self.replica_array_wordline_names.extend(self.all_wordline_names) - for bit in range(self.rbl[1]): - self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[self.rbl[0] + bit]]) - self.replica_array_wordline_names.extend(["gnd"] *2) - - for port in range(self.rbl[0]): - self.add_pin(self.rbl_wordline_names[port][port], "INPUT") - self.add_pin_list(self.all_wordline_names, "INPUT") - for port in range(self.rbl[0], self.rbl[0] + self.rbl[1]): - self.add_pin(self.rbl_wordline_names[port][port], "INPUT") + for port in range(self.rbl[0]): + self.add_pin(self.rbl_wordline_names[port][port], "INPUT") + self.add_pin_list(self.all_wordline_names, "INPUT") + for port in range(self.rbl[0], self.rbl[0] + self.rbl[1]): + self.add_pin(self.rbl_wordline_names[port][port], "INPUT") def create_instances(self): """ Create the module instances used in this design """ - - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - self.supplies = ["vdd", "gnd"] - else: - self.supplies = ["vpwr", "vgnd"] - - # Used for names/dimensions only - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - self.cell = factory.create(module_type="bitcell") - else: - self.cell = factory.create(module_type="s8_bitcell", version = "opt1") - - # Main array - self.bitcell_array_inst=self.add_inst(name="bitcell_array", - mod=self.bitcell_array) - self.connect_inst(self.all_bitline_names + self.all_wordline_names + self.supplies) - - # Replica columns - self.replica_col_insts = [] - for port in self.all_ports: - if port in self.rbls: - self.replica_col_insts.append(self.add_inst(name="replica_col_{}".format(port), - mod=self.replica_columns[port])) - self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + self.supplies) - else: - self.replica_col_insts.append(None) - - # Dummy rows under the bitcell array (connected with with the replica cell wl) - self.dummy_row_replica_insts = [] - # Note, this is the number of left and right even if we aren't adding the columns to this bitcell array! - for port in self.all_ports: - self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port), - mod=self.dummy_row)) - self.connect_inst([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[port]] + self.supplies) - - # Top/bottom dummy rows or col caps if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): + self.supplies = ["vdd", "gnd"] + + # Used for names/dimensions only + self.cell = factory.create(module_type="bitcell") + + # Main array + self.bitcell_array_inst=self.add_inst(name="bitcell_array", + mod=self.bitcell_array) + self.connect_inst(self.all_bitline_names + self.all_wordline_names + self.supplies) + + # Replica columns + self.replica_col_insts = [] + for port in self.all_ports: + if port in self.rbls: + self.replica_col_insts.append(self.add_inst(name="replica_col_{}".format(port), + mod=self.replica_columns[port])) + self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + self.supplies) + else: + self.replica_col_insts.append(None) + + # Dummy rows under the bitcell array (connected with with the replica cell wl) + self.dummy_row_replica_insts = [] + # Note, this is the number of left and right even if we aren't adding the columns to this bitcell array! + for port in self.all_ports: + self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port), + mod=self.dummy_row)) + self.connect_inst([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[port]] + self.supplies) + + # Top/bottom dummy rows or col caps self.dummy_row_insts = [] self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot", mod=self.col_cap)) @@ -374,22 +352,9 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): mod=self.row_cap_right)) self.connect_inst(self.replica_array_wordline_names + self.supplies) else: - self.dummy_row_insts = [] - self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot", - mod=self.col_cap_bottom)) - self.connect_inst(self.all_bitline_names + self.supplies) - self.dummy_row_insts.append(self.add_inst(name="dummy_row_top", - mod=self.col_cap_top)) - self.connect_inst(self.all_bitline_names + self.supplies) + from tech import custom_replica_bitcell_array_arrangement + custom_replica_bitcell_array_arrangement(self) - # Left/right Dummy columns - self.dummy_col_insts = [] - self.dummy_col_insts.append(self.add_inst(name="dummy_col_left", - mod=self.row_cap_left)) - self.connect_inst(self.replica_array_wordline_names + self.supplies) - self.dummy_col_insts.append(self.add_inst(name="dummy_col_right", - mod=self.row_cap_right)) - self.connect_inst(self.replica_array_wordline_names + self.supplies) def create_layout(self): # We will need unused wordlines grounded, so we need to know their layer diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index 929a37e3..9988096c 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -62,7 +62,11 @@ class replica_column(bitcell_base_array): def add_pins(self): self.create_all_bitline_names() - self.create_all_wordline_names() + #remove 2 wordlines to account for top/bot + if not cell_properties.bitcell.end_caps: + self.create_all_wordline_names() + else: + self.create_all_wordline_names(2) self.add_pin_list(self.all_bitline_names, "OUTPUT") self.add_pin_list(self.all_wordline_names, "INPUT") diff --git a/compiler/tests/missing_pin.gds b/compiler/tests/missing_pin.gds index 25df96f6f8225f45a3de16bfacd9df384fba6796..692677d9eebb55410a246143cdb0049584c034e1 100644 GIT binary patch literal 8520 zcmchcX^0#}6vwNtNm$l632QV53!X6=)b&G*c*QG<37Yl3l68|!WaDNtW~0WaC?24A zpx~Dn)F`4DqDB#n1O!2XibwQ=eh@T*ibhchD2ibG|6kSXsp^@YncWXI^!#RC_rL1Z zt5?<4HKtc^*GPYoB{ovZZ`5XJ@8`G0yXP*7gDT{Z% z^!usj?L2YomTNCJv$Jx2Z^h{cR<0Tu8Cbn;?ZDWo^~0+NM%S(zGwEbwDhI`8x~WXz z=e%lS!eb+TZpEprUrnbPlTI=dtG)Jr)P7jl_FA89dfw{8rPar?)dvn7_!H-SB${{^ z&TExwCru}FDRJ)6OGktW4G1-^Kkd=Ah-*u`Tl-M-WqY4wh z%TLsO6F%sJquRkzeR`eMlhma<>ZIOX_x0yV`+Lj~M?ktpsusp~;P(Y6k30i>z%uz7 zJOSl8W=G;TbV|0H^(tASE4Nv_OIUCGq^(!@1b*+vZ%3AsTx!cBX;1F=h_6mxT7I+~ zH{l?&Eg;HNvix|qEuR$ozB*M0mX^Xm8-{XDes>oIrAN`g-m%sVua23i_%?wf6<}H|W!Tt55&2`kZR- zFW1M1!hg>9Ps;Jx;1ckTT{x zbX}oTJ6Kx(1m@=f|9QmuCwdkqm_7<0y6aRs=+}RJus*xP`pz|pjN2V`@(S%ZeEl+C zFIU|M_3?LBPkM*1U+DWE@3D80P3yPUeSN>^P$A_H{y{KV?5c9(=j{6epi}5>~$sAT-4`$!6??r@&+^mfY(4B> z)~{4MSgL2eypN=g^()n0&@T`2)8(<|HT#o#l84K4zy7nGeu?B4W6Zn&B~SL(Nt@)C zBm0;6rBof*to#vKpP)T*fRZ2hp_G1yT`6%xJe6#J^tg*JDE*7;N-Y=k>%Umqr_YZ) za+ev$_#G4d@kZj4UI~A(ekYSpT|AV#@OusHj`BQ4+;ch|^uB*V`SecS3&@-Cv8Ya2 zC%}{w^>WXIevrA&mEUE|%<%o*+ZXZP@S!&G3hPrh!j0W2JTs=p<}%#}n3XM@v6;tH zcAtcAPgq%Y&8Upl2FJLUz~@zm+Bs6&WNL@TtxSG26H&t7?B0p_n>>#Q?`N&G+AZVq zH+fz9t|R4HAIY)D?L%#czbAKAXQMJoL*=B_JBAHAMA)w!-ZVUVW4;3McJ0vbOX1tW zj=cy7GCWhN{oo+O8}w$_>iI?{Gm}#7!!7g}5!_Xgk%1+WtcV@e4*DZ3tRH%=6shMM zm5f-W+T9AWaRliO8FJnqLGe1axL)33-oVK6 z;I1-yFsIsG#M^k^6THI@+&Vmn0J?Rm-A8isY`O{;7T_d5!HF!%srChd&w-wAo%|GnS!yV`MLYd#EjemWH?5GCwYnT(_yY&!v7Is1NT^m1( zS}O8=%MwMKC=_}QrJbBd;C#0NI9;C5@WQR4Wt>Du*zqE~%JyX9sP}<>_66n1(=b9A zd@9a$O?1pMTb?r2`=X}h!o_Gk*F6!FZ(7+wO7mQ=PV}h5*;JvTy$bcsfp{+P4LI``+sG+?VB?MRGrn z`@KrFgTDWv{%|{Y#w7Oj;>{j0mx?{y*VBD*$-2D%_Mz?UFOvPJ{aMz3J??)6*MHJ) z&};u`f4cr{^xx@q&JUipXouL9E&R{>e+M);^8R0gAIt+1;5sgt&$WKJjE_a`3(0Z7 zL+SKg#`Fa9;(*LHCG!^UF3gSj3|+1$lrPVr^1BQF{}rCO(B0$y|6^nDwjoh~Uxn3k ztuJ30m1x`w7@33BbEYeVSy{M7i(W>c9^@Kr#mGr6W}PXM>2+maJ7xdR5A^Qr|HX9A z&d$NxfgIg3!yk$7$FlxgZyX)6tu3v;v=r{%xKe7jtq)4U%u#56>r&nnUurAD7TI@@ z(kSw6CmS}E8I{{cn$&(;v*(&9G0N>3eQV_fK|HcG=xvC2GCu+B(R^B=+M&vO6( literal 3328 zcmbW3OKgl$6vxl^oTjO&s)m{fTbeLUyoI7HkVrj(dQ6IvN?VN)8Y>&ZLc&5USXf9T zVnHI(g|(H14H6NtV1-2NtoWaE?wRjSXTA|`GV}Ys^WFbB_i^rnQVPR^R1CtxXDZNa zYNge*&VQzkFs-bqoEsi5t(q#WBI=5gjhnBp-ud$3kF^8S%kSSE+DFACU*D5Defh-M zv5|?B!{y1+c)2oqiQ*QbbXG`9C~XgE8TEEVq-E4`iYR`9XQSCiDV~E*1!@|(dq(8) z_{jObYSaOV+M7j<7Hib#Ik=OkO0zH4sIJvD`gjCgd5b22g)wcl(d?kK+Ud7R{H`oM zb!q(Iw(5;$2b=1{0oBK;>WyXxo9g3xs!yJ&-e`8PsXpyjeG8_AXU%AKQ1pM9wQ9ad zzPY3+pTNLczHD_Px54ry`lyi$do{8#zC#r3gU!+EfqqZw`~`E>U$m4c#B^2pUHwOn zRu63CPxE=Z`XVN>Dn8?pKk4^+z01sCH&;SGnESzB9?cH7ydG*Yvx|1w_@J5;o)H?- znPJ9*cz*;2%J4mi_JkLd__xx?{}J{d^lBC1ExaGXyJOmp_YzhHwhbo7558pNdSOxP z3-RduHHs(m9lq3fO!gOD%9yUl`yRx@{4u$>`nmpOK2VRDdZ>$6cELGl zn#-5E__9tAKfb1VquFPypBjCHIpMh!VveGxItN0t7xUvs2M`lQ$Zg=dHgvCgoy9H`}!j@PXdn5h4+zgWk$8izpw8XeW$mRyNZ@K#vJ`o7r(lnS-rv= zU4)3S%ZshOKq4@rfiGSBV9s?d% zW?_?#kJ0R)uh;Q)dWpwz5I2amJw^`fzKgz%sK zk70d8tqanL$>B=HwH?c<*)40n-F5s^a~N8;#&dI=bCYx2$ZdAT@AIIHS@_>MuD7KQ z)$Hw|91S0*+;+sHSzs3gLS+n ztHh&!Mzj+3bow`F|3>37z&ocUrmv~HHRo%(Eslkd`)*Esmy75Zaxvjtyxbrcg9jMt z_0+N;Jw8@)nOLtxmpO|Ezg}51J@}2]: Initializing characterizer... -[characterizer/]: Analytical model enabled. -[verify/]: Initializing verify... -[verify/]: Finding DRC/LVS/PEX tools. -[globals/get_tool]: Using DRC: /usr/local/bin/magic -[globals/get_tool]: Using LVS: /usr/local/bin/netgen -[globals/get_tool]: Using PEX: /usr/local/bin/magic -[globals/get_tool]: Using GDS: /usr/local/bin/magic -[bitcell_base_array/__init__]: Creating replica_bitcell_array 4 x 4 -[replica_bitcell_array/__init__]: Creating replica_bitcell_array 4 x 4 -[bitcell_base_array/__init__]: Creating bitcell_array 4 x 4 -[bitcell_base_array/__init__]: Creating dummy_array 1 x 4 -[verify.magic/run_drc]: Cell replica_bitcell_array has 2074 error tiles. -WARNING: file magic.py: line 210: DRC Errors replica_bitcell_array 2074 +WARNING: file magic.py: line 210: DRC Errors replica_bitcell_array 985 -[verify.magic/run_lvs]: Flattening unmatched subcell s8sram_cell in circuit s8sram_cell_opt1_ce (0)(1 instance) -[verify.magic/run_lvs]: Flattening unmatched subcell s8sram16x16_colend_ce in circuit s8sram16x16_colenda (0)(1 instance) -[verify.magic/run_lvs]: Flattening unmatched subcell s8sram_cell_opt1_ce in circuit s8sram_cell_opt1a (0)(1 instance) -[verify.magic/run_lvs]: Flattening unmatched subcell s8sram_cell_opt1_ce in circuit s8sram_cell_opt1 (0)(1 instance) -[verify.magic/run_lvs]: Flattening unmatched subcell s8_col_cap_array in circuit replica_bitcell_array (0)(1 instance) -[verify.magic/run_lvs]: Flattening unmatched subcell s8_row_cap_array in circuit replica_bitcell_array (0)(1 instance) -[verify.magic/run_lvs]: Flattening unmatched subcell s8_row_cap_array_0 in circuit replica_bitcell_array (0)(1 instance) -[verify.magic/run_lvs]: Flattening unmatched subcell s8_col_cap_array_0 in circuit replica_bitcell_array (0)(1 instance) -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell s8sram16x16_colenda disconnected node: s8sram_colend_met2_0/m2_0_4# -[verify.magic/run_lvs]: Cell s8sram16x16_colenda disconnected node: s8sram_colend_met2_0/m2_0_236# -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell s8sram16x16_colenda disconnected node: bl0 -[verify.magic/run_lvs]: Cell s8sram16x16_colenda disconnected node: bl1 -[verify.magic/run_lvs]: Cell s8sram16x16_colenda disconnected node: vpwr -[verify.magic/run_lvs]: Cell s8sram16x16_colenda disconnected node: vgnd -[verify.magic/run_lvs]: Equate pins: cell s8sram16x16_colenda and/or s8sram16x16_colenda has no elements. -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell s8sram_cell_opt1a disconnected node: s8sram_cell_met2_0/m2_0_59# -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell s8sram_cell_opt1a disconnected node: bl0 -[verify.magic/run_lvs]: Cell s8sram_cell_opt1a disconnected node: bl1 -[verify.magic/run_lvs]: Cell s8sram_cell_opt1a disconnected node: wl0 -[verify.magic/run_lvs]: Cell s8sram_cell_opt1a disconnected node: wl1 -[verify.magic/run_lvs]: Cell s8sram_cell_opt1a disconnected node: vpwr -[verify.magic/run_lvs]: Cell s8sram_cell_opt1a disconnected node: vgnd -[verify.magic/run_lvs]: Equate pins: cell s8sram_cell_opt1a and/or s8sram_cell_opt1a has no elements. -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell s8sram_cell_opt1 disconnected node: s8sram_cell_met2_0/m2_0_59# -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell s8sram_cell_opt1 disconnected node: bl0 -[verify.magic/run_lvs]: Cell s8sram_cell_opt1 disconnected node: bl1 -[verify.magic/run_lvs]: Cell s8sram_cell_opt1 disconnected node: wl0 -[verify.magic/run_lvs]: Cell s8sram_cell_opt1 disconnected node: wl1 -[verify.magic/run_lvs]: Cell s8sram_cell_opt1 disconnected node: vpwr -[verify.magic/run_lvs]: Cell s8sram_cell_opt1 disconnected node: vgnd -[verify.magic/run_lvs]: Equate pins: cell s8sram_cell_opt1 and/or s8sram_cell_opt1 has no elements. -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/polygon00010_0/m1_42_0# -[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/a_113_124# -[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/a_113_124# -[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# -[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/a_113_143# -[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell dummy_array disconnected node: vpwr -[verify.magic/run_lvs]: Cell dummy_array disconnected node: vgnd -[verify.magic/run_lvs]: Class dummy_array: Merged 1 devices. -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/polygon00010_0/m1_42_0# -[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/a_113_124# -[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/a_113_124# -[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# -[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/a_113_143# -[verify.magic/run_lvs]: Cell dummy_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell dummy_array disconnected node: vpwr -[verify.magic/run_lvs]: Cell dummy_array disconnected node: vgnd -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Subcircuit summary: -[verify.magic/run_lvs]: Circuit 1: dummy_array |Circuit 2: dummy_array -[verify.magic/run_lvs]: -------------------------------------------|------------------------------------------- -[verify.magic/run_lvs]: s8sram_cell_opt1a (4) |s8sram_cell_opt1a (4) -[verify.magic/run_lvs]: s8sram_wlstrap (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_wlstrap_p (1) |(no matching element) -[verify.magic/run_lvs]: Number of devices: 6 **Mismatch** |Number of devices: 4 **Mismatch** -[verify.magic/run_lvs]: Number of nets: 20 **Mismatch** |Number of nets: 15 **Mismatch** -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: NET mismatches: Class fragments follow (with fanout counts): -[verify.magic/run_lvs]: Circuit 1: dummy_array |Circuit 2: dummy_array -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Net: bl0_0_3 |Net: col_0_bitcell -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 1 | s8sram_cell_opt1a/bl0 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: bl0_0_2 |Net: col_1_bitcell -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 1 | s8sram_cell_opt1a/bl0 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: bl0_0_1 |Net: col_2_bitcell -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 1 | s8sram_cell_opt1a/bl0 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: bl0_0_0 |Net: col_3_bitcell -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 1 | s8sram_cell_opt1a/bl0 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: bl1_0_3 |Net: bl_0_0 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 1 | s8sram_cell_opt1a/bl1 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: bl1_0_2 |Net: bl_0_1 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 1 | s8sram_cell_opt1a/bl1 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: bl1_0_1 |Net: bl_0_2 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 1 | s8sram_cell_opt1a/bl1 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: bl1_0_0 |Net: bl_0_3 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 1 | s8sram_cell_opt1a/bl1 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_1674_61# |Net: br_0_0 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_1174_61# |Net: br_0_1 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_674_61# |Net: br_0_2 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_38_62# |Net: br_0_3 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_1538_220# |Net: wl0_0_0 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | s8sram_cell_opt1a/wl1 = 4 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_1038_220# |Net: wl1_0_0 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | s8sram_cell_opt1a/vpwr = 4 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_538_220# |Net: vdd -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | s8sram_cell_opt1a/vgnd = 4 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_38_220# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: vpwr |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/vgnd = 4 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/vpwr = 4 | -[verify.magic/run_lvs]: s8sram_wlstrap/1 = 1 | -[verify.magic/run_lvs]: s8sram16x16_wlstrap_p/1 = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_0/vpb |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/vpb = 4 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: VSUBS |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/vnb = 4 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: wl0_0_0 |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 4 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 4 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: DEVICE mismatches: Class fragments follow (with node fanout counts): -[verify.magic/run_lvs]: Circuit 1: dummy_array |Circuit 2: dummy_array -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Instance: s8sram_wlstrap_0 |(no matching instance) -[verify.magic/run_lvs]: 1 = 10 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram16x16_wlstrap_p_0 |(no matching instance) -[verify.magic/run_lvs]: 1 = 10 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_3 |Instance: s8sram_cell_opt1arow_0, -[verify.magic/run_lvs]: bl0 = 1 | bl0 = 1 -[verify.magic/run_lvs]: bl1 = 1 | bl1 = 1 -[verify.magic/run_lvs]: vgnd = 10 | wl0 = 1 -[verify.magic/run_lvs]: vpwr = 10 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 4 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 4 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 4 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_2 |Instance: s8sram_cell_opt1arow_0, -[verify.magic/run_lvs]: bl0 = 1 | bl0 = 1 -[verify.magic/run_lvs]: bl1 = 1 | bl1 = 1 -[verify.magic/run_lvs]: vgnd = 10 | wl0 = 1 -[verify.magic/run_lvs]: vpwr = 10 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 4 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 4 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 4 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_1 |Instance: s8sram_cell_opt1arow_0, -[verify.magic/run_lvs]: bl0 = 1 | bl0 = 1 -[verify.magic/run_lvs]: bl1 = 1 | bl1 = 1 -[verify.magic/run_lvs]: vgnd = 10 | wl0 = 1 -[verify.magic/run_lvs]: vpwr = 10 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 4 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 4 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 4 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_0 |Instance: s8sram_cell_opt1arow_0, -[verify.magic/run_lvs]: bl0 = 1 | bl0 = 1 -[verify.magic/run_lvs]: bl1 = 1 | bl1 = 1 -[verify.magic/run_lvs]: vgnd = 10 | wl0 = 1 -[verify.magic/run_lvs]: vpwr = 10 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 4 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 4 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 4 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Netlists do not match. -[verify.magic/run_lvs]: Flattening non-matched subcircuits dummy_array dummy_array -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/polygon00010_0/m1_42_0# -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/a_113_124# -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/a_113_124# -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/a_113_143# -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: vpwr -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: vgnd -[verify.magic/run_lvs]: Class bitcell_array: Merged 10 devices. -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/polygon00010_0/m1_42_0# -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/a_113_124# -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/a_113_124# -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_0/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram16x16_wlstrap_p_0/s8sram16x16_wlstrap_p_ce_0/a_113_143# -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: s8sram_wlstrap_1/s8sram_wlstrap_ce_0/polygon00006_0/m1_158_122# -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: vpwr -[verify.magic/run_lvs]: Cell bitcell_array disconnected node: vgnd -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Subcircuit summary: -[verify.magic/run_lvs]: Circuit 1: bitcell_array |Circuit 2: bitcell_array -[verify.magic/run_lvs]: -------------------------------------------|------------------------------------------- -[verify.magic/run_lvs]: s8sram_cell_opt1a (8) |s8sram_cell_opt1a (8) -[verify.magic/run_lvs]: s8sram_wlstrap (1) |(no matching element) -[verify.magic/run_lvs]: s8sram_cell_opt1 (8) |s8sram_cell_opt1 (8) -[verify.magic/run_lvs]: s8sram16x16_wlstrap_p (1) |(no matching element) -[verify.magic/run_lvs]: Number of devices: 18 **Mismatch** |Number of devices: 16 **Mismatch** -[verify.magic/run_lvs]: Number of nets: 43 **Mismatch** |Number of nets: 21 **Mismatch** -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: NET mismatches: Class fragments follow (with fanout counts): -[verify.magic/run_lvs]: Circuit 1: bitcell_array |Circuit 2: bitcell_array -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Net: bl1_0_3 |Net: vdd -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 2 | s8sram_cell_opt1a/vgnd = 8 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 2 | s8sram_cell_opt1/vgnd = 8 -[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: bl1_0_2 |Net: col_0_bitcell -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 2 | s8sram_cell_opt1a/bl0 = 2 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 2 | s8sram_cell_opt1/bl0 = 2 -[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: bl1_0_1 |Net: col_1_bitcell -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 2 | s8sram_cell_opt1a/bl0 = 2 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 2 | s8sram_cell_opt1/bl0 = 2 -[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: bl1_0_0 |Net: col_2_bitcell -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 2 | s8sram_cell_opt1a/bl0 = 2 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 2 | s8sram_cell_opt1/bl0 = 2 -[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: vpwr |Net: col_3_bitcell -[verify.magic/run_lvs]: s8sram_cell_opt1a/vgnd = 8 | s8sram_cell_opt1a/bl0 = 2 -[verify.magic/run_lvs]: s8sram_cell_opt1a/vpwr = 8 | s8sram_cell_opt1/bl0 = 2 -[verify.magic/run_lvs]: s8sram_wlstrap/1 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1/vgnd = 8 | -[verify.magic/run_lvs]: s8sram_cell_opt1/vpwr = 8 | -[verify.magic/run_lvs]: s8sram16x16_wlstrap_p/1 = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_0/vpb |Net: bl_0_0 -[verify.magic/run_lvs]: s8sram_cell_opt1a/vpb = 8 | s8sram_cell_opt1a/bl1 = 2 -[verify.magic/run_lvs]: s8sram_cell_opt1/vpb = 8 | s8sram_cell_opt1/bl1 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: VSUBS |Net: bl_0_1 -[verify.magic/run_lvs]: s8sram_cell_opt1a/vnb = 8 | s8sram_cell_opt1a/bl1 = 2 -[verify.magic/run_lvs]: s8sram_cell_opt1/vnb = 8 | s8sram_cell_opt1/bl1 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_0/s8sram_cell_opt1_ |Net: bl_0_2 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/bl1 = 2 -[verify.magic/run_lvs]: | s8sram_cell_opt1/bl1 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_1/s8sram_cell_opt1_ |Net: bl_0_3 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/bl1 = 2 -[verify.magic/run_lvs]: | s8sram_cell_opt1/bl1 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_2/s8sram_cell_opt1_ |Net: br_0_0 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 2 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_3/s8sram_cell_opt1_ |Net: br_0_1 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 2 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_4/s8sram_cell_opt1_ |Net: br_0_2 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 2 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_5/s8sram_cell_opt1_ |Net: br_0_3 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 2 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_6/s8sram_cell_opt1_ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_7/s8sram_cell_opt1_ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_0/s8sram_cell_opt1_ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_1/s8sram_cell_opt1_ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_2/s8sram_cell_opt1_ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_3/s8sram_cell_opt1_ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_4/s8sram_cell_opt1_ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_5/s8sram_cell_opt1_ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_6/s8sram_cell_opt1_ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1a_7/s8sram_cell_opt1_ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_0/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_1/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_2/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_3/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_4/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_5/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_6/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_7/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_0/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_1/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_2/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_3/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_4/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_5/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_6/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_7/s8sram_cell_opt1_c |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_3 -[verify.magic/run_lvs]: | s8sram_cell_opt1/vpwr = 4 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_1 -[verify.magic/run_lvs]: | s8sram_cell_opt1/vpwr = 4 -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_3 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl1 = 4 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_1 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl1 = 4 -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_2 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/vpwr = 4 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_0 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/vpwr = 4 -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_2 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 4 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_0 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 4 -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Net: wl0_0_1 |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 4 | -[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 4 | -[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: wl0_0_3 |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 4 | -[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 4 | -[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Net: wl0_0_0 |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 4 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 4 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: wl0_0_2 |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 4 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 4 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: DEVICE mismatches: Class fragments follow (with node fanout counts): -[verify.magic/run_lvs]: Circuit 1: bitcell_array |Circuit 2: bitcell_array -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Instance: s8sram_wlstrap_0 |(no matching instance) -[verify.magic/run_lvs]: 1 = 34 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram16x16_wlstrap_p_0 |(no matching instance) -[verify.magic/run_lvs]: 1 = 34 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_7 |Instance: s8sram_cell_opt1row_3, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_6 |Instance: s8sram_cell_opt1row_3, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_5 |Instance: s8sram_cell_opt1row_3, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_4 |Instance: s8sram_cell_opt1row_3, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_3 |Instance: s8sram_cell_opt1row_1, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_2 |Instance: s8sram_cell_opt1row_1, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_1 |Instance: s8sram_cell_opt1row_1, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_0 |Instance: s8sram_cell_opt1row_1, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_7 |Instance: s8sram_cell_opt1arow_2, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_6 |Instance: s8sram_cell_opt1arow_2, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_5 |Instance: s8sram_cell_opt1arow_2, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_4 |Instance: s8sram_cell_opt1arow_2, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_3 |Instance: s8sram_cell_opt1arow_0, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_2 |Instance: s8sram_cell_opt1arow_0, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_1 |Instance: s8sram_cell_opt1arow_0, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_0 |Instance: s8sram_cell_opt1arow_0, -[verify.magic/run_lvs]: bl0 = 8 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 8 | bl1 = 4 -[verify.magic/run_lvs]: vgnd = 34 | wl0 = 4 -[verify.magic/run_lvs]: vpwr = 34 | wl1 = 4 -[verify.magic/run_lvs]: vpb = 16 | vpwr = 4 -[verify.magic/run_lvs]: wl1 = 12 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 12 | -[verify.magic/run_lvs]: vnb = 16 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 12 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Netlists do not match. -[verify.magic/run_lvs]: Flattening non-matched subcircuits bitcell_array bitcell_arrayClass replica_column: Merged 4 devices. -[verify.magic/run_lvs]: Class replica_column: Merged 1 devices. -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Subcircuit summary: -[verify.magic/run_lvs]: Circuit 1: replica_column |Circuit 2: replica_column -[verify.magic/run_lvs]: -------------------------------------------|------------------------------------------- -[verify.magic/run_lvs]: s8sram_cell_opt1a (2) |s8sram_cell_opt1a (2) -[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent (1) |(no matching element) -[verify.magic/run_lvs]: s8sram_cell_opt1 (3) |s8sram_cell_opt1 (3) -[verify.magic/run_lvs]: s8sram16x16_colenda (2) |s8sram16x16_colenda (1) **Mismatch** -[verify.magic/run_lvs]: s8sram16x16_wlstrap_p (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_colend_p_cent (1) |(no matching element) -[verify.magic/run_lvs]: Number of devices: 10 **Mismatch** |Number of devices: 6 **Mismatch** -[verify.magic/run_lvs]: Number of nets: 22 **Mismatch** |Number of nets: 14 **Mismatch** -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Flattening instances of s8sram16x16_colenda in cell replica_column makes a better match -[verify.magic/run_lvs]: Flattening instances of s8sram16x16_colenda in cell replica_column makes a better match -[verify.magic/run_lvs]: Making another compare attempt. -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Subcircuit summary: -[verify.magic/run_lvs]: Circuit 1: replica_column |Circuit 2: replica_column -[verify.magic/run_lvs]: -------------------------------------------|------------------------------------------- -[verify.magic/run_lvs]: s8sram_cell_opt1a (2) |s8sram_cell_opt1a (2) -[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent (1) |(no matching element) -[verify.magic/run_lvs]: s8sram_cell_opt1 (3) |s8sram_cell_opt1 (3) -[verify.magic/run_lvs]: nshort (2) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_wlstrap_p (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_colend_p_cent (1) |(no matching element) -[verify.magic/run_lvs]: Number of devices: 10 **Mismatch** |Number of devices: 5 **Mismatch** -[verify.magic/run_lvs]: Number of nets: 22 **Mismatch** |Number of nets: 14 **Mismatch** -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: NET mismatches: Class fragments follow (with fanout counts): -[verify.magic/run_lvs]: Circuit 1: replica_column |Circuit 2: replica_column -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Net: br_0_0 |Net: wl0_0_1 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 2 | s8sram_cell_opt1/wl0 = 1 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 2 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 3 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 3 | -[verify.magic/run_lvs]: nshort/(drain|source) = 4 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: vgnd |Net: wl0_0_3 -[verify.magic/run_lvs]: s8sram_cell_opt1a/vgnd = 2 | s8sram_cell_opt1/wl0 = 1 -[verify.magic/run_lvs]: s8sram_cell_opt1a/vpwr = 2 | -[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent/1 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1/vgnd = 3 | -[verify.magic/run_lvs]: s8sram_cell_opt1/vpwr = 3 | -[verify.magic/run_lvs]: s8sram16x16_wlstrap_p/1 = 1 | -[verify.magic/run_lvs]: s8sram16x16_colend_p_cent/1 = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: wl_0_5 |Net: wl0_0_5 -[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 1 | s8sram_cell_opt1/wl0 = 1 -[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: wl_0_3 |Net: wl1_0_1 -[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 1 | s8sram_cell_opt1/wl1 = 1 -[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: wl_0_1 |Net: wl1_0_3 -[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 1 | s8sram_cell_opt1/wl1 = 1 -[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_38_1737# |Net: wl1_0_5 -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | s8sram_cell_opt1/wl1 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_38_1105# |Net: bl_0_0 -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | s8sram_cell_opt1/bl0 = 3 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/bl0 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_38_473# |Net: br_0_0 -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | s8sram_cell_opt1/bl1 = 3 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/bl1 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_38_1895# |Net: vdd -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | s8sram_cell_opt1/vpwr = 3 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/vpwr = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_38_1263# |Net: gnd -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | s8sram_cell_opt1/vgnd = 3 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/vgnd = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_38_631# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram16x16_colend_p_cent_0/vpb |(no matching net) -[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent/2 = 1 | -[verify.magic/run_lvs]: s8sram16x16_colend_p_cent/2 = 1 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_4 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_2 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 1 -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_4 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl0 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_2 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl0 = 1 -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Net: s8sram16x16_colenda_1/s8sram16x16_col |(no matching net) -[verify.magic/run_lvs]: nshort/gate = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram16x16_colenda_0/s8sram16x16_col |(no matching net) -[verify.magic/run_lvs]: nshort/gate = 1 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Net: a_38_947# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_38_1579# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Net: a_38_789# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: a_38_1421# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Net: wl_0_2 |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: wl_0_4 |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Net: VSUBS |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/vnb = 2 | -[verify.magic/run_lvs]: s8sram_cell_opt1/vnb = 3 | -[verify.magic/run_lvs]: nshort/bulk = 2 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: s8sram_cell_opt1_0/vpb |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/vpb = 2 | -[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent/3 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1/vpb = 3 | -[verify.magic/run_lvs]: s8sram16x16_colend_p_cent/3 = 1 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: DEVICE mismatches: Class fragments follow (with node fanout counts): -[verify.magic/run_lvs]: Circuit 1: replica_column |Circuit 2: replica_column -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Instance: s8sram16x16_colenda_p_cent_0 |(no matching instance) -[verify.magic/run_lvs]: 1 = 13 | -[verify.magic/run_lvs]: 2 = 2 | -[verify.magic/run_lvs]: 3 = 7 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram16x16_wlstrap_p_0 |(no matching instance) -[verify.magic/run_lvs]: 1 = 13 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram16x16_colend_p_cent_0 |(no matching instance) -[verify.magic/run_lvs]: 1 = 13 | -[verify.magic/run_lvs]: 2 = 2 | -[verify.magic/run_lvs]: 3 = 7 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Instance: s8sram16x16_colenda_1//s8sram16x |(no matching instance) -[verify.magic/run_lvs]: (drain,source) = (14,14) | -[verify.magic/run_lvs]: gate = 1 | -[verify.magic/run_lvs]: bulk = 7 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram16x16_colenda_0//s8sram16x |(no matching instance) -[verify.magic/run_lvs]: (drain,source) = (14,14) | -[verify.magic/run_lvs]: gate = 1 | -[verify.magic/run_lvs]: bulk = 7 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_2 |Instance: s8sram_cell_opt1rbc_5 -[verify.magic/run_lvs]: bl0 = 14 | bl0 = 5 -[verify.magic/run_lvs]: bl1 = 14 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 13 | wl0 = 1 -[verify.magic/run_lvs]: vpwr = 13 | wl1 = 1 -[verify.magic/run_lvs]: vpb = 7 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 3 | vgnd = 5 -[verify.magic/run_lvs]: wl0 = 3 | -[verify.magic/run_lvs]: vnb = 7 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 3 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_1 |Instance: s8sram_cell_opt1rbc_3 -[verify.magic/run_lvs]: bl0 = 14 | bl0 = 5 -[verify.magic/run_lvs]: bl1 = 14 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 13 | wl0 = 1 -[verify.magic/run_lvs]: vpwr = 13 | wl1 = 1 -[verify.magic/run_lvs]: vpb = 7 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 3 | vgnd = 5 -[verify.magic/run_lvs]: wl0 = 3 | -[verify.magic/run_lvs]: vnb = 7 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 3 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1_0 |Instance: s8sram_cell_opt1rbc_1 -[verify.magic/run_lvs]: bl0 = 14 | bl0 = 5 -[verify.magic/run_lvs]: bl1 = 14 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 13 | wl0 = 1 -[verify.magic/run_lvs]: vpwr = 13 | wl1 = 1 -[verify.magic/run_lvs]: vpb = 7 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 3 | vgnd = 5 -[verify.magic/run_lvs]: wl0 = 3 | -[verify.magic/run_lvs]: vnb = 7 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 3 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_0 |(no matching instance) -[verify.magic/run_lvs]: bl0 = 14 | -[verify.magic/run_lvs]: bl1 = 14 | -[verify.magic/run_lvs]: vgnd = 13 | -[verify.magic/run_lvs]: vpwr = 13 | -[verify.magic/run_lvs]: vpb = 7 | -[verify.magic/run_lvs]: wl1 = 3 | -[verify.magic/run_lvs]: wl0 = 3 | -[verify.magic/run_lvs]: vnb = 7 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 3 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8sram_cell_opt1a_1 |(no matching instance) -[verify.magic/run_lvs]: bl0 = 14 | -[verify.magic/run_lvs]: bl1 = 14 | -[verify.magic/run_lvs]: vgnd = 13 | -[verify.magic/run_lvs]: vpwr = 13 | -[verify.magic/run_lvs]: vpb = 7 | -[verify.magic/run_lvs]: wl1 = 3 | -[verify.magic/run_lvs]: wl0 = 3 | -[verify.magic/run_lvs]: vnb = 7 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 3 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: (no matching instance) |Instance: s8sram_cell_opt1arbc_2 -[verify.magic/run_lvs]: | bl0 = 5 -[verify.magic/run_lvs]: | bl1 = 5 -[verify.magic/run_lvs]: | wl0 = 1 -[verify.magic/run_lvs]: | wl1 = 1 -[verify.magic/run_lvs]: | vpwr = 5 -[verify.magic/run_lvs]: | vgnd = 5 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: (no matching instance) |Instance: s8sram_cell_opt1arbc_4 -[verify.magic/run_lvs]: | bl0 = 5 -[verify.magic/run_lvs]: | bl1 = 5 -[verify.magic/run_lvs]: | wl0 = 1 -[verify.magic/run_lvs]: | wl1 = 1 -[verify.magic/run_lvs]: | vpwr = 5 -[verify.magic/run_lvs]: | vgnd = 5 -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Netlists do not match. -[verify.magic/run_lvs]: Flattening non-matched subcircuits replica_column replica_column -[verify.magic/run_lvs]: Cell replica_bitcell_array disconnected node: vdd -[verify.magic/run_lvs]: Cell replica_bitcell_array disconnected node: gnd -[verify.magic/run_lvs]: Class replica_bitcell_array: Merged 23 devices. -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell replica_bitcell_array disconnected node: vdd -[verify.magic/run_lvs]: Cell replica_bitcell_array disconnected node: gnd -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Subcircuit summary: -[verify.magic/run_lvs]: Circuit 1: replica_bitcell_array |Circuit 2: replica_bitcell_array -[verify.magic/run_lvs]: -------------------------------------------|------------------------------------------- -[verify.magic/run_lvs]: s8sram16x16_colenda (4) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_colend_p_cent (1) |(no matching element) -[verify.magic/run_lvs]: s8sram_cell_opt1a (14) |s8sram_cell_opt1a (14) -[verify.magic/run_lvs]: s8sram_wlstrap (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_wlstrap_p (1) |(no matching element) -[verify.magic/run_lvs]: s8sram_cell_opt1 (11) |s8sram_cell_opt1 (11) -[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent (1) |(no matching element) -[verify.magic/run_lvs]: nshort (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_corner (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_cornera (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_rowenda (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_rowend (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_cornerb (1) |(no matching element) -[verify.magic/run_lvs]: Number of devices: 39 **Mismatch** |Number of devices: 25 **Mismatch** -[verify.magic/run_lvs]: Number of nets: 62 **Mismatch** |Number of nets: 32 **Mismatch** -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Flattening instances of s8sram16x16_colenda in cell replica_bitcell_array makes a better match -[verify.magic/run_lvs]: Flattening instances of s8sram16x16_colenda in cell replica_bitcell_array makes a better match -[verify.magic/run_lvs]: Making another compare attempt. -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Cell replica_bitcell_array disconnected node: vdd -[verify.magic/run_lvs]: Cell replica_bitcell_array disconnected node: gnd -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: Subcircuit summary: -[verify.magic/run_lvs]: Circuit 1: replica_bitcell_array |Circuit 2: replica_bitcell_array -[verify.magic/run_lvs]: -------------------------------------------|------------------------------------------- -[verify.magic/run_lvs]: nshort (5) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_colend_p_cent (1) |(no matching element) -[verify.magic/run_lvs]: s8sram_cell_opt1a (14) |s8sram_cell_opt1a (14) -[verify.magic/run_lvs]: s8sram_wlstrap (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_wlstrap_p (1) |(no matching element) -[verify.magic/run_lvs]: s8sram_cell_opt1 (11) |s8sram_cell_opt1 (11) -[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_corner (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_cornera (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_rowenda (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_rowend (1) |(no matching element) -[verify.magic/run_lvs]: s8sram16x16_cornerb (1) |(no matching element) -[verify.magic/run_lvs]: Number of devices: 39 **Mismatch** |Number of devices: 25 **Mismatch** -[verify.magic/run_lvs]: Number of nets: 62 **Mismatch** |Number of nets: 32 **Mismatch** -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: NET mismatches: Class fragments follow (with fanout counts): -[verify.magic/run_lvs]: Circuit 1: replica_bitcell_array |Circuit 2: replica_bitcell_array -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Net: dummy_array_0/bl0_0_2 |Net: dummy_arraydummy_row_0/col_0_bitcell -[verify.magic/run_lvs]: nshort/(drain|source) = 2 | s8sram_cell_opt1a/bl0 = 1 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 3 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 3 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: dummy_array_0/bl0_0_3 |Net: dummy_arraydummy_row_0/col_1_bitcell -[verify.magic/run_lvs]: nshort/(drain|source) = 2 | s8sram_cell_opt1a/bl0 = 1 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 3 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 3 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: dummy_array_0/bl0_0_0 |Net: dummy_arraydummy_row_0/col_2_bitcell -[verify.magic/run_lvs]: nshort/(drain|source) = 2 | s8sram_cell_opt1a/bl0 = 1 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 3 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 3 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: dummy_array_0/bl0_0_1 |Net: dummy_arraydummy_row_0/col_3_bitcell -[verify.magic/run_lvs]: nshort/(drain|source) = 2 | s8sram_cell_opt1a/bl0 = 1 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 3 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 3 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 2 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 2 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: rbl_bl_0_0 |Net: bl_0_0 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl0 = 2 | s8sram_cell_opt1a/bl1 = 3 -[verify.magic/run_lvs]: s8sram_cell_opt1a/bl1 = 2 | s8sram_cell_opt1/bl1 = 2 -[verify.magic/run_lvs]: s8sram_cell_opt1/bl0 = 3 | -[verify.magic/run_lvs]: s8sram_cell_opt1/bl1 = 3 | -[verify.magic/run_lvs]: nshort/(drain|source) = 2 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: VSUBS |Net: bl_0_1 -[verify.magic/run_lvs]: nshort/bulk = 5 | s8sram_cell_opt1a/bl1 = 3 -[verify.magic/run_lvs]: s8sram_cell_opt1a/vnb = 14 | s8sram_cell_opt1/bl1 = 2 -[verify.magic/run_lvs]: s8sram_cell_opt1/vnb = 11 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: rbl_wl1_0_0 |Net: bl_0_2 -[verify.magic/run_lvs]: s8sram16x16_colend_p_cent/1 = 1 | s8sram_cell_opt1a/bl1 = 3 -[verify.magic/run_lvs]: s8sram_cell_opt1a/vgnd = 14 | s8sram_cell_opt1/bl1 = 2 -[verify.magic/run_lvs]: s8sram_cell_opt1a/vpwr = 14 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 4 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 4 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | -[verify.magic/run_lvs]: s8sram_wlstrap/1 = 1 | -[verify.magic/run_lvs]: s8sram16x16_wlstrap_p/1 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1/vgnd = 11 | -[verify.magic/run_lvs]: s8sram_cell_opt1/vpwr = 11 | -[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent/1 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | -[verify.magic/run_lvs]: s8sram16x16_corner/1 = 1 | -[verify.magic/run_lvs]: s8sram16x16_cornera/2 = 1 | -[verify.magic/run_lvs]: s8sram16x16_rowenda/1 = 1 | -[verify.magic/run_lvs]: s8sram16x16_rowenda/2 = 1 | -[verify.magic/run_lvs]: s8sram16x16_rowend/1 = 1 | -[verify.magic/run_lvs]: s8sram16x16_rowend/2 = 1 | -[verify.magic/run_lvs]: s8sram16x16_cornerb/1 = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: dummy_array_0/s8sram_cell_opt1a_0/vpb |Net: bl_0_3 -[verify.magic/run_lvs]: nshort/gate = 5 | s8sram_cell_opt1a/bl1 = 3 -[verify.magic/run_lvs]: s8sram16x16_colend_p_cent/2 = 1 | s8sram_cell_opt1/bl1 = 2 -[verify.magic/run_lvs]: s8sram16x16_colend_p_cent/3 = 1 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/vpb = 14 | -[verify.magic/run_lvs]: s8sram_cell_opt1/vpb = 11 | -[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent/2 = 1 | -[verify.magic/run_lvs]: s8sram16x16_colenda_p_cent/3 = 1 | -[verify.magic/run_lvs]: s8sram16x16_corner/2 = 1 | -[verify.magic/run_lvs]: s8sram16x16_corner/3 = 1 | -[verify.magic/run_lvs]: s8sram16x16_cornera/1 = 1 | -[verify.magic/run_lvs]: s8sram16x16_cornera/3 = 1 | -[verify.magic/run_lvs]: s8sram16x16_cornerb/2 = 1 | -[verify.magic/run_lvs]: s8sram16x16_cornerb/3 = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /dummy_array_0/a_1674_61# |Net: br_0_0 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 3 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /dummy_array_0/a_1174_61# |Net: br_0_1 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 3 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /dummy_array_0/a_674_61# |Net: br_0_2 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 3 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /dummy_array_0/a_38_62# |Net: br_0_3 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/wl0 = 3 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_0/ |Net: vpwr -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1/vpwr = 3 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/vpwr = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_1/ |Net: vgnd -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1/vgnd = 3 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/vgnd = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_2/ |Net: rbl_bl_0_0 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1/bl0 = 3 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/bl0 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_3/ |Net: rbl_br_0_0 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1/bl1 = 3 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/bl1 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_4/ |Net: rbl_wl0_0_0 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1/wl0 = 1 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 4 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_5/ |Net: rbl_wl1_0_0 -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1/wl1 = 1 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/vpwr = 4 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_6/ |Net: dummy_arraydummy_row_0/vdd -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/vgnd = 4 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_7/ |Net: /bitcell_array/col_0_bitcell -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/bl0 = 2 -[verify.magic/run_lvs]: | s8sram_cell_opt1/bl0 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /replica_column_0/a_38_1421# |Net: /bitcell_array/col_1_bitcell -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/bl0 = 2 -[verify.magic/run_lvs]: | s8sram_cell_opt1/bl0 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /replica_column_0/a_38_789# |Net: /bitcell_array/col_2_bitcell -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_62# = 1 | s8sram_cell_opt1a/bl0 = 2 -[verify.magic/run_lvs]: | s8sram_cell_opt1/bl0 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /dummy_array_0/a_1538_220# |Net: /bitcell_array/col_3_bitcell -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | s8sram_cell_opt1a/bl0 = 2 -[verify.magic/run_lvs]: | s8sram_cell_opt1/bl0 = 2 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /dummy_array_0/a_1038_220# |Net: /bitcell_array/vdd -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | s8sram_cell_opt1a/vgnd = 8 -[verify.magic/run_lvs]: | s8sram_cell_opt1/vgnd = 8 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /dummy_array_0/a_538_220# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /dummy_array_0/a_38_220# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_0/ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_1/ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_2/ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_3/ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_4/ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_5/ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_6/ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1a_7/ |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /replica_column_0/a_38_1579# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /replica_column_0/a_38_947# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_0/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_1/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_2/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_3/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_4/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_5/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_6/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_7/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /replica_column_0/a_38_1737# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /replica_column_0/a_38_1105# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /replica_column_0/a_38_473# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_62# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_0/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_1/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_2/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_3/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_4/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_5/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_6/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /bitcell_array_0/s8sram_cell_opt1_7/s |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /replica_column_0/a_38_1895# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /replica_column_0/a_38_1263# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: /replica_column_0/a_38_631# |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/a_38_220# = 1 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_3 -[verify.magic/run_lvs]: | s8sram_cell_opt1/vpwr = 4 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl1 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_1 -[verify.magic/run_lvs]: | s8sram_cell_opt1/vpwr = 4 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl1 = 1 -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_3 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl1 = 4 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_1 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl1 = 4 -[verify.magic/run_lvs]: | s8sram_cell_opt1/wl0 = 1 -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_2 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/vpwr = 4 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: (no matching net) |Net: wl1_0_0 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/vpwr = 4 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 1 -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_2 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 4 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl0 = 1 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: (no matching net) |Net: wl0_0_0 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl1 = 4 -[verify.magic/run_lvs]: | s8sram_cell_opt1a/wl0 = 1 -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Net: wl1_0_1 |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 5 | -[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 5 | -[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: wl1_0_3 |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1/wl1 = 5 | -[verify.magic/run_lvs]: s8sram_cell_opt1/wl0 = 5 | -[verify.magic/run_lvs]: s8sram_cell_opt1/s8sram_cell_met2_0/m2_0 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Net: wl1_0_0 |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 5 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 5 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Net: wl1_0_2 |(no matching net) -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl1 = 5 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/wl0 = 5 | -[verify.magic/run_lvs]: s8sram_cell_opt1a/s8sram_cell_met2_0/m2_ | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: DEVICE mismatches: Class fragments follow (with node fanout counts): -[verify.magic/run_lvs]: Circuit 1: replica_bitcell_array |Circuit 2: replica_bitcell_array -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Instance: s8_col_cap_array_0//s8sram16x16_ |(no matching instance) -[verify.magic/run_lvs]: (drain,source) = (12,12) | -[verify.magic/run_lvs]: gate = 40 | -[verify.magic/run_lvs]: bulk = 30 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8_col_cap_array_0//s8sram16x16_ |(no matching instance) -[verify.magic/run_lvs]: (drain,source) = (12,12) | -[verify.magic/run_lvs]: gate = 40 | -[verify.magic/run_lvs]: bulk = 30 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8_col_cap_array_0//s8sram16x16_ |(no matching instance) -[verify.magic/run_lvs]: (drain,source) = (12,12) | -[verify.magic/run_lvs]: gate = 40 | -[verify.magic/run_lvs]: bulk = 30 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8_col_cap_array_0//s8sram16x16_ |(no matching instance) -[verify.magic/run_lvs]: (drain,source) = (12,12) | -[verify.magic/run_lvs]: gate = 40 | -[verify.magic/run_lvs]: bulk = 30 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: replica_column_0//s8sram16x16_co |(no matching instance) -[verify.magic/run_lvs]: (drain,source) = (12,12) | -[verify.magic/run_lvs]: gate = 40 | -[verify.magic/run_lvs]: bulk = 30 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8_col_cap_array_0//s8sram16x16_ |(no matching instance) -[verify.magic/run_lvs]: 1 = 76 | -[verify.magic/run_lvs]: 2 = 40 | -[verify.magic/run_lvs]: 3 = 40 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: dummy_array_0//s8sram_wlstrap_0 |(no matching instance) -[verify.magic/run_lvs]: 1 = 76 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: dummy_array_0//s8sram16x16_wlstr |(no matching instance) -[verify.magic/run_lvs]: 1 = 76 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: replica_column_0//s8sram16x16_co |(no matching instance) -[verify.magic/run_lvs]: 1 = 76 | -[verify.magic/run_lvs]: 2 = 40 | -[verify.magic/run_lvs]: 3 = 40 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8_row_cap_array_0//s8sram16x16_ |(no matching instance) -[verify.magic/run_lvs]: 1 = 76 | -[verify.magic/run_lvs]: 2 = 40 | -[verify.magic/run_lvs]: 3 = 40 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8_row_cap_array_0//s8sram16x16_ |(no matching instance) -[verify.magic/run_lvs]: 1 = 40 | -[verify.magic/run_lvs]: 2 = 76 | -[verify.magic/run_lvs]: 3 = 40 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8_row_cap_array_0//s8sram16x16_ |(no matching instance) -[verify.magic/run_lvs]: 1 = 76 | -[verify.magic/run_lvs]: 2 = 76 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8_row_cap_array_0//s8sram16x16_ |(no matching instance) -[verify.magic/run_lvs]: 1 = 76 | -[verify.magic/run_lvs]: 2 = 76 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: s8_row_cap_array_0_0//s8sram16x1 |(no matching instance) -[verify.magic/run_lvs]: 1 = 76 | -[verify.magic/run_lvs]: 2 = 40 | -[verify.magic/run_lvs]: 3 = 40 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Instance: replica_column_0//s8sram_cell_op |Instance: replica_columnreplica_col_0/s8sr -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 5 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 76 | vgnd = 5 -[verify.magic/run_lvs]: wl0 = 76 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 76 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: replica_column_0//s8sram_cell_op |Instance: bitcell_array/s8sram_cell_opt1ro -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: replica_column_0//s8sram_cell_op |Instance: bitcell_array/s8sram_cell_opt1ro -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ro -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ro -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ro -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ro -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ro -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ro -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |(no matching instance) -[verify.magic/run_lvs]: bl0 = 12 | -[verify.magic/run_lvs]: bl1 = 12 | -[verify.magic/run_lvs]: vgnd = 76 | -[verify.magic/run_lvs]: vpwr = 76 | -[verify.magic/run_lvs]: vpb = 40 | -[verify.magic/run_lvs]: wl1 = 15 | -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |(no matching instance) -[verify.magic/run_lvs]: bl0 = 12 | -[verify.magic/run_lvs]: bl1 = 12 | -[verify.magic/run_lvs]: vgnd = 76 | -[verify.magic/run_lvs]: vpwr = 76 | -[verify.magic/run_lvs]: vpb = 40 | -[verify.magic/run_lvs]: wl1 = 15 | -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: (no matching instance) |Instance: replica_columnreplica_col_0/s8sr -[verify.magic/run_lvs]: | bl0 = 5 -[verify.magic/run_lvs]: | bl1 = 5 -[verify.magic/run_lvs]: | wl0 = 5 -[verify.magic/run_lvs]: | wl1 = 5 -[verify.magic/run_lvs]: | vpwr = 5 -[verify.magic/run_lvs]: | vgnd = 5 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: (no matching instance) |Instance: replica_columnreplica_col_0/s8sr -[verify.magic/run_lvs]: | bl0 = 5 -[verify.magic/run_lvs]: | bl1 = 5 -[verify.magic/run_lvs]: | wl0 = 5 -[verify.magic/run_lvs]: | wl1 = 5 -[verify.magic/run_lvs]: | vpwr = 5 -[verify.magic/run_lvs]: | vgnd = 5 -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Instance: replica_column_0//s8sram_cell_op |Instance: dummy_arraydummy_row_0/s8sram_ce -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 1 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 4 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: replica_column_0//s8sram_cell_op |Instance: dummy_arraydummy_row_0/s8sram_ce -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 1 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 4 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: dummy_arraydummy_row_0/s8sram_ce -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 1 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 4 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: dummy_arraydummy_row_0/s8sram_ce -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 1 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 4 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ar -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ar -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ar -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ar -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ar -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: bitcell_array_0//s8sram_cell_opt |Instance: bitcell_array/s8sram_cell_opt1ar -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 15 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 15 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 15 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: dummy_array_0//s8sram_cell_opt1a |Instance: bitcell_array/s8sram_cell_opt1ar -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 76 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 76 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 76 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: dummy_array_0//s8sram_cell_opt1a |Instance: bitcell_array/s8sram_cell_opt1ar -[verify.magic/run_lvs]: bl0 = 12 | bl0 = 4 -[verify.magic/run_lvs]: bl1 = 12 | bl1 = 5 -[verify.magic/run_lvs]: vgnd = 76 | wl0 = 5 -[verify.magic/run_lvs]: vpwr = 76 | wl1 = 5 -[verify.magic/run_lvs]: vpb = 40 | vpwr = 5 -[verify.magic/run_lvs]: wl1 = 76 | vgnd = 16 -[verify.magic/run_lvs]: wl0 = 76 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 76 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: dummy_array_0//s8sram_cell_opt1a |(no matching instance) -[verify.magic/run_lvs]: bl0 = 12 | -[verify.magic/run_lvs]: bl1 = 12 | -[verify.magic/run_lvs]: vgnd = 76 | -[verify.magic/run_lvs]: vpwr = 76 | -[verify.magic/run_lvs]: vpb = 40 | -[verify.magic/run_lvs]: wl1 = 76 | -[verify.magic/run_lvs]: wl0 = 76 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 76 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: Instance: dummy_array_0//s8sram_cell_opt1a |(no matching instance) -[verify.magic/run_lvs]: bl0 = 12 | -[verify.magic/run_lvs]: bl1 = 12 | -[verify.magic/run_lvs]: vgnd = 76 | -[verify.magic/run_lvs]: vpwr = 76 | -[verify.magic/run_lvs]: vpb = 40 | -[verify.magic/run_lvs]: wl1 = 76 | -[verify.magic/run_lvs]: wl0 = 76 | -[verify.magic/run_lvs]: vnb = 30 | -[verify.magic/run_lvs]: a_38_62# = 1 | -[verify.magic/run_lvs]: s8sram_cell_met2_0/m2_0_59# = 76 | -[verify.magic/run_lvs]: a_38_220# = 1 | -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: (no matching instance) |Instance: replica_columnreplica_col_0/s8sr -[verify.magic/run_lvs]: | bl0 = 5 -[verify.magic/run_lvs]: | bl1 = 5 -[verify.magic/run_lvs]: | wl0 = 5 -[verify.magic/run_lvs]: | wl1 = 5 -[verify.magic/run_lvs]: | vpwr = 5 -[verify.magic/run_lvs]: | vgnd = 5 -[verify.magic/run_lvs]: | -[verify.magic/run_lvs]: (no matching instance) |Instance: replica_columnreplica_col_0/s8sr -[verify.magic/run_lvs]: | bl0 = 5 -[verify.magic/run_lvs]: | bl1 = 5 -[verify.magic/run_lvs]: | wl0 = 5 -[verify.magic/run_lvs]: | wl1 = 5 -[verify.magic/run_lvs]: | vpwr = 5 -[verify.magic/run_lvs]: | vgnd = 5 -[verify.magic/run_lvs]: --------------------------------------------------------------------------------------- -[verify.magic/run_lvs]: Netlists do not match. -[verify.magic/run_lvs]: Netlists do not match. ERROR: file magic.py: line 285: replica_bitcell_array LVS mismatch (results in /home/jesse/output/replica_bitcell_array.lvs.report) diff --git a/missing_pin.gds b/missing_pin.gds index 0bad623f596405237eb17edbd0c140b3f8fecd4a..692677d9eebb55410a246143cdb0049584c034e1 100644 GIT binary patch literal 8520 zcmchcX^0#}6vwNtNm$l632QV53!X6=)b&G*c*QG<37Yl3l68|!WaDNtW~0WaC?24A zpx~Dn)F`4DqDB#n1O!2XibwQ=eh@T*ibhchD2ibG|6kSXsp^@YncWXI^!#RC_rL1Z zt5?<4HKtc^*GPYoB{ovZZ`5XJ@8`G0yXP*7gDT{Z% z^!usj?L2YomTNCJv$Jx2Z^h{cR<0Tu8Cbn;?ZDWo^~0+NM%S(zGwEbwDhI`8x~WXz z=e%lS!eb+TZpEprUrnbPlTI=dtG)Jr)P7jl_FA89dfw{8rPar?)dvn7_!H-SB${{^ z&TExwCru}FDRJ)6OGktW4G1-^Kkd=Ah-*u`Tl-M-WqY4wh z%TLsO6F%sJquRkzeR`eMlhma<>ZIOX_x0yV`+Lj~M?ktpsusp~;P(Y6k30i>z%uz7 zJOSl8W=G;TbV|0H^(tASE4Nv_OIUCGq^(!@1b*+vZ%3AsTx!cBX;1F=h_6mxT7I+~ zH{l?&Eg;HNvix|qEuR$ozB*M0mX^Xm8-{XDes>oIrAN`g-m%sVua23i_%?wf6<}H|W!Tt55&2`kZR- zFW1M1!hg>9Ps;Jx;1ckTT{x zbX}oTJ6Kx(1m@=f|9QmuCwdkqm_7<0y6aRs=+}RJus*xP`pz|pjN2V`@(S%ZeEl+C zFIU|M_3?LBPkM*1U+DWE@3D80P3yPUeSN>^P$A_H{y{KV?5c9(=j{6epi}5>~$sAT-4`$!6??r@&+^mfY(4B> z)~{4MSgL2eypN=g^()n0&@T`2)8(<|HT#o#l84K4zy7nGeu?B4W6Zn&B~SL(Nt@)C zBm0;6rBof*to#vKpP)T*fRZ2hp_G1yT`6%xJe6#J^tg*JDE*7;N-Y=k>%Umqr_YZ) za+ev$_#G4d@kZj4UI~A(ekYSpT|AV#@OusHj`BQ4+;ch|^uB*V`SecS3&@-Cv8Ya2 zC%}{w^>WXIevrA&mEUE|%<%o*+ZXZP@S!&G3hPrh!j0W2JTs=p<}%#}n3XM@v6;tH zcAtcAPgq%Y&8Upl2FJLUz~@zm+Bs6&WNL@TtxSG26H&t7?B0p_n>>#Q?`N&G+AZVq zH+fz9t|R4HAIY)D?L%#czbAKAXQMJoL*=B_JBAHAMA)w!-ZVUVW4;3McJ0vbOX1tW zj=cy7GCWhN{oo+O8}w$_>iI?{Gm}#7!!7g}5!_Xgk%1+WtcV@e4*DZ3tRH%=6shMM zm5f-W+T9AWaRliO8FJnqLGe1axL)33-oVK6 z;I1-yFsIsG#M^k^6THI@+&Vmn0J?Rm-A8isY`O{;7T_d5!HF!%srChd&w-wAo%|GnS!yV`MLYd#EjemWH?5GCwYnT(_yY&!v7Is1NT^m1( zS}O8=%MwMKC=_}QrJbBd;C#0NI9;C5@WQR4Wt>Du*zqE~%JyX9sP}<>_66n1(=b9A zd@9a$O?1pMTb?r2`=X}h!o_Gk*F6!FZ(7+wO7mQ=PV}h5*;JvTy$bcsfp{+P4LI``+sG+?VB?MRGrn z`@KrFgTDWv{%|{Y#w7Oj;>{j0mx?{y*VBD*$-2D%_Mz?UFOvPJ{aMz3J??)6*MHJ) z&};u`f4cr{^xx@q&JUipXouL9E&R{>e+M);^8R0gAIt+1;5sgt&$WKJjE_a`3(0Z7 zL+SKg#`Fa9;(*LHCG!^UF3gSj3|+1$lrPVr^1BQF{}rCO(B0$y|6^nDwjoh~Uxn3k ztuJ30m1x`w7@33BbEYeVSy{M7i(W>c9^@Kr#mGr6W}PXM>2+maJ7xdR5A^Qr|HX9A z&d$NxfgIg3!yk$7$FlxgZyX)6tu3v;v=r{%xKe7jtq)4U%u#56>r&nnUurAD7TI@@ z(kSw6CmS}E8I{{cn$&(;v*(&9G0N>3eQV_fK|HcG=xvC2GCu+B(R^B=+M&vO6( literal 7442 zcmd6sX=q(V6vyW-? z#JUzmL=XhGd{Byt2&GCu#0{&0J5+JO4L4|Az^CHf>WQlce|o zxh0nzkb5Pb;?wZw^vD0LezGww(@?MBa^Fz8=wbdc zQPdeX66#EonQS`DY>cDi-n4Keu*Y3zmxczeU!J_nF8eOqWGn=0@sfWuhAi9+ex6e8 zpg$HW^c*$OJYK;UaM|E-9*HT7Ya=;Na3m1+lT>f=X5UpOLqrP{%o`r>NQ*WLZ>@goyV{3J z!vp2P?dd!|%l6&kwC{pO@g2+tFGb%e)!sNE-?P-WKgUb`1F7eW-COInGk!$88ZekH z_sVFIF(HcGP@ewmdgWqT5l> zO4Nb;2HK?_)xNTZz6EXi9eOZ&6o0RzR6CgKpKqnOUfxdeB={ztm1T4ogAZ}v3134(>Rmaxe#}SA zg#-ro;BN)~eigD@a|&fWFQor)zW682)5y0UWRh~m@+0FuVmv43x7e~9F4Ps`FhMm*2T`qC!F3Dg{OuR+dpwqL3Cs`*~3cz;WvVFEeVxFaal4*K=qV)fd7n@KKQcNk$Qy`Oyj zYO9}?uFRTGcLSx`L0`W$*Z(op{VDi&%+ar@)(0O;PS!hEAoVBJ4*LG3{{F7)9I@WP zOESMmFIhc)mZ&y~U&fAQ{GBCCta4McdQ*Y|vp!*3fZys$ z{VC}su2O8ZzdErVw1c^NuCB~SQtz*>YFGVaV`f#xy%Ja3J+~_Ig=gy%npV|lWaz~R z`KlzERh5k=bMiMNJ=?~msVO7uZJLZh`oG=Zog-)(*OcMW}jl1Qher9p^u03U` zYi=p;*z|!YgZt5A&x-O&*UE`0qx%x&4pk;2agv#B>P@4Wi;s+xY89sdmsG4I0B(eQ*J^M=*E5;8v_>pQcnhn5&1{gxB#3?TffzG%M8( zX7%107QSlbCb|aXn(C-_FjpV6BmWzyGZ^m#ak5aV9jvJjw~9W(tD#=0b}&~To`*WW zg+2g-GWbKJ>n9Fpa8PgBw_V>Q-;WU3LXZP6H8 za!NUDGs`0joY4nT+C6s=WiloQ!J}^{?eFgf8uYiWV5Fhyjx{qj@T1o-b9Ds zUy0uthw^tacujs+GGE*+`N^6wnwuXSSB&FHo=-TwlxhdF?Qwd>w;YEy&gJ;jaSE!v zYJ672Sj-<@D?0mb;a{nCFxNlpOFudOrc#mVe|jx(?{Npj3O+`j8)EeUHAw zcnlm_He)X&zy7%~mL124v6NOR7hk_RFUF#dCvRnrUSlk~K6rTyzZ3+M&>xP`Px7l$ z%T;<>zkU@lSnxQ?Jc&OrK7sdgLrS%SzFyilMhvEYl{x-%qbceb!zy$1Ew+D8H%b45 zhb3ot6ub-l;}~rhd%_#>{3P1wnCK2ywC@UAzSlnXHxv7r{jXFz==YEGudio)sAqjp zKc%fFOrWnHw*D8nXc7Cm?&I-XWc~qt`M)6Td)kRwq>Zg4+6+Cx4_uLG((sgSq}~ zw18cTOrnEP^n3#fboQ!~f2RI+S44Jx6J`CCY6q?Vao$=IukwEa_=H}vvHl>YSd7Z? z^pp7-$i3Mn)RcRG-3Ljv4_351qc1dBwcTf_xBD@v_NIKj-Jg+9_i4L-W52dkyVH-; z@?^ZqnbCdU*H%}a*`&g9#aLzZ!ZB+pR$gs?XU|;T86f9074nmM^D<5Iimq1 P?*BJ>Zp)0GI5vL+uw1`# diff --git a/sram_0.05/sram_16_16_sky130_0.05.log b/sram_0.05/sram_16_16_sky130_0.05.log index 8ca4e621..e8814676 100644 --- a/sram_0.05/sram_16_16_sky130_0.05.log +++ b/sram_0.05/sram_16_16_sky130_0.05.log @@ -6,13 +6,15 @@ [globals/import_tech]: Importing technology: sky130 [globals/import_tech]: Adding technology path: /home/jesse/openram/technology [globals/init_paths]: Creating temp directory: /home/jesse/output/ -[verify/]: Initializing verify... -[verify/]: LVS/DRC/PEX disabled. [characterizer/]: Initializing characterizer... [characterizer/]: Finding spice simulator. +[verify/]: Initializing verify... +[verify/]: LVS/DRC/PEX disabled. +WARNING: file __init__.py: line 79: Did not find Magic. + [globals/setup_bitcell]: Using bitcell: bitcell_1rw_1r |==============================================================================| -|========= OpenRAM v1.1.5 =========| +|========= OpenRAM v1.1.6 =========| |========= =========| |========= VLSI Design and Automation Lab =========| |========= Computer Science and Engineering Department =========| @@ -23,7 +25,7 @@ |========= Temp dir: /home/jesse/output/ =========| |========= See LICENSE for license info =========| |==============================================================================| -** Start: 07/01/2020 04:43:37 +** Start: 10/07/2020 13:40:02 Technology: sky130 Total size: 256 bits Word size: 16 @@ -42,6 +44,7 @@ Performing simulation-based characterization with ngspice [sram_config/recompute_sizes]: Row addr size: 4 Col addr size: 0 Bank addr size: 4 Words per row: 1 Output files are: +/home/jesse/openram/sram_0.05/sram_16_16_sky130_0.05.lvs /home/jesse/openram/sram_0.05/sram_16_16_sky130_0.05.sp /home/jesse/openram/sram_0.05/sram_16_16_sky130_0.05.v /home/jesse/openram/sram_0.05/sram_16_16_sky130_0.05.lib @@ -55,198 +58,11 @@ Output files are: [dff_array/__init__]: Creating data_dff rows=1 cols=16 [dff_array/__init__]: Creating wmask_dff rows=1 cols=2 [bank/__init__]: create sram of size 16 with 16 words -[port_data/__init__]: create data port of size 16 with 1 words per row -[precharge/__init__]: creating precharge cell precharge -[pgate/bin_width]: binning pmos tx, target: 0.44999999999999996, found 0.55 x 1 = 0.55 -[pgate/bin_width]: binning pmos tx, target: 0.55, found 0.55 x 1 = 0.55 -[precharge_array/__init__]: Creating precharge_array -[precharge/__init__]: creating precharge cell precharge_0 -[pgate/bin_width]: binning pmos tx, target: 0.44999999999999996, found 0.55 x 1 = 0.55 -[sense_amp_array/__init__]: Creating sense_amp_array -[sense_amp/__init__]: Create sense_amp -[write_driver_array/__init__]: Creating write_driver_array -[write_driver/__init__]: Create write_driver -[write_mask_and_array/__init__]: Creating write_mask_and_array -[pand2/__init__]: Creating pand2 pand2 -[pnand2/__init__]: creating pnand2 structure pnand2 with size of 1 -[pgate/bin_width]: binning nmos tx, target: 0.72, found 0.74 x 1 = 0.74 -[pgate/bin_width]: binning pmos tx, target: 1.08, found 1.12 x 1 = 1.12 -[pgate/bin_width]: binning nmos tx, target: 0.74, found 0.74 x 1 = 0.74 -[pgate/bin_width]: binning nmos tx, target: 0.74, found 0.74 x 1 = 0.74 -[pgate/bin_width]: binning pmos tx, target: 1.12, found 1.12 x 1 = 1.12 -[pdriver/__init__]: creating pdriver pdriver -[pinv/__init__]: creating pinv structure pinv with size of 2.0 -[pgate/bin_width]: binning nmos tx, target: 0.36, found 0.36 x 1 = 0.36 -[pgate/bin_width]: binning pmos tx, target: 0.36, found 0.42 x 1 = 0.42 -[pinv/determine_tx_mults]: Height avail 4.6100 PMOS 2.2000 NMOS 2.2000 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 2.16, found 1.12 x 2 = 2.24 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 0.72, found 0.74 x 1 = 0.74 -[pinv/determine_tx_mults]: pinv bin count: 2 pinv bin error: 0.06481481481481488 percent error 0.03240740740740744 -[pgate/bin_width]: binning nmos tx, target: 0.74, found 0.74 x 1 = 0.74 -[pgate/bin_width]: binning pmos tx, target: 1.12, found 1.12 x 1 = 1.12 -[port_data/__init__]: create data port of size 16 with 1 words per row -[precharge_array/__init__]: Creating precharge_array_0 -[precharge/__init__]: creating precharge cell precharge_1 -[pgate/bin_width]: binning pmos tx, target: 0.44999999999999996, found 0.55 x 1 = 0.55 [port_address/__init__]: create data port of cols 16 rows 16 [and2_dec/__init__]: Creating and2_dec and2_dec [pinv_dec/__init__]: creating pinv_dec structure pinv_dec with size of 1 [pinv/__init__]: creating pinv structure pinv_dec with size of 1 -[pgate/bin_width]: binning nmos tx, target: 0.36, found 0.36 x 1 = 0.36 -[pgate/bin_width]: binning pmos tx, target: 1.08, found 1.12 x 1 = 1.12 -[pgate/bin_width]: binning nmos tx, target: 0.36, found 0.36 x 1 = 0.36 -[pgate/bin_width]: binning pmos tx, target: 1.12, found 1.12 x 1 = 1.12 +[pgate/best_bin]: binning nmos tx, target: 0.36, found 1 x 0.36 = 0.36 +[pgate/best_bin]: binning pmos tx, target: 1.12, found 1 x 1.12 = 1.12 [and3_dec/__init__]: Creating and3_dec and3_dec -[wordline_driver_array/__init__]: Creating wordline_driver_array -[wordline_driver/__init__]: Creating wordline_driver wordline_driver -[pinv_dec/__init__]: creating pinv_dec structure pinv_dec_0 with size of 16 -[pinv/__init__]: creating pinv structure pinv_dec_0 with size of 16 -[pgate/bin_width]: binning nmos tx, target: 5.76, found 7.0 x 1 = 7.0 -[pgate/bin_width]: binning pmos tx, target: 17.28, found 7.0 x 3 = 21.0 -[pgate/bin_width]: binning nmos tx, target: 7.0, found 7.0 x 1 = 7.0 -[pgate/bin_width]: binning pmos tx, target: 7.0, found 7.0 x 1 = 7.0 -[replica_bitcell_array/__init__]: Creating replica_bitcell_array 16 x 16 -[bitcell_base_array/__init__]: Creating bitcell_array 16 x 16 -[replica_bitcell_1rw_1r/__init__]: Create replica bitcell 1rw+1r object -[dummy_bitcell_1rw_1r/__init__]: Create dummy bitcell 1rw+1r object -[col_cap_bitcell_1rw_1r/__init__]: Create col_cap bitcell 1rw+1r object -[bitcell_base_array/__init__]: Creating dummy_array 1 x 16 -[bitcell_base_array/__init__]: Creating col_cap_array 1 x 16 -[bitcell_base_array/__init__]: Creating row_cap_array 20 x 1 -[row_cap_bitcell_1rw_1r/__init__]: Create row_cap bitcell 1rw+1r object -[bitcell_base_array/__init__]: Creating row_cap_array_0 20 x 1 -[control_logic/__init__]: Creating control_logic_rw -[dff_buf/__init__]: Creating dff_buf -[pinv/__init__]: creating pinv structure pinv_0 with size of 2 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 2.16, found 1.12 x 2 = 2.24 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 0.72, found 0.74 x 1 = 0.74 -[pinv/determine_tx_mults]: pinv bin count: 4 pinv bin error: 0.12962962962962976 percent error 0.03240740740740744 -[pinv/__init__]: creating pinv structure pinv_1 with size of 4 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 4.32, found 1.6499999999999997 x 3 = 4.949999999999999 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 1.44, found 1.68 x 1 = 1.68 -[pinv/determine_tx_mults]: pinv bin count: 6 pinv bin error: 0.44212962962962954 percent error 0.07368827160493825 -[pgate/bin_width]: binning nmos tx, target: 1.68, found 1.68 x 1 = 1.68 -[pgate/bin_width]: binning pmos tx, target: 1.6499999999999997, found 1.65 x 1 = 1.65 -[dff_buf_array/__init__]: Creating dff_buf_array -[dff_buf/__init__]: Creating dff_buf_0 -[pand2/__init__]: Creating pand2 pand2_0 -[pnand2/__init__]: creating pnand2 structure pnand2_0 with size of 1 -[pgate/bin_width]: binning nmos tx, target: 0.72, found 0.74 x 1 = 0.74 -[pgate/bin_width]: binning pmos tx, target: 1.08, found 1.12 x 1 = 1.12 -[pdriver/__init__]: creating pdriver pdriver_0 -[pinv/__init__]: creating pinv structure pinv_2 with size of 12 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 12.959999999999999, found 2.0 x 7 = 14.0 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 4.32, found 1.68 x 3 = 5.04 -[pinv/determine_tx_mults]: pinv bin count: 8 pinv bin error: 0.6890432098765432 percent error 0.0861304012345679 -[pgate/bin_width]: binning nmos tx, target: 1.68, found 1.68 x 1 = 1.68 -[pgate/bin_width]: binning pmos tx, target: 2.0, found 2.0 x 1 = 2.0 -[pbuf/__init__]: creating pbuf with size of 16 -[pinv/__init__]: creating pinv structure pinv_3 with size of 16 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 17.28, found 2.0 x 9 = 18.0 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 5.76, found 2.0 x 3 = 6.0 -[pinv/determine_tx_mults]: pinv bin count: 10 pinv bin error: 0.7723765432098766 percent error 0.07723765432098766 -[pgate/bin_width]: binning nmos tx, target: 2.0, found 2.0 x 1 = 2.0 -[pgate/bin_width]: binning pmos tx, target: 2.0, found 2.0 x 1 = 2.0 -[pdriver/__init__]: creating pdriver pdriver_1 -[pinv/__init__]: creating pinv structure pinv_4 with size of 1 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 1.08, found 1.12 x 1 = 1.12 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 0.36, found 0.36 x 1 = 0.36 -[pinv/determine_tx_mults]: pinv bin count: 12 pinv bin error: 0.8094135802469137 percent error 0.0674511316872428 -[pinv/__init__]: creating pinv structure pinv_5 with size of 1 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 1.08, found 1.12 x 1 = 1.12 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 0.36, found 0.36 x 1 = 0.36 -[pinv/determine_tx_mults]: pinv bin count: 14 pinv bin error: 0.8464506172839508 percent error 0.06046075837742505 -[pinv/__init__]: creating pinv structure pinv_6 with size of 4 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 4.32, found 1.6499999999999997 x 3 = 4.949999999999999 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 1.44, found 1.68 x 1 = 1.68 -[pinv/determine_tx_mults]: pinv bin count: 16 pinv bin error: 1.1589506172839505 percent error 0.07243441358024691 -[pinv/__init__]: creating pinv structure pinv_7 with size of 13 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 14.04, found 2.0 x 8 = 16.0 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 4.68, found 1.68 x 3 = 5.04 -[pinv/determine_tx_mults]: pinv bin count: 18 pinv bin error: 1.3754748338081673 percent error 0.07641526854489818 -[pgate/bin_width]: binning nmos tx, target: 1.68, found 1.68 x 1 = 1.68 -[pgate/bin_width]: binning pmos tx, target: 2.0, found 2.0 x 1 = 2.0 -[pinv/__init__]: creating pinv structure pinv_8 with size of 38 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 41.04, found 2.0 x 21 = 42.0 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 13.68, found 2.0 x 7 = 14.0 -[pinv/determine_tx_mults]: pinv bin count: 20 pinv bin error: 1.4222584595391614 percent error 0.07111292297695807 -[pgate/bin_width]: binning nmos tx, target: 2.0, found 2.0 x 1 = 2.0 -[pgate/bin_width]: binning pmos tx, target: 2.0, found 2.0 x 1 = 2.0 -[pdriver/__init__]: creating pdriver pdriver_2 -[pinv/__init__]: creating pinv structure pinv_9 with size of 2 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 2.16, found 1.12 x 2 = 2.24 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 0.72, found 0.74 x 1 = 0.74 -[pinv/determine_tx_mults]: pinv bin count: 22 pinv bin error: 1.4870732743539763 percent error 0.06759423974336255 -[pinv/__init__]: creating pinv structure pinv_10 with size of 5 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 5.3999999999999995, found 2.0 x 3 = 6.0 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 1.7999999999999998, found 2.0 x 1 = 2.0 -[pinv/determine_tx_mults]: pinv bin count: 24 pinv bin error: 1.7092954965761986 percent error 0.07122064569067495 -[pgate/bin_width]: binning nmos tx, target: 2.0, found 2.0 x 1 = 2.0 -[pgate/bin_width]: binning pmos tx, target: 2.0, found 2.0 x 1 = 2.0 -[pand3/__init__]: Creating pand3 pand3 -[pnand3/__init__]: creating pnand3 structure pnand3 with size of 1 -[pgate/bin_width]: binning nmos tx, target: 0.72, found 0.74 x 1 = 0.74 -[pgate/bin_width]: binning pmos tx, target: 1.08, found 1.12 x 1 = 1.12 -[pgate/bin_width]: binning nmos tx, target: 0.74, found 0.74 x 1 = 0.74 -[pdriver/__init__]: creating pdriver pdriver_3 -[pinv/__init__]: creating pinv structure pinv_11 with size of 24 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 25.919999999999998, found 2.0 x 13 = 26.0 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 8.64, found 2.0 x 5 = 10.0 -[pinv/determine_tx_mults]: pinv bin count: 26 pinv bin error: 1.8697893237366925 percent error 0.07191497398987279 -[pgate/bin_width]: binning nmos tx, target: 2.0, found 2.0 x 1 = 2.0 -[pgate/bin_width]: binning pmos tx, target: 2.0, found 2.0 x 1 = 2.0 -[pand3/__init__]: Creating pand3 pand3_0 -[pdriver/__init__]: creating pdriver pdriver_4 -[pinv/__init__]: creating pinv structure pinv_12 with size of 16 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 17.28, found 2.0 x 9 = 18.0 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 5.76, found 2.0 x 3 = 6.0 -[pinv/determine_tx_mults]: pinv bin count: 28 pinv bin error: 1.9531226570700257 percent error 0.06975438060964377 -[pinv/__init__]: creating pinv structure pinv_13 with size of 1 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 1.08, found 1.12 x 1 = 1.12 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 0.36, found 0.36 x 1 = 0.36 -[pinv/determine_tx_mults]: pinv bin count: 30 pinv bin error: 1.9901596941070627 percent error 0.06633865647023543 -[pnand2/__init__]: creating pnand2 structure pnand2_1 with size of 1 -[pgate/bin_width]: binning nmos tx, target: 0.72, found 0.74 x 1 = 0.74 -[pgate/bin_width]: binning pmos tx, target: 1.08, found 1.12 x 1 = 1.12 -[delay_chain/__init__]: creating delay chain [4, 4, 4, 4, 4, 4, 4, 4, 4] -[pinv/__init__]: creating pinv structure pinv_14 with size of 1 -[pinv/determine_tx_mults]: Height avail 4.6100 PMOS 2.2000 NMOS 2.2000 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 1.08, found 1.12 x 1 = 1.12 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 0.36, found 0.36 x 1 = 0.36 -[pinv/determine_tx_mults]: pinv bin count: 32 pinv bin error: 2.0271967311441 percent error 0.06334989784825312 -[control_logic/__init__]: Creating control_logic_r -[dff_buf_array/__init__]: Creating dff_buf_array_0 -[pdriver/__init__]: creating pdriver pdriver_5 -[pinv/__init__]: creating pinv structure pinv_15 with size of 12 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 12.959999999999999, found 2.0 x 7 = 14.0 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 4.32, found 1.68 x 3 = 5.04 -[pinv/determine_tx_mults]: pinv bin count: 34 pinv bin error: 2.2741103113910133 percent error 0.06688559739385333 -[pinv/__init__]: creating pinv structure pinv_16 with size of 37 -[pinv/determine_tx_mults]: Height avail 6.0800 PMOS 2.9350 NMOS 2.9350 -[pinv/determine_tx_mults]: prebinning pmos tx, target: 39.96, found 2.0 x 20 = 40.0 -[pinv/determine_tx_mults]: prebinning nmos tx, target: 13.32, found 2.0 x 7 = 14.0 -[pinv/determine_tx_mults]: pinv bin count: 36 pinv bin error: 2.3261623634430655 percent error 0.06461562120675182 -[pgate/bin_width]: binning nmos tx, target: 2.0, found 2.0 x 1 = 2.0 -[pgate/bin_width]: binning pmos tx, target: 2.0, found 2.0 x 1 = 2.0 -** Submodules: 8.6 seconds -** Placement: 0.0 seconds -*** Init supply router: 56.2 seconds -[supply_hannan_router/route]: Running hannan supply router on vdd and gnd... -[supply_hannan_router/retrieve_pins]: Retrieving pins for vdd. -[supply_hannan_router/retrieve_pins]: Retrieving pins for gnd. -[supply_hannan_router/route]: Building matrix +[and4_dec/__init__]: Creating and4_dec and4_dec diff --git a/sram_1b_16_1rw_sky130.log b/sram_1b_16_1rw_sky130.log index 9b298b1e..f57734de 100644 --- a/sram_1b_16_1rw_sky130.log +++ b/sram_1b_16_1rw_sky130.log @@ -13,6 +13,7 @@ [globals/get_tool]: Using PEX: /usr/local/bin/magic [globals/get_tool]: Using GDS: /usr/local/bin/magic [bitcell_base_array/__init__]: Creating replica_bitcell_array 4 x 4 -[replica_bitcell_array/__init__]: Creating replica_bitcell_array 4 x 4 +[replica_bitcell_array/__init__]: Creating replica_bitcell_array 4 x 4 rbls: [1, 0] left_rbl: None right_rbl: None [bitcell_base_array/__init__]: Creating bitcell_array 4 x 4 -[bitcell_base_array/__init__]: Creating dummy_array 1 x 4 +[bitcell_array/__init__]: Creating bitcell_array 4 x 4 +[bitcell_base_array/__init__]: Creating replica_column 7 x 1 From 1e7ae06b7e52df715a000132513e71c96e36287d Mon Sep 17 00:00:00 2001 From: jcirimel Date: Thu, 8 Oct 2020 05:32:03 -0700 Subject: [PATCH 83/83] fix extra wl in col end, work on bring wl pins out to row end array, TODO: mirror alternating row end --- compiler/custom/s8_row_cap_array.py | 46 ++++++------ compiler/custom/s8_row_end.py | 10 ++- compiler/modules/bitcell_base_array.py | 84 ++++++++-------------- compiler/modules/replica_bitcell_array.py | 60 +++++++++++----- compiler/tests/missing_pin.gds | Bin 8520 -> 3444 bytes compiler/tests/sram_1b_16_1rw_sky130.log | 2 +- missing_pin.gds | Bin 8520 -> 3444 bytes sram_1b_16_1rw_sky130.log | 1 + 8 files changed, 101 insertions(+), 102 deletions(-) diff --git a/compiler/custom/s8_row_cap_array.py b/compiler/custom/s8_row_cap_array.py index ab3dce1c..e19db1be 100644 --- a/compiler/custom/s8_row_cap_array.py +++ b/compiler/custom/s8_row_cap_array.py @@ -73,24 +73,24 @@ class s8_row_cap_array(design.design): if alternate_bitcell == 0: row_layout.append(self.rowend1) self.cell_inst[row]=self.add_inst(name=name, mod=self.rowend1) - #self.connect_inst(self.get_bitcell_pins(row, 0)) + self.connect_inst(["wl_0_{}".format(row-1), "vpwr"]) alternate_bitcell = 1 else: row_layout.append(self.rowend2) self.cell_inst[row]=self.add_inst(name=name,mod=self.rowend2) - #self.connect_inst(self.get_bitcell_pins(row, 0)) + self.connect_inst(["wl_0_{}".format(row-1), "vpwr"]) alternate_bitcell = 0 elif (row == 0): row_layout.append(self.bottom_corner) self.cell_inst[row]=self.add_inst(name=name, mod=self.bottom_corner) - #self.connect_inst(self.get_bitcell_pins_col_cap(row, 0)) + self.connect_inst([]) elif (row == self.rows - 1): row_layout.append(self.top_corner) self.cell_inst[row]=self.add_inst(name=name, mod=self.top_corner) - #self.connect_inst(self.get_bitcell_pins_col_cap(row, 0)) + self.connect_inst([]) self.array_layout.append(row_layout) @@ -118,9 +118,9 @@ class s8_row_cap_array(design.design): if inst.width > self.width: self.width = inst.width yoffset = 0.0 - for row in range(0, len(self.array_layout)): - xoffset = 0.0 + xoffset = 0.0 + for col in range(0, len(self.array_layout[row])): inst = self.insts[col + row*len(self.array_layout[row])] inst.place(offset=[xoffset, yoffset]) @@ -138,25 +138,25 @@ class s8_row_cap_array(design.design): def add_layout_pins(self): """ Add the layout pins """ - return - row_list = self.cell.get_all_wl_names() + if self.column_offset == 0: + row_list = self.cell.get_all_wl_names() - for row in range(1, self.row_size - 1): - for cell_row in row_list: - wl_pin = self.cell_inst[row, 0].get_pin(cell_row) - self.add_layout_pin(text=cell_row + "_{0}".format(row), - layer=wl_pin.layer, - offset=wl_pin.ll().scale(0, 1), - width=self.width, - height=wl_pin.height()) + for row in range(1, self.rows-1): + if row > 0 and row < self.rows: + for cell_row in row_list: + wl_pin = self.cell_inst[row].get_pin(cell_row) + self.add_layout_pin(text=cell_row + "_0_{0}".format(row), + layer=wl_pin.layer, + offset=wl_pin.ll().scale(0, 1), + width=self.width, + height=wl_pin.height()) - # Add vdd/gnd via stacks - for row in range(1, self.row_size - 1): - for col in range(self.column_size): - inst = self.cell_inst[row, col] - for pin_name in ["vdd", "gnd"]: + # Add vdd/gnd via stacks + for row in range(1, self.rows): + inst = self.cell_inst[row] + for pin_name in ["vpwr", "vgnd"]: for pin in inst.get_pins(pin_name): self.add_power_pin(name=pin.name, - loc=pin.center(), - start_layer=pin.layer) + loc=pin.center(), + start_layer=pin.layer) diff --git a/compiler/custom/s8_row_end.py b/compiler/custom/s8_row_end.py index e9902397..d02ca709 100644 --- a/compiler/custom/s8_row_end.py +++ b/compiler/custom/s8_row_end.py @@ -17,8 +17,8 @@ class s8_row_end(design.design): def __init__(self, version, name=""): super().__init__(name) - pin_names = [] - type_list = [] + pin_names = ["wl", "vpwr"] + type_list = ["OUTPUT", "POWER"] if version == "rowend": self.name = "s8sram16x16_rowend" @@ -31,4 +31,8 @@ class s8_row_end(design.design): GDS["unit"], layer["mem"], "s8sram16x16_rowend_ce\x00") - pin_map = utils.get_libcell_pins(pin_names, self.name, GDS["unit"]) + self.pin_map = utils.get_libcell_pins(pin_names, self.name, GDS["unit"]) + + + self.add_pin("wl", "OUTPUT") + self.add_pin("vpwr", "POWER") diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index ffc3bb0f..ff2ff5a0 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -64,7 +64,7 @@ class bitcell_base_array(design.design): else: self.wordline_names[port].append("wl0_{0}_{1}".format(port, row)) self.wordline_names[port].append("wl1_{0}_{1}".format(port, row)) - + self.all_wordline_names = [x for sl in zip(*self.wordline_names) for x in sl] def add_pins(self): @@ -147,32 +147,33 @@ class bitcell_base_array(design.design): def add_layout_pins(self): """ Add the layout pins """ - if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): - bitline_names = self.cell.get_all_bitline_names() - for col in range(self.column_size): - for port in self.all_ports: - bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port]) - self.add_layout_pin(text="bl_{0}_{1}".format(port, col), - layer=bl_pin.layer, - offset=bl_pin.ll().scale(1, 0), - width=bl_pin.width(), - height=self.height) - br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1]) - self.add_layout_pin(text="br_{0}_{1}".format(port, col), - layer=br_pin.layer, - offset=br_pin.ll().scale(1, 0), - width=br_pin.width(), - height=self.height) + bitline_names = self.cell.get_all_bitline_names() + for col in range(self.column_size): + for port in self.all_ports: + bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port]) + self.add_layout_pin(text="bl_{0}_{1}".format(port, col), + layer=bl_pin.layer, + offset=bl_pin.ll().scale(1, 0), + width=bl_pin.width(), + height=self.height) + br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1]) + self.add_layout_pin(text="br_{0}_{1}".format(port, col), + layer=br_pin.layer, + offset=br_pin.ll().scale(1, 0), + width=br_pin.width(), + height=self.height) - wl_names = self.cell.get_all_wl_names() - for row in range(self.row_size): - for port in self.all_ports: - wl_pin = self.cell_inst[row, 0].get_pin(wl_names[port]) - self.add_layout_pin(text="wl_{0}_{1}".format(port, row), - layer=wl_pin.layer, - offset=wl_pin.ll().scale(0, 1), - width=self.width, - height=wl_pin.height()) + wl_names = self.cell.get_all_wl_names() + for row in range(self.row_size): + for port in self.all_ports: + wl_pin = self.cell_inst[row, 0].get_pin(wl_names[port]) + self.add_layout_pin(text="wl_{0}_{1}".format(port, row), + layer=wl_pin.layer, + offset=wl_pin.ll().scale(0, 1), + width=self.width, + height=wl_pin.height()) + + if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): # Copy a vdd/gnd layout pin from every cell for row in range(self.row_size): @@ -181,37 +182,8 @@ class bitcell_base_array(design.design): for pin_name in ["vdd", "gnd"]: self.copy_layout_pin(inst, pin_name) else: - bitline_names = self.cell.get_all_bitline_names() - for col in range(self.column_size): - for port in self.all_ports: - bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port]) - self.add_layout_pin(text="bl0_{0}_{1}".format(port, col), - layer=bl_pin.layer, - offset=bl_pin.ll().scale(1, 0), - width=bl_pin.width(), - height=self.height) - br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1]) - self.add_layout_pin(text="bl1_{0}_{1}".format(port, col), - layer=br_pin.layer, - offset=br_pin.ll().scale(1, 0), - width=br_pin.width(), - height=self.height) - wl_names = self.cell.get_all_wl_names() - for row in range(self.row_size): - for port in self.all_ports: - wl0_pin = self.cell_inst[row, 0].get_pin(wl_names[port]) - self.add_layout_pin(text="wl0_{0}_{1}".format(port, row), - layer=wl0_pin.layer, - offset=wl0_pin.ll().scale(0, 1), - width=self.width, - height=wl0_pin.height()) - wl1_pin = self.cell_inst[row, 0].get_pin(wl_names[port]) - self.add_layout_pin(text="wl1_{0}_{1}".format(port, row), - layer=wl1_pin.layer, - offset=wl1_pin.ll().scale(0, 1), - width=self.width, - height=wl1_pin.height()) + # Copy a vdd/gnd layout pin from every cell for row in range(self.row_size): for col in range(self.column_size): diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 816a5391..dbd724c7 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -502,26 +502,18 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): def add_layout_pins(self): """ Add the layout pins """ - # All wordlines - # Main array wl and bl/br - for pin_name in self.all_wordline_names: - pin_list = self.bitcell_array_inst.get_pins(pin_name) - for pin in pin_list: - self.add_layout_pin(text=pin_name, - layer=pin.layer, - offset=pin.ll().scale(0, 1), - width=self.width, - height=pin.height()) - - for pin_name in self.all_bitline_names: - pin_list = self.bitcell_array_inst.get_pins(pin_name) - for pin in pin_list: - self.add_layout_pin(text=pin_name, - layer=pin.layer, - offset=pin.ll().scale(1, 0), - width=pin.width(), - height=self.height) + #All wordlines + #Main array wl and bl/br + if not cell_properties.compare_ports(cell_properties.bitcell_array.use_custom_cell_arrangement): + for pin_name in self.all_wordline_names: + pin_list = self.bitcell_array_inst.get_pins(pin_name) + for pin in pin_list: + self.add_layout_pin(text=pin_name, + layer=pin.layer, + offset=pin.ll().scale(0, 1), + width=self.width, + height=pin.height()) # Replica wordlines (go by the row instead of replica column because we may have to add a pin # even though the column is in another local bitcell array) for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): @@ -534,6 +526,36 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array): offset=pin.ll().scale(0, 1), width=self.width, height=pin.height()) + else: + for pin_name in self.all_wordline_names: + pin_list = self.dummy_col_insts[0].get_pins(pin_name) + for pin in pin_list: + self.add_layout_pin(text=pin_name, + layer=pin.layer, + offset=pin.ll().scale(0, 1), + width=self.width, + height=pin.height()) + # Replica wordlines (go by the row instead of replica column because we may have to add a pin + # even though the column is in another local bitcell array) + for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): + for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()): + if wl_name in self.gnd_wordline_names: + continue + pin = inst.get_pin(pin_name) + self.add_layout_pin(text=wl_name, + layer=pin.layer, + offset=pin.ll().scale(0, 1), + width=self.width, + height=pin.height()) + + for pin_name in self.all_bitline_names: + pin_list = self.bitcell_array_inst.get_pins(pin_name) + for pin in pin_list: + self.add_layout_pin(text=pin_name, + layer=pin.layer, + offset=pin.ll().scale(1, 0), + width=pin.width(), + height=self.height) # Replica bitlines if len(self.rbls) > 0: diff --git a/compiler/tests/missing_pin.gds b/compiler/tests/missing_pin.gds index 692677d9eebb55410a246143cdb0049584c034e1..69d112e423b42ca89bfa29d91a6b37c4cd272f15 100644 GIT binary patch literal 3444 zcmai%PiR#~6voe;`^QvLjq-eA43<(*(TJp=rWCZs)QutpS}LN3su826YEqlfx@n=P zbk|kEg+C!z(sp{*i~G~d4S^0qxUuKoAc==|ny zuN-(!2J(7+e-ZTK(`RNUJ~}pjc4%sRX7W>!tVg7H)yeBpEOD|?2K!R+Z8C5UyonD< z`=n&cy6E$zUZ1b=`jWISt=A`0BC0n+pI*Z=Nqf*QlCGII+cTe<`1s8->ru;ku*y0c z_M^`J0QVq0lJ?=2QMc&b4rqQCQ6@*he=5=r#2h_BrhX$L#? zQRTUxO)lvv@O|h5X$Ncd$q@X1#hAhD40yXD?O<2EJLL5#mPYj??O?6mZNZqaM<|nN z@LomQ!C3F#oQCYx{l=~Jb7mEI49{AD-+==lD$zajw2FjXDeCt$=)AtRfB74J+Cb}b z3Ai79g2f>CyrMgT=L`7U_oNQ2?LYm-yhN$Gw2A)Fk5c>3ii#RH8}Z{%Y76?8^?$J3 zkG-q)r}d@%D)TqMFDj;Y@r*s1v^NiaWavf_#~TUn(}gnLocGi@(lsP)ABU+V-W%JW zN$k_yx0T5+{{LhSzicn`fp)HFsMejuk0-nzT36{$$N|hwf~YT&cCa&_pijO+|C$46 z^~pK~X>Y5~j`;4hk8f*>_$2LMZG0WC#^HOBUiRZq(%vmTyoCDz_XU#nw*6teWq;hH zJ)nWfL(CoOk)$1r$A8fD(f(w9__BKbx+3ju`gcsfygJ$Fr+PivNZQ-^Q`kv z(hkP?`T33YIv&;QcrZTF#t9P`>t`(fhA=#ec3-1$SL#u~bpzZ>c`O~#?dZrnBgy;unR`oKN7>7*gC7iu)S zB*m&?Htejy7dHp^=JZ{i?-={{%Qf?3Po#GsAHmF9^V#UxxL$fz6`!1)o%Z#G`Oh+W E0bzJ6EC2ui literal 8520 zcmchcX^0#}6vwNtNm$l632QV53!X6=)b&G*c*QG<37Yl3l68|!WaDNtW~0WaC?24A zpx~Dn)F`4DqDB#n1O!2XibwQ=eh@T*ibhchD2ibG|6kSXsp^@YncWXI^!#RC_rL1Z zt5?<4HKtc^*GPYoB{ovZZ`5XJ@8`G0yXP*7gDT{Z% z^!usj?L2YomTNCJv$Jx2Z^h{cR<0Tu8Cbn;?ZDWo^~0+NM%S(zGwEbwDhI`8x~WXz z=e%lS!eb+TZpEprUrnbPlTI=dtG)Jr)P7jl_FA89dfw{8rPar?)dvn7_!H-SB${{^ z&TExwCru}FDRJ)6OGktW4G1-^Kkd=Ah-*u`Tl-M-WqY4wh z%TLsO6F%sJquRkzeR`eMlhma<>ZIOX_x0yV`+Lj~M?ktpsusp~;P(Y6k30i>z%uz7 zJOSl8W=G;TbV|0H^(tASE4Nv_OIUCGq^(!@1b*+vZ%3AsTx!cBX;1F=h_6mxT7I+~ zH{l?&Eg;HNvix|qEuR$ozB*M0mX^Xm8-{XDes>oIrAN`g-m%sVua23i_%?wf6<}H|W!Tt55&2`kZR- zFW1M1!hg>9Ps;Jx;1ckTT{x zbX}oTJ6Kx(1m@=f|9QmuCwdkqm_7<0y6aRs=+}RJus*xP`pz|pjN2V`@(S%ZeEl+C zFIU|M_3?LBPkM*1U+DWE@3D80P3yPUeSN>^P$A_H{y{KV?5c9(=j{6epi}5>~$sAT-4`$!6??r@&+^mfY(4B> z)~{4MSgL2eypN=g^()n0&@T`2)8(<|HT#o#l84K4zy7nGeu?B4W6Zn&B~SL(Nt@)C zBm0;6rBof*to#vKpP)T*fRZ2hp_G1yT`6%xJe6#J^tg*JDE*7;N-Y=k>%Umqr_YZ) za+ev$_#G4d@kZj4UI~A(ekYSpT|AV#@OusHj`BQ4+;ch|^uB*V`SecS3&@-Cv8Ya2 zC%}{w^>WXIevrA&mEUE|%<%o*+ZXZP@S!&G3hPrh!j0W2JTs=p<}%#}n3XM@v6;tH zcAtcAPgq%Y&8Upl2FJLUz~@zm+Bs6&WNL@TtxSG26H&t7?B0p_n>>#Q?`N&G+AZVq zH+fz9t|R4HAIY)D?L%#czbAKAXQMJoL*=B_JBAHAMA)w!-ZVUVW4;3McJ0vbOX1tW zj=cy7GCWhN{oo+O8}w$_>iI?{Gm}#7!!7g}5!_Xgk%1+WtcV@e4*DZ3tRH%=6shMM zm5f-W+T9AWaRliO8FJnqLGe1axL)33-oVK6 z;I1-yFsIsG#M^k^6THI@+&Vmn0J?Rm-A8isY`O{;7T_d5!HF!%srChd&w-wAo%|GnS!yV`MLYd#EjemWH?5GCwYnT(_yY&!v7Is1NT^m1( zS}O8=%MwMKC=_}QrJbBd;C#0NI9;C5@WQR4Wt>Du*zqE~%JyX9sP}<>_66n1(=b9A zd@9a$O?1pMTb?r2`=X}h!o_Gk*F6!FZ(7+wO7mQ=PV}h5*;JvTy$bcsfp{+P4LI``+sG+?VB?MRGrn z`@KrFgTDWv{%|{Y#w7Oj;>{j0mx?{y*VBD*$-2D%_Mz?UFOvPJ{aMz3J??)6*MHJ) z&};u`f4cr{^xx@q&JUipXouL9E&R{>e+M);^8R0gAIt+1;5sgt&$WKJjE_a`3(0Z7 zL+SKg#`Fa9;(*LHCG!^UF3gSj3|+1$lrPVr^1BQF{}rCO(B0$y|6^nDwjoh~Uxn3k ztuJ30m1x`w7@33BbEYeVSy{M7i(W>c9^@Kr#mGr6W}PXM>2+maJ7xdR5A^Qr|HX9A z&d$NxfgIg3!yk$7$FlxgZyX)6tu3v;v=r{%xKe7jtq)4U%u#56>r&nnUurAD7TI@@ z(kSw6CmS}E8I{{cn$&(;v*(&9G0N>3eQV_fK|HcG=xvC2GCu+B(R^B=+M&vO6( diff --git a/compiler/tests/sram_1b_16_1rw_sky130.log b/compiler/tests/sram_1b_16_1rw_sky130.log index e92e1a3b..0fafc96e 100644 --- a/compiler/tests/sram_1b_16_1rw_sky130.log +++ b/compiler/tests/sram_1b_16_1rw_sky130.log @@ -1,4 +1,4 @@ -WARNING: file magic.py: line 210: DRC Errors replica_bitcell_array 985 +WARNING: file magic.py: line 210: DRC Errors replica_bitcell_array 1010 ERROR: file magic.py: line 285: replica_bitcell_array LVS mismatch (results in /home/jesse/output/replica_bitcell_array.lvs.report) diff --git a/missing_pin.gds b/missing_pin.gds index 692677d9eebb55410a246143cdb0049584c034e1..69d112e423b42ca89bfa29d91a6b37c4cd272f15 100644 GIT binary patch literal 3444 zcmai%PiR#~6voe;`^QvLjq-eA43<(*(TJp=rWCZs)QutpS}LN3su826YEqlfx@n=P zbk|kEg+C!z(sp{*i~G~d4S^0qxUuKoAc==|ny zuN-(!2J(7+e-ZTK(`RNUJ~}pjc4%sRX7W>!tVg7H)yeBpEOD|?2K!R+Z8C5UyonD< z`=n&cy6E$zUZ1b=`jWISt=A`0BC0n+pI*Z=Nqf*QlCGII+cTe<`1s8->ru;ku*y0c z_M^`J0QVq0lJ?=2QMc&b4rqQCQ6@*he=5=r#2h_BrhX$L#? zQRTUxO)lvv@O|h5X$Ncd$q@X1#hAhD40yXD?O<2EJLL5#mPYj??O?6mZNZqaM<|nN z@LomQ!C3F#oQCYx{l=~Jb7mEI49{AD-+==lD$zajw2FjXDeCt$=)AtRfB74J+Cb}b z3Ai79g2f>CyrMgT=L`7U_oNQ2?LYm-yhN$Gw2A)Fk5c>3ii#RH8}Z{%Y76?8^?$J3 zkG-q)r}d@%D)TqMFDj;Y@r*s1v^NiaWavf_#~TUn(}gnLocGi@(lsP)ABU+V-W%JW zN$k_yx0T5+{{LhSzicn`fp)HFsMejuk0-nzT36{$$N|hwf~YT&cCa&_pijO+|C$46 z^~pK~X>Y5~j`;4hk8f*>_$2LMZG0WC#^HOBUiRZq(%vmTyoCDz_XU#nw*6teWq;hH zJ)nWfL(CoOk)$1r$A8fD(f(w9__BKbx+3ju`gcsfygJ$Fr+PivNZQ-^Q`kv z(hkP?`T33YIv&;QcrZTF#t9P`>t`(fhA=#ec3-1$SL#u~bpzZ>c`O~#?dZrnBgy;unR`oKN7>7*gC7iu)S zB*m&?Htejy7dHp^=JZ{i?-={{%Qf?3Po#GsAHmF9^V#UxxL$fz6`!1)o%Z#G`Oh+W E0bzJ6EC2ui literal 8520 zcmchcX^0#}6vwNtNm$l632QV53!X6=)b&G*c*QG<37Yl3l68|!WaDNtW~0WaC?24A zpx~Dn)F`4DqDB#n1O!2XibwQ=eh@T*ibhchD2ibG|6kSXsp^@YncWXI^!#RC_rL1Z zt5?<4HKtc^*GPYoB{ovZZ`5XJ@8`G0yXP*7gDT{Z% z^!usj?L2YomTNCJv$Jx2Z^h{cR<0Tu8Cbn;?ZDWo^~0+NM%S(zGwEbwDhI`8x~WXz z=e%lS!eb+TZpEprUrnbPlTI=dtG)Jr)P7jl_FA89dfw{8rPar?)dvn7_!H-SB${{^ z&TExwCru}FDRJ)6OGktW4G1-^Kkd=Ah-*u`Tl-M-WqY4wh z%TLsO6F%sJquRkzeR`eMlhma<>ZIOX_x0yV`+Lj~M?ktpsusp~;P(Y6k30i>z%uz7 zJOSl8W=G;TbV|0H^(tASE4Nv_OIUCGq^(!@1b*+vZ%3AsTx!cBX;1F=h_6mxT7I+~ zH{l?&Eg;HNvix|qEuR$ozB*M0mX^Xm8-{XDes>oIrAN`g-m%sVua23i_%?wf6<}H|W!Tt55&2`kZR- zFW1M1!hg>9Ps;Jx;1ckTT{x zbX}oTJ6Kx(1m@=f|9QmuCwdkqm_7<0y6aRs=+}RJus*xP`pz|pjN2V`@(S%ZeEl+C zFIU|M_3?LBPkM*1U+DWE@3D80P3yPUeSN>^P$A_H{y{KV?5c9(=j{6epi}5>~$sAT-4`$!6??r@&+^mfY(4B> z)~{4MSgL2eypN=g^()n0&@T`2)8(<|HT#o#l84K4zy7nGeu?B4W6Zn&B~SL(Nt@)C zBm0;6rBof*to#vKpP)T*fRZ2hp_G1yT`6%xJe6#J^tg*JDE*7;N-Y=k>%Umqr_YZ) za+ev$_#G4d@kZj4UI~A(ekYSpT|AV#@OusHj`BQ4+;ch|^uB*V`SecS3&@-Cv8Ya2 zC%}{w^>WXIevrA&mEUE|%<%o*+ZXZP@S!&G3hPrh!j0W2JTs=p<}%#}n3XM@v6;tH zcAtcAPgq%Y&8Upl2FJLUz~@zm+Bs6&WNL@TtxSG26H&t7?B0p_n>>#Q?`N&G+AZVq zH+fz9t|R4HAIY)D?L%#czbAKAXQMJoL*=B_JBAHAMA)w!-ZVUVW4;3McJ0vbOX1tW zj=cy7GCWhN{oo+O8}w$_>iI?{Gm}#7!!7g}5!_Xgk%1+WtcV@e4*DZ3tRH%=6shMM zm5f-W+T9AWaRliO8FJnqLGe1axL)33-oVK6 z;I1-yFsIsG#M^k^6THI@+&Vmn0J?Rm-A8isY`O{;7T_d5!HF!%srChd&w-wAo%|GnS!yV`MLYd#EjemWH?5GCwYnT(_yY&!v7Is1NT^m1( zS}O8=%MwMKC=_}QrJbBd;C#0NI9;C5@WQR4Wt>Du*zqE~%JyX9sP}<>_66n1(=b9A zd@9a$O?1pMTb?r2`=X}h!o_Gk*F6!FZ(7+wO7mQ=PV}h5*;JvTy$bcsfp{+P4LI``+sG+?VB?MRGrn z`@KrFgTDWv{%|{Y#w7Oj;>{j0mx?{y*VBD*$-2D%_Mz?UFOvPJ{aMz3J??)6*MHJ) z&};u`f4cr{^xx@q&JUipXouL9E&R{>e+M);^8R0gAIt+1;5sgt&$WKJjE_a`3(0Z7 zL+SKg#`Fa9;(*LHCG!^UF3gSj3|+1$lrPVr^1BQF{}rCO(B0$y|6^nDwjoh~Uxn3k ztuJ30m1x`w7@33BbEYeVSy{M7i(W>c9^@Kr#mGr6W}PXM>2+maJ7xdR5A^Qr|HX9A z&d$NxfgIg3!yk$7$FlxgZyX)6tu3v;v=r{%xKe7jtq)4U%u#56>r&nnUurAD7TI@@ z(kSw6CmS}E8I{{cn$&(;v*(&9G0N>3eQV_fK|HcG=xvC2GCu+B(R^B=+M&vO6( diff --git a/sram_1b_16_1rw_sky130.log b/sram_1b_16_1rw_sky130.log index f57734de..248d025f 100644 --- a/sram_1b_16_1rw_sky130.log +++ b/sram_1b_16_1rw_sky130.log @@ -17,3 +17,4 @@ [bitcell_base_array/__init__]: Creating bitcell_array 4 x 4 [bitcell_array/__init__]: Creating bitcell_array 4 x 4 [bitcell_base_array/__init__]: Creating replica_column 7 x 1 +[bitcell_base_array/__init__]: Creating dummy_array 1 x 4