diff --git a/compiler/base/contact.py b/compiler/base/contact.py index c3fa810d..5c300033 100644 --- a/compiler/base/contact.py +++ b/compiler/base/contact.py @@ -1,11 +1,11 @@ -import design +import hierarchy_design import debug import utils from tech import drc from vector import vector -class contact(design.design): +class contact(hierarchy_design.hierarchy_design): """ Object for a contact shape with its conductor enclosures. Creates a contact array minimum active or poly enclosure and metal1 enclosure. @@ -31,7 +31,7 @@ class contact(design.design): dimensions[0], dimensions[1]) - design.design.__init__(self, name) + hierarchy_design.hierarchy_design.__init__(self, name) debug.info(4, "create contact object {0}".format(name)) self.layer_stack = layer_stack @@ -158,6 +158,9 @@ class contact(design.design): width=well_width, height=well_height) + def analytical_power(self, proc, vdd, temp, load): + """ Get total power of a module """ + return self.return_power() # This is not instantiated and used for calculations only. @@ -167,4 +170,5 @@ active = contact(layer_stack=("active", "contact", "poly")) poly = contact(layer_stack=("poly", "contact", "metal1")) m1m2 = contact(layer_stack=("metal1", "via1", "metal2")) m2m3 = contact(layer_stack=("metal2", "via2", "metal3")) +#m3m4 = contact(layer_stack=("metal3", "via3", "metal4")) diff --git a/compiler/base/design.py b/compiler/base/design.py index 794bb79a..09522f35 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -1,5 +1,5 @@ -import hierarchy_layout -import hierarchy_spice +from hierarchy_design import hierarchy_design +import contact import globals import verify import debug @@ -7,46 +7,24 @@ import os from globals import OPTS -class design(hierarchy_spice.spice, hierarchy_layout.layout): +class design(hierarchy_design): """ - Design Class for all modules to inherit the base features. - Class consisting of a set of modules and instances of these modules + This is the same as the hierarchy_design class except it contains + some DRC constants and analytical models for other modules to reuse. + """ - name_map = [] - def __init__(self, name): - self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds" - self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp" - - self.name = name - hierarchy_layout.layout.__init__(self, name) - hierarchy_spice.spice.__init__(self, name) - + hierarchy_design.__init__(self,name) + self.setup_drc_constants() - - # Check if the name already exists, if so, give an error - # because each reference must be a unique name. - # These modules ensure unique names or have no changes if they - # aren't unique - ok_list = ['ms_flop', - 'dff', - 'dff_buf', - 'bitcell', - 'contact', - 'ptx', - 'sram', - 'hierarchical_predecode2x4', - 'hierarchical_predecode3x8'] - if name not in design.name_map: - design.name_map.append(name) - else: - for ok_names in ok_list: - if ok_names in self.__class__.__name__: - break - else: - debug.error("Duplicate layout reference name {0} of class {1}. GDS2 requires names be unique.".format(name,self.__class__),-1) - + + self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space, self.m2_space) + self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space, self.m3_space) + # SCMOS doesn't have m4... + #self.m3_pitch = max(contact.m3m4.width,contact.m3m4.height) + max(self.m3_space, self.m4_space) + self.m3_pitch = self.m2_pitch + def setup_drc_constants(self): """ These are some DRC constants used in many places in the compiler.""" from tech import drc @@ -61,70 +39,14 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout): self.m3_space = drc["metal3_to_metal3"] self.active_width = drc["minwidth_active"] self.contact_width = drc["minwidth_contact"] - + self.poly_to_active = drc["poly_to_active"] self.poly_extend_active = drc["poly_extend_active"] self.contact_to_gate = drc["contact_to_gate"] self.well_enclose_active = drc["well_enclosure_active"] self.implant_enclose_active = drc["implant_enclosure_active"] self.implant_space = drc["implant_to_implant"] - - def get_layout_pins(self,inst): - """ Return a map of pin locations of the instance offset """ - # find the instance - for i in self.insts: - if i.name == inst.name: - break - else: - debug.error("Couldn't find instance {0}".format(inst_name),-1) - inst_map = inst.mod.pin_map - return inst_map - - def DRC_LVS(self, final_verification=False): - """Checks both DRC and LVS for a module""" - if OPTS.check_lvsdrc: - tempspice = OPTS.openram_temp + "/temp.sp" - tempgds = OPTS.openram_temp + "/temp.gds" - self.sp_write(tempspice) - self.gds_write(tempgds) - debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name)) - debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name)) - os.remove(tempspice) - os.remove(tempgds) - - def DRC(self): - """Checks DRC for a module""" - if OPTS.check_lvsdrc: - tempgds = OPTS.openram_temp + "/temp.gds" - self.gds_write(tempgds) - debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name)) - os.remove(tempgds) - - def LVS(self, final_verification=False): - """Checks LVS for a module""" - if OPTS.check_lvsdrc: - tempspice = OPTS.openram_temp + "/temp.sp" - tempgds = OPTS.openram_temp + "/temp.gds" - self.sp_write(tempspice) - self.gds_write(tempgds) - debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name)) - os.remove(tempspice) - os.remove(tempgds) - - def __str__(self): - """ override print function output """ - return "design: " + self.name - - def __repr__(self): - """ override print function output """ - text="( design: " + self.name + " pins=" + str(self.pins) + " " + str(self.width) + "x" + str(self.height) + " )\n" - for i in self.objs: - text+=str(i)+",\n" - for i in self.insts: - text+=str(i)+",\n" - return text - def analytical_power(self, proc, vdd, temp, load): """ Get total power of a module """ total_module_power = self.return_power() diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py new file mode 100644 index 00000000..87659bd7 --- /dev/null +++ b/compiler/base/hierarchy_design.py @@ -0,0 +1,111 @@ +import hierarchy_layout +import hierarchy_spice +import globals +import verify +import debug +import os +from globals import OPTS + + +class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): + """ + Design Class for all modules to inherit the base features. + Class consisting of a set of modules and instances of these modules + """ + name_map = [] + + + def __init__(self, name): + self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds" + self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp" + + self.name = name + hierarchy_layout.layout.__init__(self, name) + hierarchy_spice.spice.__init__(self, name) + + + # Check if the name already exists, if so, give an error + # because each reference must be a unique name. + # These modules ensure unique names or have no changes if they + # aren't unique + ok_list = ['ms_flop', + 'dff', + 'dff_buf', + 'bitcell', + 'contact', + 'ptx', + 'sram', + 'hierarchical_predecode2x4', + 'hierarchical_predecode3x8'] + if name not in hierarchy_design.name_map: + hierarchy_design.name_map.append(name) + else: + for ok_names in ok_list: + if ok_names in self.__class__.__name__: + break + else: + debug.error("Duplicate layout reference name {0} of class {1}. GDS2 requires names be unique.".format(name,self.__class__),-1) + + + def get_layout_pins(self,inst): + """ Return a map of pin locations of the instance offset """ + # find the instance + for i in self.insts: + if i.name == inst.name: + break + else: + debug.error("Couldn't find instance {0}".format(inst_name),-1) + inst_map = inst.mod.pin_map + return inst_map + + + def DRC_LVS(self, final_verification=False): + """Checks both DRC and LVS for a module""" + # Unit tests will check themselves. + # Do not run if disabled in options. + if not OPTS.is_unit_test and OPTS.check_lvsdrc: + tempspice = OPTS.openram_temp + "/temp.sp" + tempgds = OPTS.openram_temp + "/temp.gds" + self.sp_write(tempspice) + self.gds_write(tempgds) + debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name)) + debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name)) + os.remove(tempspice) + os.remove(tempgds) + + def DRC(self): + """Checks DRC for a module""" + # Unit tests will check themselves. + # Do not run if disabled in options. + if not OPTS.is_unit_test and OPTS.check_lvsdrc: + tempgds = OPTS.openram_temp + "/temp.gds" + self.gds_write(tempgds) + debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name)) + os.remove(tempgds) + + def LVS(self, final_verification=False): + """Checks LVS for a module""" + # Unit tests will check themselves. + # Do not run if disabled in options. + if not OPTS.is_unit_test and OPTS.check_lvsdrc: + tempspice = OPTS.openram_temp + "/temp.sp" + tempgds = OPTS.openram_temp + "/temp.gds" + self.sp_write(tempspice) + self.gds_write(tempgds) + debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name)) + os.remove(tempspice) + os.remove(tempgds) + + def __str__(self): + """ override print function output """ + return "design: " + self.name + + def __repr__(self): + """ override print function output """ + text="( design: " + self.name + " pins=" + str(self.pins) + " " + str(self.width) + "x" + str(self.height) + " )\n" + for i in self.objs: + text+=str(i)+",\n" + for i in self.insts: + text+=str(i)+",\n" + return text + diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 010680d6..58a3d1fe 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -524,6 +524,62 @@ class layout(lef.lef): return blockages + def create_horizontal_pin_bus(self, layer, pitch, offset, names, length): + """ Create a horizontal bus of pins. """ + self.create_bus(layer,pitch,offset,names,length,vertical=False,make_pins=True) + + def create_vertical_pin_bus(self, layer, pitch, offset, names, length): + """ Create a horizontal bus of pins. """ + self.create_bus(layer,pitch,offset,names,length,vertical=True,make_pins=True) + + def create_vertical_bus(self, layer, pitch, offset, names, length): + """ Create a horizontal bus. """ + self.create_bus(layer,pitch,offset,names,length,vertical=True,make_pins=False) + + def create_horiontal_bus(self, layer, pitch, offset, names, length): + """ Create a horizontal bus. """ + self.create_bus(layer,pitch,offset,names,length,vertical=False,make_pins=False) + + + def create_bus(self, layer, pitch, offset, names, length, vertical, make_pins): + """ + Create a horizontal or vertical bus. It can be either just rectangles, or actual + layout pins. It returns an map of line center line positions indexed by name. + """ + + # half minwidth so we can return the center line offsets + half_minwidth = 0.5*drc["minwidth_{}".format(layer)] + + line_positions = {} + if vertical: + for i in range(len(names)): + line_offset = offset + vector(i*pitch,0) + if make_pins: + self.add_layout_pin(text=names[i], + layer=layer, + offset=line_offset, + height=length) + else: + self.add_rect(layer=layer, + offset=line_offset, + height=length) + line_positions[names[i]]=line_offset+vector(half_minwidth,0) + else: + for i in range(len(names)): + line_offset = offset + vector(0,i*pitch + half_minwidth) + if make_pins: + self.add_layout_pin(text=names[i], + layer=layer, + offset=line_offset, + width=length) + else: + self.add_rect(layer=layer, + offset=line_offset, + width=length) + line_positions[names[i]]=line_offset+vector(0,half_minwidth) + + return line_positions + def add_enclosure(self, insts, layer="nwell"): """ Add a layer that surrounds the given instances. Useful for creating wells, for example. Doesn't check for minimum widths or diff --git a/compiler/characterizer/__init__.py b/compiler/characterizer/__init__.py index 6930a112..dc9398d0 100644 --- a/compiler/characterizer/__init__.py +++ b/compiler/characterizer/__init__.py @@ -1,16 +1,18 @@ import os import debug +import globals from globals import OPTS,find_exe,get_tool from .lib import * from .delay import * from .setup_hold import * -debug.info(2,"Initializing characterizer...") - +debug.info(1,"Initializing characterizer...") OPTS.spice_exe = "" if not OPTS.analytical_delay: + debug.info(1, "Finding spice simulator.") + if OPTS.spice_name != "": OPTS.spice_exe=find_exe(OPTS.spice_name) if OPTS.spice_exe=="": @@ -24,6 +26,7 @@ if not OPTS.analytical_delay: if OPTS.spice_exe == "": debug.error("No recognizable spice version found. Unable to perform characterization.",1) - +else: + debug.info(1,"Analytical model enabled.") diff --git a/compiler/debug.py b/compiler/debug.py index 7001373e..1bf46db0 100644 --- a/compiler/debug.py +++ b/compiler/debug.py @@ -13,19 +13,19 @@ def check(check,str): (frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1] if not check: - print("ERROR: file {0}: line {1}: {2}".format(os.path.basename(filename),line_number,str)) + sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) assert 0 def error(str,return_value=0): (frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1] - print("ERROR: file {0}: line {1}: {2}".format(os.path.basename(filename),line_number,str)) + sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) assert return_value==0 def warning(str): (frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1] - print("WARNING: file {0}: line {1}: {2}".format(os.path.basename(filename),line_number,str)) + sys.stderr.write("WARNING: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) def info(lev, str): diff --git a/compiler/globals.py b/compiler/globals.py index 86d091b1..34cfbe08 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -9,12 +9,14 @@ import optparse import options import sys import re +import copy import importlib USAGE = "Usage: openram.py [options] \nUse -h for help.\n" # Anonymous object that will be the options OPTS = options.options() +CHECKPOINT_OPTS=None def parse_args(): """ Parse the optional arguments for OpenRAM """ @@ -102,6 +104,8 @@ def check_versions(): def init_openram(config_file, is_unit_test=True): """Initialize the technology, paths, simulators, etc.""" + + check_versions() debug.info(1,"Initializing OpenRAM...") @@ -112,6 +116,30 @@ def init_openram(config_file, is_unit_test=True): import_tech() + # Reset the static duplicate name checker for unit tests. + import hierarchy_design + hierarchy_design.hierarchy_design.name_map=[] + + global OPTS + global CHECKPOINT_OPTS + + # This is a hack. If we are running a unit test and have checkpointed + # the options, load them rather than reading the config file. + # This way, the configuration is reloaded at the start of every unit test. + # If a unit test fails, we don't have to worry about restoring the old config values + # that may have been tested. + if is_unit_test and CHECKPOINT_OPTS: + OPTS.__dict__ = CHECKPOINT_OPTS.__dict__.copy() + return + + # Import these to find the executables for checkpointing + import characterizer + import verify + # Make a checkpoint of the options so we can restore + # after each unit test + if not CHECKPOINT_OPTS: + CHECKPOINT_OPTS = copy.copy(OPTS) + def get_tool(tool_type, preferences): @@ -132,15 +160,15 @@ def get_tool(tool_type, preferences): return(None,"") - def read_config(config_file, is_unit_test=True): """ Read the configuration file that defines a few parameters. The config file is just a Python file that defines some config - options. + options. This will only actually get read the first time. Subsequent + reads will just restore the previous copy (ask mrg) """ global OPTS - + # Create a full path relative to current dir unless it is already an abs path if not os.path.isabs(config_file): config_file = os.getcwd() + "/" + config_file @@ -164,6 +192,7 @@ def read_config(config_file, is_unit_test=True): # The command line will over-ride the config file # except in the case of the tech name! This is because the tech name # is sometimes used to specify the config file itself (e.g. unit tests) + # Note that if we re-read a config file, nothing will get read again! if not k in OPTS.__dict__ or k=="tech_name": OPTS.__dict__[k]=v @@ -192,12 +221,16 @@ def read_config(config_file, is_unit_test=True): os.chmod(OPTS.output_path, 0o750) except: debug.error("Unable to make output directory.",-1) - - + def end_openram(): """ Clean up openram for a proper exit """ cleanup_paths() + + import verify + verify.print_drc_stats() + verify.print_lvs_stats() + verify.print_pex_stats() @@ -206,6 +239,7 @@ def cleanup_paths(): """ We should clean up the temp directory after execution. """ + global OPTS if not OPTS.purge_temp: debug.info(0,"Preserving temp directory: {}".format(OPTS.openram_temp)) return @@ -275,9 +309,6 @@ def import_tech(): debug.info(2,"Importing technology: " + OPTS.tech_name) - # Set the tech to the config file we read in instead of the command line value. - OPTS.tech_name = OPTS.tech_name - # environment variable should point to the technology dir try: OPENRAM_TECH = os.path.abspath(os.environ.get("OPENRAM_TECH")) @@ -323,6 +354,8 @@ def print_time(name, now_time, last_time=None): def report_status(): """ Check for valid arguments and report the info about the SRAM being generated """ + global OPTS + # Check if all arguments are integers for bits, size, banks if type(OPTS.word_size)!=int: debug.error("{0} is not an integer in config file.".format(OPTS.word_size)) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 3ed6c222..db58441a 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -161,10 +161,6 @@ class bank(design.design): else: self.num_col_addr_lines = 0 - # M1/M2 routing pitch is based on contacted pitch - self.m1_pitch = contact.m1m2.height + max(self.m1_space,self.m2_space) - self.m2_pitch = contact.m2m3.height + max(self.m2_space,self.m3_space) - # The width of this bus is needed to place other modules (e.g. decoder) # A width on each side too self.central_bus_width = self.m2_pitch * self.num_control_lines + 2*self.m2_width diff --git a/compiler/modules/bank_select.py b/compiler/modules/bank_select.py index d0b3070a..2abfb3c6 100644 --- a/compiler/modules/bank_select.py +++ b/compiler/modules/bank_select.py @@ -56,10 +56,6 @@ class bank_select(design.design): def calculate_module_offsets(self): - # M1/M2 routing pitch is based on contacted pitch - self.m1_pitch = contact.m1m2.height + max(self.m1_space,self.m2_space) - self.m2_pitch = contact.m2m3.height + max(self.m2_space,self.m3_space) - self.xoffset_nand = self.inv4x.width + 2*self.m2_pitch + drc["pwell_to_nwell"] self.xoffset_nor = self.inv4x.width + 2*self.m2_pitch + drc["pwell_to_nwell"] self.xoffset_inv = max(self.xoffset_nand + self.nand2.width, self.xoffset_nor + self.nor2.width) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 33501158..8526cb43 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -86,10 +86,6 @@ class control_logic(design.design): # These aren't for instantiating, but we use them to get the dimensions #self.poly_contact_offset = vector(0.5*contact.poly.width,0.5*contact.poly.height) - # M1/M2 routing pitch is based on contacted pitch - self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"]) - self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(drc["metal2_to_metal2"],drc["metal3_to_metal3"]) - # Have the cell gap leave enough room to route an M2 wire. # Some cells may have pwell/nwell spacing problems too when the wells are different heights. #self.cell_gap = max(self.m2_pitch,drc["pwell_to_nwell"]) diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 179cc936..5742cc6c 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -45,7 +45,8 @@ class hierarchical_decoder(design.design): self.add_pins() self.create_pre_decoder() self.create_row_decoder() - self.create_vertical_rail() + self.create_input_rail() + self.create_predecode_rail() self.route_vdd_gnd() def add_modules(self): @@ -60,7 +61,6 @@ class hierarchical_decoder(design.design): def add_decoders(self): """ Create the decoders based on the number of pre-decodes """ - # FIXME: Only add these if needed? self.pre2_4 = pre2x4() self.add_mod(self.pre2_4) @@ -68,8 +68,8 @@ class hierarchical_decoder(design.design): self.add_mod(self.pre3_8) 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 pre-decoder and 3:8 pre-decoder + needed based on the number of inputs """ if (num_inputs == 2): return (1,0) elif (num_inputs == 3): @@ -90,12 +90,6 @@ class hierarchical_decoder(design.design): debug.error("Invalid number of inputs for hierarchical decoder",-1) def setup_layout_constants(self): - # Vertical metal rail gap definition - self.metal2_extend_contact = (contact.m1m2.second_layer_height - contact.m1m2.contact_width) / 2 - self.metal2_spacing = self.metal2_extend_contact + self.m2_space - self.metal2_pitch = self.metal2_spacing + self.m2_width - self.via_shift = (contact.m1m2.second_layer_width - contact.m1m2.first_layer_width) / 2 - self.predec_groups = [] # This array is a 2D array. # Distributing vertical rails to different groups. One group belongs to one pre-decoder. @@ -120,7 +114,75 @@ class hierarchical_decoder(design.design): self.calculate_dimensions() + def create_input_rail(self): + """ Create input rails for the predecoders """ + # inputs should be as high as the decoders + input_height = self.no_of_pre2x4*self.pre2_4.height + self.no_of_pre3x8*self.pre3_8.height + + # Find the left-most predecoder + min_x = 0 + if self.no_of_pre2x4 > 0: + min_x = min(min_x, -self.pre2_4.width) + if self.no_of_pre3x8 > 0: + min_x = min(min_x, -self.pre3_8.width) + input_offset=vector(min_x - self.input_routing_width,0) + + input_bus_names = ["A[{0}]".format(i) for i in range(self.num_inputs)] + self.create_vertical_pin_bus(layer="metal2", + pitch=self.m2_pitch, + offset=input_offset, + names=input_bus_names, + length=input_height) + self.connect_input_to_predecodes() + + + def connect_input_to_predecodes(self): + """ Connect the vertical input rail to the predecoders """ + for pre_num in range(self.no_of_pre2x4): + for i in range(2): + index = pre_num * 2 + i + + input_pin = self.get_pin("A[{}]".format(index)) + + in_name = "in[{}]".format(i) + decoder_pin = self.pre2x4_inst[pre_num].get_pin(in_name) + + # Offset each decoder pin up so they don't conflit + decoder_offset = decoder_pin.center() + vector(0,i*self.m2_pitch) + input_offset = input_pin.center().scale(1,0) + decoder_offset.scale(0,1) + + self.connect_input_rail(decoder_offset, input_offset) + + + for pre_num in range(self.no_of_pre3x8): + for i in range(3): + index = pre_num * 3 + i + self.no_of_pre2x4 * 2 + + input_pin = self.get_pin("A[{}]".format(index)) + + in_name = "in[{}]".format(i) + decoder_pin = self.pre3x8_inst[pre_num].get_pin(in_name) + + # Offset each decoder pin up so they don't conflit + decoder_offset = decoder_pin.center() + vector(0,i*self.m2_pitch) + input_offset = input_pin.center().scale(1,0) + decoder_offset.scale(0,1) + + self.connect_input_rail(decoder_offset, input_offset) + + + def connect_input_rail(self, input_offset, output_offset): + """ Connect a vertical M2 coordinate to another vertical M2 coordinate to the predecode inputs """ + + self.add_via_center(layers=("metal2", "via2", "metal3"), + offset=input_offset, + rotate=90) + self.add_via_center(layers=("metal2", "via2", "metal3"), + offset=output_offset, + rotate=90) + self.add_path(("metal3"), [input_offset, output_offset]) + + def add_pins(self): """ Add the module pins """ @@ -143,10 +205,11 @@ class hierarchical_decoder(design.design): debug.error("Not enough rows for a hierarchical decoder. Non-hierarchical not supported yet.",-1) # Calculates height and width of pre-decoder, - if(self.no_of_pre3x8 > 0): + if self.no_of_pre3x8 > 0: self.predecoder_width = self.pre3_8.width else: self.predecoder_width = self.pre2_4.width + self.predecoder_height = self.pre2_4.height*self.no_of_pre2x4 + self.pre3_8.height*self.no_of_pre3x8 # Calculates height and width of row-decoder @@ -154,12 +217,14 @@ class hierarchical_decoder(design.design): nand_width = self.nand2.width else: nand_width = self.nand3.width - self.routing_width = self.metal2_pitch*self.total_number_of_predecoder_outputs + self.internal_routing_width = self.m2_pitch*self.total_number_of_predecoder_outputs self.row_decoder_height = self.inv.height * self.rows + self.input_routing_width = (self.num_inputs+1) * self.m2_pitch # Calculates height and width of hierarchical decoder self.height = self.row_decoder_height - self.width = self.predecoder_width + self.routing_width + nand_width + self.inv.width + self.width = self.input_routing_width + self.predecoder_width \ + + self.internal_routing_width + nand_width + self.inv.width def create_pre_decoder(self): """ Creates pre-decoder and places labels input address [A] """ @@ -171,7 +236,7 @@ class hierarchical_decoder(design.design): self.add_pre3x8(i) def add_pre2x4(self,num): - """ Add a 2x4 predecoder """ + """ Add a 2x4 predecoder to the left of the origin """ if (self.num_inputs == 2): base = vector(-self.pre2_4.width,0) @@ -193,27 +258,9 @@ class hierarchical_decoder(design.design): offset=base)) self.connect_inst(pins) - self.add_pre2x4_pins(num) - - - - def add_pre2x4_pins(self,num): - """ Add the input pins to the 2x4 predecoder """ - - for i in range(2): - pin = self.pre2x4_inst[num].get_pin("in[{}]".format(i)) - pin_offset = pin.ll() - - pin = self.pre2_4.get_pin("in[{}]".format(i)) - self.add_layout_pin(text="A[{0}]".format(i + 2*num ), - layer="metal2", - offset=pin_offset, - width=pin.width(), - height=pin.height()) - def add_pre3x8(self,num): - """ Add 3x8 numbered predecoder """ + """ Add 3x8 predecoder to the left of the origin and above any 2x4 decoders """ if (self.num_inputs == 3): offset = vector(-self.pre_3_8.width,0) mirror ="R0" @@ -238,20 +285,6 @@ class hierarchical_decoder(design.design): offset=offset)) self.connect_inst(pins) - # The 3x8 predecoders will be stacked, so use yoffset - self.add_pre3x8_pins(num,offset) - - def add_pre3x8_pins(self,num,offset): - """ Add the input pins to the 3x8 predecoder at the given offset """ - - for i in range(3): - pin = self.pre3x8_inst[num].get_pin("in[{}]".format(i)) - pin_offset = pin.ll() - self.add_layout_pin(text="A[{0}]".format(i + 3*num + 2*self.no_of_pre2x4), - layer="metal2", - offset=pin_offset, - width=pin.width(), - height=pin.height()) @@ -313,7 +346,7 @@ class hierarchical_decoder(design.design): self.nand_inst.append(self.add_inst(name=name, mod=nand_mod, - offset=[self.routing_width, y_off], + offset=[self.internal_routing_width, y_off], mirror=mirror)) @@ -325,9 +358,9 @@ class hierarchical_decoder(design.design): z_pin = self.inv.get_pin("Z") if (self.num_inputs == 4 or self.num_inputs == 5): - x_off = self.routing_width + self.nand2.width + x_off = self.internal_routing_width + self.nand2.width else: - x_off = self.routing_width + self.nand3.width + x_off = self.internal_routing_width + self.nand3.width self.inv_inst = [] for row in range(self.rows): @@ -377,7 +410,7 @@ class hierarchical_decoder(design.design): - def create_vertical_rail(self): + def create_predecode_rail(self): """ Creates vertical metal 2 rails to connect predecoder and decoder stages.""" # This is not needed for inputs <4 since they have no pre/decode stages. @@ -387,8 +420,8 @@ class hierarchical_decoder(design.design): self.rail_x_offsets = [] for i in range(self.total_number_of_predecoder_outputs): # The offsets go into the negative x direction - # assuming the predecodes are placed at (self.routing_width,0) - x_offset = self.metal2_pitch * i + # assuming the predecodes are placed at (self.internal_routing_width,0) + x_offset = self.m2_pitch * i self.rail_x_offsets.append(x_offset+0.5*self.m2_width) self.add_rect(layer="metal2", offset=vector(x_offset,0), @@ -406,7 +439,7 @@ class hierarchical_decoder(design.design): index = pre_num * 4 + i out_name = "out[{}]".format(i) pin = self.pre2x4_inst[pre_num].get_pin(out_name) - self.connect_rail_m3(index, pin) + self.connect_predecode_rail_m3(index, pin) for pre_num in range(self.no_of_pre3x8): @@ -414,7 +447,7 @@ class hierarchical_decoder(design.design): index = pre_num * 8 + i + self.no_of_pre2x4 * 4 out_name = "out[{}]".format(i) pin = self.pre3x8_inst[pre_num].get_pin(out_name) - self.connect_rail_m3(index, pin) + self.connect_predecode_rail_m3(index, pin) @@ -430,17 +463,17 @@ class hierarchical_decoder(design.design): if (self.num_inputs == 4 or self.num_inputs == 5): for index_A in self.predec_groups[0]: for index_B in self.predec_groups[1]: - self.connect_rail(index_A, self.nand_inst[row_index].get_pin("A")) - self.connect_rail(index_B, self.nand_inst[row_index].get_pin("B")) + self.connect_predecode_rail(index_A, self.nand_inst[row_index].get_pin("A")) + self.connect_predecode_rail(index_B, self.nand_inst[row_index].get_pin("B")) row_index = row_index + 1 elif (self.num_inputs > 5): for index_A in self.predec_groups[0]: for index_B in self.predec_groups[1]: for index_C in self.predec_groups[2]: - self.connect_rail(index_A, self.nand_inst[row_index].get_pin("A")) - self.connect_rail(index_B, self.nand_inst[row_index].get_pin("B")) - self.connect_rail(index_C, self.nand_inst[row_index].get_pin("C")) + self.connect_predecode_rail(index_A, self.nand_inst[row_index].get_pin("A")) + self.connect_predecode_rail(index_B, self.nand_inst[row_index].get_pin("B")) + self.connect_predecode_rail(index_C, self.nand_inst[row_index].get_pin("C")) row_index = row_index + 1 def route_vdd_gnd(self): @@ -476,7 +509,7 @@ class hierarchical_decoder(design.design): self.copy_layout_pin(pre, "gnd") - def connect_rail(self, rail_index, pin): + def connect_predecode_rail(self, rail_index, pin): """ Connect the routing rail to the given metal1 pin """ rail_pos = vector(self.rail_x_offsets[rail_index],pin.lc().y) self.add_path("metal1", [rail_pos, pin.lc()]) @@ -485,7 +518,7 @@ class hierarchical_decoder(design.design): rotate=90) - def connect_rail_m3(self, rail_index, pin): + def connect_predecode_rail_m3(self, rail_index, pin): """ Connect the routing rail to the given metal1 pin """ mid_point = vector(pin.cx(), pin.cy()+self.inv.height/2) rail_pos = vector(self.rail_x_offsets[rail_index],mid_point.y) diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index e0d05d92..d111b02b 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -50,10 +50,6 @@ class hierarchical_predecode(design.design): debug.error("Invalid number of predecode inputs.",-1) def setup_constraints(self): - # use a conservative douple spacing just to get rid of annoying via DRCs - self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space, self.m2_space) - self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space,self.m3_space) - # The rail offsets are indexed by the label self.rails = {} diff --git a/compiler/modules/replica_bitline.py b/compiler/modules/replica_bitline.py index 8d1d6242..f4c8995f 100644 --- a/compiler/modules/replica_bitline.py +++ b/compiler/modules/replica_bitline.py @@ -53,11 +53,6 @@ class replica_bitline(design.design): # These aren't for instantiating, but we use them to get the dimensions self.poly_contact_offset = vector(0.5*contact.poly.width,0.5*contact.poly.height) - # M1/M2 routing pitch is based on contacted pitch - self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space,self.m2_space) - self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space,self.m3_space) - - # Quadrant 1: Replica bitline and such are not rotated, but they must be placed far enough # away from the delay chain/inverter with space for three M2 tracks self.bitcell_offset = vector(0,self.replica_bitcell.height) diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 31614ae1..777958a5 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -57,7 +57,6 @@ class single_level_column_mux_array(design.design): def setup_layout_constants(self): self.column_addr_size = num_of_inputs = int(self.words_per_row / 2) self.width = self.columns * self.mux.width - self.m1_pitch = contact.m1m2.width + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"]) # one set of metal1 routes for select signals and a pair to interconnect the mux outputs bl/br # one extra route pitch is to space from the sense amp self.route_height = (self.words_per_row + 3)*self.m1_pitch diff --git a/compiler/regress.sh b/compiler/regress.sh deleted file mode 100755 index 904ef9d8..00000000 --- a/compiler/regress.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -python tests/regress.py -t freepdk45 -python tests/regress.py -t scn3me_subm diff --git a/compiler/sram.py b/compiler/sram.py index 0c144fb7..0296ad02 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -1,19 +1,17 @@ import sys -from tech import drc, spice -import debug -import design -from math import log,sqrt,ceil -import contact -from bank import bank -from dff_buf_array import dff_buf_array -from dff_array import dff_array import datetime import getpass +import debug +import design +from sram_1bank import sram_1bank +from sram_2bank import sram_2bank +from sram_4bank import sram_4bank +from math import log,sqrt,ceil from vector import vector from globals import OPTS, print_time -class sram(design.design): +class sram(sram_1bank,sram_2bank,sram_4bank): """ Dynamically generated SRAM by connecting banks to control logic. The number of banks should be 1 , 2 or 4 @@ -35,8 +33,8 @@ class sram(design.design): # reset the static duplicate name checker for unit tests # in case we create more than one SRAM - import design - design.design.name_map=[] + from design import design + design.name_map=[] self.word_size = word_size self.num_words = num_words @@ -46,18 +44,20 @@ class sram(design.design): self.num_words)) start_time = datetime.datetime.now() - design.design.__init__(self, name) - - # M1/M2 routing pitch is based on contacted pitch of the biggest layer - self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space,self.m2_space) - self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space,self.m3_space) - self.m3_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space,self.m3_space) + self.compute_sizes() + if self.num_banks == 1: + sram_1bank.__init__(self,name) + elif self.num_banks == 2: + sram_2bank.__init__(self,name) + elif self.num_banks == 4: + sram_4bank.__init__(self,name) + else: + debug.error("Invalid number of banks.",-1) self.control_size = 6 self.bank_to_bus_distance = 5*self.m3_width - - self.compute_sizes() + self.create_modules() self.add_pins() self.create_layout() @@ -109,8 +109,10 @@ class sram(design.design): debug.info(1,"Words per row: {}".format(self.words_per_row)) def estimate_words_per_row(self,tentative_num_cols, word_size): - """This provides a heuristic rounded estimate for the number of words - per row.""" + """ + This provides a heuristic rounded estimate for the number of words + per row. + """ if tentative_num_cols < 1.5*word_size: return 1 @@ -120,7 +122,8 @@ class sram(design.design): return 2 def amend_words_per_row(self,tentative_num_rows, words_per_row): - """This picks the number of words per row more accurately by limiting + """ + 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 @@ -138,7 +141,7 @@ class sram(design.design): """ Add pins for entire SRAM. """ for i in range(self.word_size): - self.add_pin("DATA[{0}]".format(i),"INOUT") + self.add_pin("DIN[{0}]".format(i),"INPUT") for i in range(self.addr_size): self.add_pin("ADDR[{0}]".format(i),"INPUT") @@ -147,162 +150,18 @@ class sram(design.design): self.control_logic_outputs=self.control_logic.get_outputs() self.add_pin_list(self.control_logic_inputs,"INPUT") + + for i in range(self.word_size): + self.add_pin("DOUT[{0}]".format(i),"OUTPUT") + self.add_pin("vdd","POWER") self.add_pin("gnd","GROUND") + def create_layout(self): - """ Layout creation """ - - if self.num_banks == 1: - self.add_single_bank_modules() - self.add_single_bank_pins() - self.route_single_bank() - elif self.num_banks == 2: - self.add_two_bank_modules() - self.route_two_banks() - elif self.num_banks == 4: - self.add_four_bank_modules() - self.route_four_banks() - else: - debug.error("Invalid number of banks.",-1) - - - def add_four_bank_modules(self): - """ Adds the modules and the buses to the top level """ - - self.compute_bus_sizes() - - self.add_four_banks() - - self.compute_four_bank_offsets() - - self.add_busses() - - self.add_four_bank_logic() - - self.width = self.bank_inst[1].ur().x - self.height = max(self.control_logic_inst.uy(),self.msb_decoder_inst.uy()) - - - def add_two_bank_modules(self): - """ Adds the modules and the buses to the top level """ - - self.compute_bus_sizes() - - self.add_two_banks() - - self.compute_two_bank_offsets() - - self.add_busses() - - self.add_two_bank_logic() - - self.width = self.bank_inst[1].ur().x - self.height = self.control_logic_inst.uy() - - - def add_single_bank_modules(self): - """ - This adds the moduels for a single bank SRAM with control - logic. - """ - - # No orientation or offset - self.bank_inst = self.add_bank(0, [0, 0], 1, 1) - - # 3/5/18 MRG: Cannot reference positions inside submodules because boundaries - # are not recomputed using instance placement. So, place the control logic such that it aligns - # with the top of the SRAM. - control_pos = vector(-self.control_logic.width - self.m3_pitch, - 3*self.supply_rail_width) - self.add_control_logic(position=control_pos) - - # Leave room for the control routes to the left of the flops - addr_pos = vector(self.control_logic_inst.lx() + 4*self.m2_pitch, - control_pos.y + self.control_logic.height + self.m1_pitch) - self.add_addr_dff(addr_pos) - - # two supply rails are already included in the bank, so just 2 here. - self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch - self.height = self.bank.height - - - def route_shared_banks(self): - """ Route the shared signals for two and four bank configurations. """ - - # create the input control pins - for n in self.control_logic_inputs + ["clk"]: - self.copy_layout_pin(self.control_logic_inst, n) - - # connect the control logic to the control bus - for n in self.control_logic_outputs + ["vdd", "gnd"]: - pins = self.control_logic_inst.get_pins(n) - for pin in pins: - if pin.layer=="metal2": - pin_pos = pin.bc() - break - rail_pos = vector(pin_pos.x,self.horz_control_bus_positions[n].y) - self.add_path("metal2",[pin_pos,rail_pos]) - self.add_via_center(("metal1","via1","metal2"),rail_pos) - - # connect the control logic cross bar - for n in self.control_logic_outputs: - cross_pos = vector(self.vert_control_bus_positions[n].x,self.horz_control_bus_positions[n].y) - self.add_via_center(("metal1","via1","metal2"),cross_pos) - - # connect the bank select signals to the vertical bus - for i in range(self.num_banks): - pin = self.bank_inst[i].get_pin("bank_sel") - pin_pos = pin.rc() if i==0 else pin.lc() - rail_pos = vector(self.vert_control_bus_positions["bank_sel[{}]".format(i)].x,pin_pos.y) - self.add_path("metal3",[pin_pos,rail_pos]) - self.add_via_center(("metal2","via2","metal3"),rail_pos) - - - def route_four_banks(self): - """ Route all of the signals for the four bank SRAM. """ - - self.route_shared_banks() - - # connect the data output to the data bus - for n in self.data_bus_names: - for i in [0,1]: - pin_pos = self.bank_inst[i].get_pin(n).bc() - rail_pos = vector(pin_pos.x,self.data_bus_positions[n].y) - self.add_path("metal2",[pin_pos,rail_pos]) - self.add_via_center(("metal2","via2","metal3"),rail_pos) - - for i in [2,3]: - pin_pos = self.bank_inst[i].get_pin(n).uc() - rail_pos = vector(pin_pos.x,self.data_bus_positions[n].y) - self.add_path("metal2",[pin_pos,rail_pos]) - self.add_via_center(("metal2","via2","metal3"),rail_pos) - - # route msb address bits - # route 2:4 decoder - self.route_double_msb_address() - - # connect the banks to the vertical address bus - # connect the banks to the vertical control bus - for n in self.addr_bus_names + self.control_bus_names: - # Skip these from the horizontal bus - if n in ["vdd", "gnd"]: continue - # This will be the bank select, so skip it - if n in self.msb_bank_sel_addr: continue - - for bank_id in [0,2]: - pin0_pos = self.bank_inst[bank_id].get_pin(n).rc() - pin1_pos = self.bank_inst[bank_id+1].get_pin(n).lc() - rail_pos = vector(self.vert_control_bus_positions[n].x,pin0_pos.y) - self.add_path("metal3",[pin0_pos,pin1_pos]) - self.add_via_center(("metal2","via2","metal3"),rail_pos) - - - self.route_bank_supply_rails(left_banks=[0,2], bottom_banks=[2,3]) - - - - + """ Layout creation """ + self.add_modules() + self.route() def compute_bus_sizes(self): """ Compute the independent bus widths shared between two and four bank SRAMs """ @@ -325,417 +184,70 @@ class sram(design.design): self.supply_bus_width = self.data_bus_width # Sanity check to ensure we can fit the control logic above a single bank (0.9 is a hack really) - debug.check(self.bank.width + self.vertical_bus_width > 0.9*self.control_logic.width, "Bank is too small compared to control logic.") + debug.check(self.bank.width + self.vertical_bus_width > 0.9*self.control_logic.width, + "Bank is too small compared to control logic.") - def compute_four_bank_offsets(self): - """ Compute the overall offsets for a four bank SRAM """ - - # The main difference is that the four bank SRAM has the data bus in the middle of the four banks - # as opposed to the top of the banks. - - # In 4 bank SRAM, the height is determined by the bank decoder and address flop - self.vertical_bus_height = 2*self.bank.height + 4*self.bank_to_bus_distance + self.data_bus_height \ - + self.supply_bus_height + self.msb_decoder.height + self.msb_address.width - # The address bus extends down through the power rails, but control and bank_sel bus don't - self.addr_bus_height = self.vertical_bus_height - - self.vertical_bus_offset = vector(self.bank.width + self.bank_to_bus_distance, 0) - self.data_bus_offset = vector(0, self.bank.height + self.bank_to_bus_distance) - self.supply_bus_offset = vector(0, self.data_bus_offset.y + self.data_bus_height + self.bank.height + 2*self.bank_to_bus_distance) - self.control_bus_offset = vector(0, self.supply_bus_offset.y + self.supply_bus_height) - self.bank_sel_bus_offset = self.vertical_bus_offset + vector(self.m2_pitch*self.control_size,0) - self.addr_bus_offset = self.bank_sel_bus_offset.scale(1,0) + vector(self.m2_pitch*self.num_banks,0) - - # Control is placed at the top above the control bus and everything - self.control_logic_position = vector(0, self.control_bus_offset.y + self.control_bus_height + self.m1_pitch) - - # Bank select flops get put to the right of control logic above bank1 and the buses - # Leave a pitch to get the vdd rails up to M2 - self.msb_address_position = vector(self.bank_inst[1].lx() + 3*self.supply_rail_pitch, - self.supply_bus_offset.y + self.supply_bus_height + 2*self.m1_pitch + self.msb_address.width) - - # Decoder goes above the MSB address flops, and is flipped in Y - # separate the two by a bank to bus distance for nwell rules, just in case - self.msb_decoder_position = self.msb_address_position + vector(self.msb_decoder.width, self.bank_to_bus_distance) - - - def compute_two_bank_offsets(self): - """ Compute the overall offsets for a two bank SRAM """ - - # In 2 bank SRAM, the height is determined by the control bus which is higher than the msb address - self.vertical_bus_height = self.bank.height + 2*self.bank_to_bus_distance + self.data_bus_height + self.control_bus_height - # The address bus extends down through the power rails, but control and bank_sel bus don't - self.addr_bus_height = self.vertical_bus_height - - self.vertical_bus_offset = vector(self.bank.width + self.bank_to_bus_distance, 0) - self.data_bus_offset = vector(0, self.bank.height + self.bank_to_bus_distance) - self.supply_bus_offset = vector(0, self.data_bus_offset.y + self.data_bus_height) - self.control_bus_offset = vector(0, self.supply_bus_offset.y + self.supply_bus_height) - self.bank_sel_bus_offset = self.vertical_bus_offset + vector(self.m2_pitch*self.control_size,0) - self.addr_bus_offset = self.bank_sel_bus_offset.scale(1,0) + vector(self.m2_pitch*self.num_banks,0) - - # Control is placed at the top above the control bus and everything - self.control_logic_position = vector(0, self.control_bus_offset.y + self.control_bus_height + self.m1_pitch) - - # Bank select flops get put to the right of control logic above bank1 and the buses - # Leave a pitch to get the vdd rails up to M2 - self.msb_address_position = vector(self.bank_inst[1].lx() + 3*self.supply_rail_pitch, - self.supply_bus_offset.y+self.supply_bus_height + 2*self.m1_pitch + self.msb_address.width) def add_busses(self): """ Add the horizontal and vertical busses """ # Vertical bus # The order of the control signals on the control bus: self.control_bus_names = ["clk_buf", "tri_en_bar", "tri_en", "clk_buf_bar", "w_en", "s_en"] - self.vert_control_bus_positions = self.create_bus(layer="metal2", - pitch=self.m2_pitch, - offset=self.vertical_bus_offset, - names=self.control_bus_names, - length=self.vertical_bus_height, - vertical=True) + self.vert_control_bus_positions = self.create_vertical_bus(layer="metal2", + pitch=self.m2_pitch, + offset=self.vertical_bus_offset, + names=self.control_bus_names, + length=self.vertical_bus_height) self.addr_bus_names=["A[{}]".format(i) for i in range(self.addr_size)] - self.vert_control_bus_positions.update(self.create_bus(layer="metal2", - pitch=self.m2_pitch, - offset=self.addr_bus_offset, - names=self.addr_bus_names, - length=self.addr_bus_height, - vertical=True, - make_pins=True)) + self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2", + pitch=self.m2_pitch, + offset=self.addr_bus_offset, + names=self.addr_bus_names, + length=self.addr_bus_height)) self.bank_sel_bus_names = ["bank_sel[{}]".format(i) for i in range(self.num_banks)] - self.vert_control_bus_positions.update(self.create_bus(layer="metal2", - pitch=self.m2_pitch, - offset=self.bank_sel_bus_offset, - names=self.bank_sel_bus_names, - length=self.vertical_bus_height, - vertical=True, - make_pins=True)) + self.vert_control_bus_positions.update(self.create_vertical_pin_bus(layer="metal2", + pitch=self.m2_pitch, + offset=self.bank_sel_bus_offset, + names=self.bank_sel_bus_names, + length=self.vertical_bus_height)) # Horizontal data bus self.data_bus_names = ["DATA[{}]".format(i) for i in range(self.word_size)] - self.data_bus_positions = self.create_bus(layer="metal3", - pitch=self.m3_pitch, - offset=self.data_bus_offset, - names=self.data_bus_names, - length=self.data_bus_width, - vertical=False, - make_pins=True) + self.data_bus_positions = self.create_horizontal_pin_bus(layer="metal3", + pitch=self.m3_pitch, + offset=self.data_bus_offset, + names=self.data_bus_names, + length=self.data_bus_width) # Horizontal control logic bus # vdd/gnd in bus go along whole SRAM # FIXME: Fatten these wires? - self.horz_control_bus_positions = self.create_bus(layer="metal1", - pitch=self.m1_pitch, - offset=self.supply_bus_offset, - names=["vdd"], - length=self.supply_bus_width, - vertical=False) + self.horz_control_bus_positions = self.create_horizontal_bus(layer="metal1", + pitch=self.m1_pitch, + offset=self.supply_bus_offset, + names=["vdd"], + length=self.supply_bus_width) # The gnd rail must not be the entire width since we protrude the right-most vdd rail up for # the decoder in 4-bank SRAMs - self.horz_control_bus_positions.update(self.create_bus(layer="metal1", - pitch=self.m1_pitch, - offset=self.supply_bus_offset+vector(0,self.m1_pitch), - names=["gnd"], - length=self.supply_bus_width, - vertical=False)) - self.horz_control_bus_positions.update(self.create_bus(layer="metal1", - pitch=self.m1_pitch, - offset=self.control_bus_offset, - names=self.control_bus_names, - length=self.control_bus_width, - vertical=False)) - - def add_two_bank_logic(self): - """ Add the control and MSB logic """ - - self.add_control_logic(position=self.control_logic_position) - - self.msb_address_inst = self.add_inst(name="msb_address", - mod=self.msb_address, - offset=self.msb_address_position, - rotate=270) - self.msb_bank_sel_addr = "ADDR[{}]".format(self.addr_size-1) - self.connect_inst([self.msb_bank_sel_addr,"bank_sel[1]","bank_sel[0]","clk_buf", "vdd", "gnd"]) - - def add_four_bank_logic(self): - """ Add the control and MSB decode/bank select logic for four banks """ - - - self.add_control_logic(position=self.control_logic_position) - - self.msb_address_inst = self.add_inst(name="msb_address", - mod=self.msb_address, - offset=self.msb_address_position, - rotate=270) - - self.msb_bank_sel_addr = ["ADDR[{}]".format(i) for i in range(self.addr_size-2,self.addr_size,1)] - temp = list(self.msb_bank_sel_addr) - temp.extend(["msb{0}[{1}]".format(j,i) for i in range(2) for j in ["","_bar"]]) - temp.extend(["clk_buf", "vdd", "gnd"]) - self.connect_inst(temp) - - self.msb_decoder_inst = self.add_inst(name="msb_decoder", - mod=self.msb_decoder, - offset=self.msb_decoder_position, - mirror="MY") - temp = ["msb[{}]".format(i) for i in range(2)] - temp.extend(["bank_sel[{}]".format(i) for i in range(4)]) - temp.extend(["vdd", "gnd"]) - self.connect_inst(temp) - - - def route_two_banks(self): - """ Route all of the signals for the two bank SRAM. """ - - self.route_shared_banks() - - # connect the horizontal control bus to the vertical bus - # connect the data output to the data bus - for n in self.data_bus_names: - for i in [0,1]: - pin_pos = self.bank_inst[i].get_pin(n).uc() - rail_pos = vector(pin_pos.x,self.data_bus_positions[n].y) - self.add_path("metal2",[pin_pos,rail_pos]) - self.add_via_center(("metal2","via2","metal3"),rail_pos) - - self.route_single_msb_address() - - # connect the banks to the vertical address bus - # connect the banks to the vertical control bus - for n in self.addr_bus_names + self.control_bus_names: - # Skip these from the horizontal bus - if n in ["vdd", "gnd"]: continue - # This will be the bank select, so skip it - if n == self.msb_bank_sel_addr: continue - pin0_pos = self.bank_inst[0].get_pin(n).rc() - pin1_pos = self.bank_inst[1].get_pin(n).lc() - rail_pos = vector(self.vert_control_bus_positions[n].x,pin0_pos.y) - self.add_path("metal3",[pin0_pos,pin1_pos]) - self.add_via_center(("metal2","via2","metal3"),rail_pos) - + self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1", + pitch=self.m1_pitch, + offset=self.supply_bus_offset+vector(0,self.m1_pitch), + names=["gnd"], + length=self.supply_bus_width)) + self.horz_control_bus_positions.update(self.create_horizontal_bus(layer="metal1", + pitch=self.m1_pitch, + offset=self.control_bus_offset, + names=self.control_bus_names, + length=self.control_bus_width)) - def route_double_msb_address(self): - """ Route two MSB address bits and the bank decoder for 4-bank SRAM """ - # connect the MSB flops to the address input bus - for i in [0,1]: - msb_pins = self.msb_address_inst.get_pins("din[{}]".format(i)) - for msb_pin in msb_pins: - if msb_pin.layer == "metal3": - msb_pin_pos = msb_pin.lc() - break - rail_pos = vector(self.vert_control_bus_positions[self.msb_bank_sel_addr[i]].x,msb_pin_pos.y) - self.add_path("metal3",[msb_pin_pos,rail_pos]) - self.add_via_center(("metal2","via2","metal3"),rail_pos) - # Connect clk - clk_pin = self.msb_address_inst.get_pin("clk") - clk_pos = clk_pin.bc() - rail_pos = self.horz_control_bus_positions["clk_buf"] - bend_pos = vector(clk_pos.x,self.horz_control_bus_positions["clk_buf"].y) - self.add_path("metal1",[clk_pos,bend_pos,rail_pos]) - - # Connect bank decoder outputs to the bank select vertical bus wires - for i in range(self.num_banks): - msb_pin = self.msb_decoder_inst.get_pin("out[{}]".format(i)) - msb_pin_pos = msb_pin.lc() - rail_pos = vector(self.vert_control_bus_positions["bank_sel[{}]".format(i)].x,msb_pin_pos.y) - self.add_path("metal1",[msb_pin_pos,rail_pos]) - self.add_via_center(("metal1","via1","metal2"),rail_pos) - - # connect MSB flop outputs to the bank decoder inputs - msb_pin = self.msb_address_inst.get_pin("dout[0]") - msb_pin_pos = msb_pin.rc() - in_pin = self.msb_decoder_inst.get_pin("in[0]") - in_pos = in_pin.bc() + vector(0,1*self.m2_pitch,) # pin is up from bottom - out_pos = msb_pin_pos + vector(1*self.m2_pitch,0) # route out to the right - up_pos = vector(out_pos.x,in_pos.y) # and route up to the decoer - self.add_wire(("metal1","via1","metal2"),[msb_pin_pos,out_pos,up_pos,in_pos]) - self.add_via_center(("metal1","via1","metal2"),in_pos) - self.add_via_center(("metal1","via1","metal2"),msb_pin_pos,rotate=90) - - msb_pin = self.msb_address_inst.get_pin("dout[1]") - msb_pin_pos = msb_pin.rc() - in_pin = self.msb_decoder_inst.get_pin("in[1]") - in_pos = in_pin.bc() + vector(0,self.bitcell.height+self.m2_pitch) # route the next row up - out_pos = msb_pin_pos + vector(2*self.m2_pitch,0) # route out to the right - up_pos = vector(out_pos.x,in_pos.y) # and route up to the decoer - self.add_wire(("metal1","via1","metal2"),[msb_pin_pos,out_pos,up_pos,in_pos]) - self.add_via_center(("metal1","via1","metal2"),in_pos) - self.add_via_center(("metal1","via1","metal2"),msb_pin_pos,rotate=90) - - self.route_double_msb_address_supplies() - - def route_double_msb_address_supplies(self): - """ Route the vdd/gnd bits of the 2-bit bank decoder. """ - - # Route the right-most vdd/gnd of the right upper bank to the top of the decoder - vdd_pins = self.bank_inst[1].get_pins("vdd") - left_bank_vdd_pin = None - right_bank_vdd_pin = None - for vdd_pin in vdd_pins: - if vdd_pin.layer != "metal2": - continue - if left_bank_vdd_pin == None or vdd_pin.lx()right_bank_vdd_pin.lx(): - right_bank_vdd_pin = vdd_pin - # Route to top - self.add_rect(layer="metal2", - offset=vdd_pin.ul(), - height=self.height-vdd_pin.uy(), - width=vdd_pin.width()) - - gnd_pins = self.bank_inst[1].get_pins("gnd") - left_bank_gnd_pin = None - right_bank_gnd_pin = None - for gnd_pin in gnd_pins: - if gnd_pin.layer != "metal2": - continue - if left_bank_gnd_pin == None or gnd_pin.lx()right_bank_gnd_pin.lx(): - right_bank_gnd_pin = gnd_pin - # Route to top - self.add_rect(layer="metal2", - offset=gnd_pin.ul(), - height=self.height-gnd_pin.uy(), - width=gnd_pin.width()) - - # Connect bank decoder vdd/gnd supplies using the previous bank pins - vdd_pins = self.msb_decoder_inst.get_pins("vdd") - for vdd_pin in vdd_pins: - if vdd_pin.layer != "metal1": - continue - rail1_pos = vector(left_bank_vdd_pin.cx(),vdd_pin.cy()) - rail2_pos = vector(right_bank_vdd_pin.cx(),vdd_pin.cy()) - self.add_path("metal1",[rail1_pos,rail2_pos]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=rail1_pos, - rotate=90, - size=[1,3]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=rail2_pos, - rotate=90, - size=[1,3]) - gnd_pins = self.msb_decoder_inst.get_pins("gnd") - for gnd_pin in gnd_pins: - if gnd_pin.layer != "metal1": - continue - rail1_pos = vector(left_bank_gnd_pin.cx(),gnd_pin.cy()) - rail2_pos = vector(right_bank_gnd_pin.cx(),gnd_pin.cy()) - self.add_path("metal1",[rail1_pos,rail2_pos]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=rail1_pos, - rotate=90, - size=[1,3]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=rail2_pos, - rotate=90, - size=[1,3]) - - # connect the bank MSB flop supplies - vdd_pins = self.msb_address_inst.get_pins("vdd") - # vdd pins go down to the rail - for vdd_pin in vdd_pins: - if vdd_pin.layer != "metal1": - continue - vdd_pos = vdd_pin.bc() - down_pos = vdd_pos - vector(0,self.m1_pitch) - rail_pos = vector(vdd_pos.x,self.horz_control_bus_positions["vdd"].y) - self.add_path("metal1",[vdd_pos,down_pos]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=down_pos, - rotate=90) - self.add_path("metal2",[down_pos,rail_pos]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=rail_pos) - # gnd pins go right to the rail - gnd_pins = self.msb_address_inst.get_pins("gnd") - for gnd_pin in gnd_pins: - if gnd_pin.layer != "metal2": - continue - rail1_pos = vector(left_bank_gnd_pin.cx(),gnd_pin.cy()) - self.add_path("metal1",[rail1_pos,gnd_pin.lc()]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=gnd_pin.lc(), - rotate=90) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=rail1_pos, - rotate=90, - size=[1,3]) - - def route_single_msb_address(self): - """ Route one MSB address bit for 2-bank SRAM """ - - # connect the bank MSB flop supplies - vdd_pins = self.msb_address_inst.get_pins("vdd") - for vdd_pin in vdd_pins: - if vdd_pin.layer != "metal1": continue - vdd_pos = vdd_pin.bc() - down_pos = vdd_pos - vector(0,self.m1_pitch) - rail_pos = vector(vdd_pos.x,self.horz_control_bus_positions["vdd"].y) - self.add_path("metal1",[vdd_pos,down_pos]) - self.add_via_center(("metal1","via1","metal2"),down_pos,rotate=90) - self.add_path("metal2",[down_pos,rail_pos]) - self.add_via_center(("metal1","via1","metal2"),rail_pos) - - gnd_pins = self.msb_address_inst.get_pins("gnd") - # Only add the ground connection to the lowest metal2 rail in the flop array - # FIXME: SCMOS doesn't have a vertical rail in the cell, or we could use those - lowest_y = None - for gnd_pin in gnd_pins: - if gnd_pin.layer != "metal2": continue - if lowest_y==None or gnd_pin.by()right_bank_vdd_pin.lx(): + right_bank_vdd_pin = vdd_pin + # Route to top + self.add_rect(layer="metal2", + offset=vdd_pin.ul(), + height=self.height-vdd_pin.uy(), + width=vdd_pin.width()) + + gnd_pins = self.bank_inst[1].get_pins("gnd") + left_bank_gnd_pin = None + right_bank_gnd_pin = None + for gnd_pin in gnd_pins: + if gnd_pin.layer != "metal2": + continue + if left_bank_gnd_pin == None or gnd_pin.lx()right_bank_gnd_pin.lx(): + right_bank_gnd_pin = gnd_pin + # Route to top + self.add_rect(layer="metal2", + offset=gnd_pin.ul(), + height=self.height-gnd_pin.uy(), + width=gnd_pin.width()) + + # Connect bank decoder vdd/gnd supplies using the previous bank pins + vdd_pins = self.msb_decoder_inst.get_pins("vdd") + for vdd_pin in vdd_pins: + if vdd_pin.layer != "metal1": + continue + rail1_pos = vector(left_bank_vdd_pin.cx(),vdd_pin.cy()) + rail2_pos = vector(right_bank_vdd_pin.cx(),vdd_pin.cy()) + self.add_path("metal1",[rail1_pos,rail2_pos]) + self.add_via_center(layers=("metal1","via1","metal2"), + offset=rail1_pos, + rotate=90, + size=[1,3]) + self.add_via_center(layers=("metal1","via1","metal2"), + offset=rail2_pos, + rotate=90, + size=[1,3]) + gnd_pins = self.msb_decoder_inst.get_pins("gnd") + for gnd_pin in gnd_pins: + if gnd_pin.layer != "metal1": + continue + rail1_pos = vector(left_bank_gnd_pin.cx(),gnd_pin.cy()) + rail2_pos = vector(right_bank_gnd_pin.cx(),gnd_pin.cy()) + self.add_path("metal1",[rail1_pos,rail2_pos]) + self.add_via_center(layers=("metal1","via1","metal2"), + offset=rail1_pos, + rotate=90, + size=[1,3]) + self.add_via_center(layers=("metal1","via1","metal2"), + offset=rail2_pos, + rotate=90, + size=[1,3]) + + # connect the bank MSB flop supplies + vdd_pins = self.msb_address_inst.get_pins("vdd") + # vdd pins go down to the rail + for vdd_pin in vdd_pins: + if vdd_pin.layer != "metal1": + continue + vdd_pos = vdd_pin.bc() + down_pos = vdd_pos - vector(0,self.m1_pitch) + rail_pos = vector(vdd_pos.x,self.horz_control_bus_positions["vdd"].y) + self.add_path("metal1",[vdd_pos,down_pos]) + self.add_via_center(layers=("metal1","via1","metal2"), + offset=down_pos, + rotate=90) + self.add_path("metal2",[down_pos,rail_pos]) + self.add_via_center(layers=("metal1","via1","metal2"), + offset=rail_pos) + # gnd pins go right to the rail + gnd_pins = self.msb_address_inst.get_pins("gnd") + for gnd_pin in gnd_pins: + if gnd_pin.layer != "metal2": + continue + rail1_pos = vector(left_bank_gnd_pin.cx(),gnd_pin.cy()) + self.add_path("metal1",[rail1_pos,gnd_pin.lc()]) + self.add_via_center(layers=("metal1","via1","metal2"), + offset=gnd_pin.lc(), + rotate=90) + self.add_via_center(layers=("metal1","via1","metal2"), + offset=rail1_pos, + rotate=90, + size=[1,3]) + + + def route(self): + """ Route all of the signals for the four bank SRAM. """ + + self.route_shared_banks() + + # connect the data output to the data bus + for n in self.data_bus_names: + for i in [0,1]: + pin_pos = self.bank_inst[i].get_pin(n).bc() + rail_pos = vector(pin_pos.x,self.data_bus_positions[n].y) + self.add_path("metal2",[pin_pos,rail_pos]) + self.add_via_center(("metal2","via2","metal3"),rail_pos) + + for i in [2,3]: + pin_pos = self.bank_inst[i].get_pin(n).uc() + rail_pos = vector(pin_pos.x,self.data_bus_positions[n].y) + self.add_path("metal2",[pin_pos,rail_pos]) + self.add_via_center(("metal2","via2","metal3"),rail_pos) + + # route msb address bits + # route 2:4 decoder + self.route_double_msb_address() + + # connect the banks to the vertical address bus + # connect the banks to the vertical control bus + for n in self.addr_bus_names + self.control_bus_names: + # Skip these from the horizontal bus + if n in ["vdd", "gnd"]: continue + # This will be the bank select, so skip it + if n in self.msb_bank_sel_addr: continue + + for bank_id in [0,2]: + pin0_pos = self.bank_inst[bank_id].get_pin(n).rc() + pin1_pos = self.bank_inst[bank_id+1].get_pin(n).lc() + rail_pos = vector(self.vert_control_bus_positions[n].x,pin0_pos.y) + self.add_path("metal3",[pin0_pos,pin1_pos]) + self.add_via_center(("metal2","via2","metal3"),rail_pos) + + + self.route_bank_supply_rails(left_banks=[0,2], bottom_banks=[2,3]) + + diff --git a/compiler/tests/01_library_drc_test.py b/compiler/tests/01_library_drc_test.py index e1f9506a..b809c14d 100755 --- a/compiler/tests/01_library_drc_test.py +++ b/compiler/tests/01_library_drc_test.py @@ -13,7 +13,6 @@ class library_drc_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - global verify import verify (gds_dir, gds_files) = setup_files() @@ -31,11 +30,12 @@ class library_drc_test(openram_test): self.assertEqual(drc_errors, 0) globals.end_openram() + def setup_files(): gds_dir = OPTS.openram_tech + "/gds_lib" files = os.listdir(gds_dir) nametest = re.compile("\.gds$", re.IGNORECASE) - gds_files = filter(nametest.search, files) + gds_files = list(filter(nametest.search, files)) return (gds_dir, gds_files) @@ -45,3 +45,4 @@ if __name__ == "__main__": del sys.argv[1:] header(__file__, OPTS.tech_name) unittest.main() + diff --git a/compiler/tests/02_library_lvs_test.py b/compiler/tests/02_library_lvs_test.py index 22f2d3d7..0b35f159 100755 --- a/compiler/tests/02_library_lvs_test.py +++ b/compiler/tests/02_library_lvs_test.py @@ -14,6 +14,7 @@ class library_lvs_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) import verify + (gds_dir, sp_dir, allnames) = setup_files() lvs_errors = 0 debug.info(1, "Performing LVS on: " + ", ".join(allnames)) @@ -28,7 +29,7 @@ class library_lvs_test(openram_test): lvs_errors += 1 debug.error("Missing SPICE file {}".format(gds_name)) lvs_errors += verify.run_lvs(f, gds_name, sp_name) - self.assertEqual(lvs_errors, 0) + # fail if the error count is not zero self.assertEqual(lvs_errors, 0) globals.end_openram() diff --git a/compiler/tests/03_contact_test.py b/compiler/tests/03_contact_test.py index cf1d5f8c..b5938cec 100755 --- a/compiler/tests/03_contact_test.py +++ b/compiler/tests/03_contact_test.py @@ -15,7 +15,6 @@ class contact_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import contact @@ -43,7 +42,6 @@ class contact_test(openram_test): c = contact.contact(layer_stack, (3, 3)) self.local_drc_check(c) - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/03_path_test.py b/compiler/tests/03_path_test.py index 7f8af2d9..88a195c4 100755 --- a/compiler/tests/03_path_test.py +++ b/compiler/tests/03_path_test.py @@ -15,8 +15,7 @@ class path_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False - + import path import tech import design @@ -84,8 +83,6 @@ class path_test(openram_test): path.path(w, layer_stack, position_list) self.local_drc_check(w) - # return it back to it's normal state - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/03_ptx_1finger_nmos_test.py b/compiler/tests/03_ptx_1finger_nmos_test.py index af87aa1f..02ef0f2b 100755 --- a/compiler/tests/03_ptx_1finger_nmos_test.py +++ b/compiler/tests/03_ptx_1finger_nmos_test.py @@ -15,7 +15,6 @@ class ptx_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import ptx import tech @@ -26,7 +25,6 @@ class ptx_test(openram_test): tx_type="nmos") self.local_drc_check(fet) - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/03_ptx_1finger_pmos_test.py b/compiler/tests/03_ptx_1finger_pmos_test.py index 6b13b5c4..c00ccb72 100755 --- a/compiler/tests/03_ptx_1finger_pmos_test.py +++ b/compiler/tests/03_ptx_1finger_pmos_test.py @@ -15,7 +15,6 @@ class ptx_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import ptx import tech @@ -26,7 +25,6 @@ class ptx_test(openram_test): tx_type="pmos") self.local_drc_check(fet) - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/03_ptx_3finger_nmos_test.py b/compiler/tests/03_ptx_3finger_nmos_test.py index 1a68bbcf..60293266 100755 --- a/compiler/tests/03_ptx_3finger_nmos_test.py +++ b/compiler/tests/03_ptx_3finger_nmos_test.py @@ -15,7 +15,6 @@ class ptx_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import ptx import tech @@ -28,7 +27,6 @@ class ptx_test(openram_test): connect_poly=True) self.local_drc_check(fet) - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/03_ptx_3finger_pmos_test.py b/compiler/tests/03_ptx_3finger_pmos_test.py index e3570f1a..792de25f 100755 --- a/compiler/tests/03_ptx_3finger_pmos_test.py +++ b/compiler/tests/03_ptx_3finger_pmos_test.py @@ -15,7 +15,6 @@ class ptx_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import ptx import tech @@ -28,7 +27,6 @@ class ptx_test(openram_test): connect_poly=True) self.local_drc_check(fet) - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/03_ptx_4finger_nmos_test.py b/compiler/tests/03_ptx_4finger_nmos_test.py index 45722501..d4cc0da5 100755 --- a/compiler/tests/03_ptx_4finger_nmos_test.py +++ b/compiler/tests/03_ptx_4finger_nmos_test.py @@ -15,7 +15,6 @@ class ptx_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import ptx import tech @@ -28,7 +27,6 @@ class ptx_test(openram_test): connect_poly=True) self.local_drc_check(fet) - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/03_ptx_4finger_pmos_test.py b/compiler/tests/03_ptx_4finger_pmos_test.py index fb7dfd6c..c35390c9 100755 --- a/compiler/tests/03_ptx_4finger_pmos_test.py +++ b/compiler/tests/03_ptx_4finger_pmos_test.py @@ -15,7 +15,6 @@ class ptx_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import ptx import tech @@ -28,7 +27,6 @@ class ptx_test(openram_test): connect_poly=True) self.local_drc_check(fet) - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/03_wire_test.py b/compiler/tests/03_wire_test.py index 17abe160..cf50dc10 100755 --- a/compiler/tests/03_wire_test.py +++ b/compiler/tests/03_wire_test.py @@ -15,7 +15,6 @@ class wire_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import wire import tech @@ -122,8 +121,6 @@ class wire_test(openram_test): wire.wire(w, layer_stack, position_list) self.local_drc_check(w) - # return it back to it's normal state - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/04_pbitcell_test.py b/compiler/tests/04_pbitcell_test.py index 8a684839..b2eb7fb5 100755 --- a/compiler/tests/04_pbitcell_test.py +++ b/compiler/tests/04_pbitcell_test.py @@ -22,7 +22,6 @@ class pbitcell_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import pbitcell import tech @@ -67,9 +66,8 @@ class pbitcell_test(openram_test): tx = pbitcell.pbitcell(num_readwrite=2,num_write=0,num_read=0) self.local_check(tx) - OPTS.check_lvsdrc = True globals.end_openram() - OPTS.bitcell = "bitcell" + # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/04_pinv_10x_test.py b/compiler/tests/04_pinv_10x_test.py index 4e396b83..09eef9c3 100755 --- a/compiler/tests/04_pinv_10x_test.py +++ b/compiler/tests/04_pinv_10x_test.py @@ -17,7 +17,6 @@ class pinv_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import pinv import tech @@ -26,7 +25,6 @@ class pinv_test(openram_test): tx = pinv.pinv(size=8) self.local_check(tx) - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/04_pinv_1x_beta_test.py b/compiler/tests/04_pinv_1x_beta_test.py index d8c98ea6..17829e14 100755 --- a/compiler/tests/04_pinv_1x_beta_test.py +++ b/compiler/tests/04_pinv_1x_beta_test.py @@ -17,7 +17,6 @@ class pinv_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import pinv import tech @@ -26,7 +25,6 @@ class pinv_test(openram_test): tx = pinv.pinv(size=1, beta=3) self.local_check(tx) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/04_pinv_1x_test.py b/compiler/tests/04_pinv_1x_test.py index fa36a280..a0db1100 100755 --- a/compiler/tests/04_pinv_1x_test.py +++ b/compiler/tests/04_pinv_1x_test.py @@ -16,7 +16,6 @@ class pinv_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import pinv @@ -26,7 +25,6 @@ class pinv_test(openram_test): tx = pinv.pinv(size=1) self.local_check(tx) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/04_pinv_2x_test.py b/compiler/tests/04_pinv_2x_test.py index bedb259f..66ea15da 100755 --- a/compiler/tests/04_pinv_2x_test.py +++ b/compiler/tests/04_pinv_2x_test.py @@ -17,7 +17,6 @@ class pinv_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import pinv import tech @@ -26,7 +25,6 @@ class pinv_test(openram_test): tx = pinv.pinv(size=2) self.local_check(tx) - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/04_pinvbuf_test.py b/compiler/tests/04_pinvbuf_test.py index 3fc5e3c3..ffe6fa33 100755 --- a/compiler/tests/04_pinvbuf_test.py +++ b/compiler/tests/04_pinvbuf_test.py @@ -17,7 +17,6 @@ class pinvbuf_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import pinvbuf @@ -25,7 +24,6 @@ class pinvbuf_test(openram_test): a = pinvbuf.pinvbuf(4,8) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/04_pnand2_test.py b/compiler/tests/04_pnand2_test.py index adf3a4e8..af35bae8 100755 --- a/compiler/tests/04_pnand2_test.py +++ b/compiler/tests/04_pnand2_test.py @@ -19,7 +19,6 @@ class pnand2_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import pnand2 import tech @@ -28,7 +27,6 @@ class pnand2_test(openram_test): tx = pnand2.pnand2(size=1) self.local_check(tx) - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/04_pnand3_test.py b/compiler/tests/04_pnand3_test.py index 594be7ff..6984a0e0 100755 --- a/compiler/tests/04_pnand3_test.py +++ b/compiler/tests/04_pnand3_test.py @@ -19,7 +19,6 @@ class pnand3_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import pnand3 import tech @@ -28,7 +27,6 @@ class pnand3_test(openram_test): tx = pnand3.pnand3(size=1) self.local_check(tx) - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/04_pnor2_test.py b/compiler/tests/04_pnor2_test.py index fe18bd4c..a15f6907 100755 --- a/compiler/tests/04_pnor2_test.py +++ b/compiler/tests/04_pnor2_test.py @@ -19,7 +19,6 @@ class pnor2_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import pnor2 import tech @@ -28,7 +27,6 @@ class pnor2_test(openram_test): tx = pnor2.pnor2(size=1) self.local_check(tx) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/04_precharge_test.py b/compiler/tests/04_precharge_test.py index 018f6ef7..55460289 100755 --- a/compiler/tests/04_precharge_test.py +++ b/compiler/tests/04_precharge_test.py @@ -17,7 +17,6 @@ class precharge_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import precharge import tech @@ -26,7 +25,6 @@ class precharge_test(openram_test): tx = precharge.precharge(name="precharge_driver", size=1) self.local_check(tx) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/04_single_level_column_mux_test.py b/compiler/tests/04_single_level_column_mux_test.py index 494fcd84..d282a11a 100755 --- a/compiler/tests/04_single_level_column_mux_test.py +++ b/compiler/tests/04_single_level_column_mux_test.py @@ -19,7 +19,6 @@ class single_level_column_mux_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import single_level_column_mux import tech @@ -28,7 +27,6 @@ class single_level_column_mux_test(openram_test): tx = single_level_column_mux.single_level_column_mux(tx_size=8) self.local_check(tx) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/05_bitcell_array_test.py b/compiler/tests/05_bitcell_array_test.py index 849e6666..37649ad5 100755 --- a/compiler/tests/05_bitcell_array_test.py +++ b/compiler/tests/05_bitcell_array_test.py @@ -19,7 +19,6 @@ class array_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import bitcell_array @@ -27,7 +26,6 @@ class array_test(openram_test): a = bitcell_array.bitcell_array(name="bitcell_array", cols=4, rows=4) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/05_pbitcell_array_test.py b/compiler/tests/05_pbitcell_array_test.py index c4ad0b32..081c4d51 100644 --- a/compiler/tests/05_pbitcell_array_test.py +++ b/compiler/tests/05_pbitcell_array_test.py @@ -11,27 +11,26 @@ import globals from globals import OPTS import debug -#@unittest.skip("SKIPPING 05_array_multiport_test") - -class array_multiport_test(openram_test): +#@unittest.skip("SKIPPING 05_pbitcell_array_test") +class pbitcell_array_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import bitcell_array + debug.info(2, "Testing 4x4 array for multiport bitcell, with read ports at the edge of the bit cell") OPTS.bitcell = "pbitcell" OPTS.rw_ports = 2 OPTS.r_ports = 2 OPTS.w_ports = 2 - - debug.info(2, "Testing 4x4 array for multiport bitcell, with read ports at the edge of the bit cell") a = bitcell_array.bitcell_array(name="pbitcell_array", cols=4, rows=4) self.local_check(a) - + + debug.info(2, "Testing 4x4 array for multiport bitcell, with read/write ports at the edge of the bit cell") + OPTS.bitcell = "pbitcell" OPTS.rw_ports = 2 OPTS.r_ports = 0 OPTS.w_ports = 2 @@ -47,10 +46,12 @@ class array_multiport_test(openram_test): debug.info(2, "Testing 4x4 array for multiport bitcell, with read/write ports at the edge of the bit cell") a = bitcell_array.bitcell_array(name="pbitcell_array", cols=4, rows=4) self.local_check(a) + a = bitcell_array.bitcell_array(name="pbitcell_array", cols=4, rows=4) + self.local_check(a) - OPTS.bitcell = "bitcell" OPTS.check_lvsdrc = True globals.end_openram() + OPTS.bitcell = "bitcell" # instantiate a copy of the class to actually run the test if __name__ == "__main__": diff --git a/compiler/tests/06_hierarchical_decoder_test.py b/compiler/tests/06_hierarchical_decoder_test.py index 48cae531..eb0b105a 100755 --- a/compiler/tests/06_hierarchical_decoder_test.py +++ b/compiler/tests/06_hierarchical_decoder_test.py @@ -17,7 +17,6 @@ class hierarchical_decoder_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import hierarchical_decoder import tech @@ -48,7 +47,6 @@ class hierarchical_decoder_test(openram_test): a = hierarchical_decoder.hierarchical_decoder(rows=512) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/06_hierarchical_predecode2x4_test.py b/compiler/tests/06_hierarchical_predecode2x4_test.py index 021f53b6..79db3665 100755 --- a/compiler/tests/06_hierarchical_predecode2x4_test.py +++ b/compiler/tests/06_hierarchical_predecode2x4_test.py @@ -17,7 +17,6 @@ class hierarchical_predecode2x4_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import hierarchical_predecode2x4 as pre import tech @@ -26,7 +25,6 @@ class hierarchical_predecode2x4_test(openram_test): a = pre.hierarchical_predecode2x4() self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/06_hierarchical_predecode3x8_test.py b/compiler/tests/06_hierarchical_predecode3x8_test.py index e6bcda2d..b6609829 100755 --- a/compiler/tests/06_hierarchical_predecode3x8_test.py +++ b/compiler/tests/06_hierarchical_predecode3x8_test.py @@ -17,7 +17,6 @@ class hierarchical_predecode3x8_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import hierarchical_predecode3x8 as pre import tech @@ -26,7 +25,6 @@ class hierarchical_predecode3x8_test(openram_test): a = pre.hierarchical_predecode3x8() self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/07_single_level_column_mux_array_test.py b/compiler/tests/07_single_level_column_mux_array_test.py index 120f1093..1becd179 100755 --- a/compiler/tests/07_single_level_column_mux_array_test.py +++ b/compiler/tests/07_single_level_column_mux_array_test.py @@ -16,7 +16,6 @@ class single_level_column_mux_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import single_level_column_mux_array @@ -32,7 +31,6 @@ class single_level_column_mux_test(openram_test): a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/08_precharge_array_test.py b/compiler/tests/08_precharge_array_test.py index 84eaf6ea..d4a3190f 100755 --- a/compiler/tests/08_precharge_array_test.py +++ b/compiler/tests/08_precharge_array_test.py @@ -17,7 +17,6 @@ class precharge_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import precharge_array import tech @@ -26,7 +25,6 @@ class precharge_test(openram_test): pc = precharge_array.precharge_array(columns=3) self.local_check(pc) - OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/08_wordline_driver_test.py b/compiler/tests/08_wordline_driver_test.py index 1688bb5b..af97f018 100755 --- a/compiler/tests/08_wordline_driver_test.py +++ b/compiler/tests/08_wordline_driver_test.py @@ -19,7 +19,6 @@ class wordline_driver_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import wordline_driver import tech @@ -28,7 +27,6 @@ class wordline_driver_test(openram_test): tx = wordline_driver.wordline_driver(rows=8) self.local_check(tx) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/09_sense_amp_array_test.py b/compiler/tests/09_sense_amp_array_test.py index db1adf75..ba483218 100755 --- a/compiler/tests/09_sense_amp_array_test.py +++ b/compiler/tests/09_sense_amp_array_test.py @@ -17,7 +17,6 @@ class sense_amp_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import sense_amp_array @@ -30,7 +29,6 @@ class sense_amp_test(openram_test): a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/10_write_driver_array_test.py b/compiler/tests/10_write_driver_array_test.py index bc47d3ab..d7f1f7ec 100755 --- a/compiler/tests/10_write_driver_array_test.py +++ b/compiler/tests/10_write_driver_array_test.py @@ -17,7 +17,6 @@ class write_driver_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import write_driver_array @@ -29,7 +28,6 @@ class write_driver_test(openram_test): a = write_driver_array.write_driver_array(columns=16, word_size=8) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/11_dff_array_test.py b/compiler/tests/11_dff_array_test.py index a194ddad..e85056e9 100755 --- a/compiler/tests/11_dff_array_test.py +++ b/compiler/tests/11_dff_array_test.py @@ -17,7 +17,6 @@ class dff_array_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import dff_array @@ -33,7 +32,6 @@ class dff_array_test(openram_test): a = dff_array.dff_array(rows=3, columns=1) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/11_dff_buf_array_test.py b/compiler/tests/11_dff_buf_array_test.py index dc1af1e7..6c40e447 100755 --- a/compiler/tests/11_dff_buf_array_test.py +++ b/compiler/tests/11_dff_buf_array_test.py @@ -17,7 +17,6 @@ class dff_buf_array_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import dff_buf_array @@ -33,7 +32,6 @@ class dff_buf_array_test(openram_test): a = dff_buf_array.dff_buf_array(rows=3, columns=1) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/11_dff_buf_test.py b/compiler/tests/11_dff_buf_test.py index 22d0e3cb..44aca54c 100755 --- a/compiler/tests/11_dff_buf_test.py +++ b/compiler/tests/11_dff_buf_test.py @@ -17,7 +17,6 @@ class dff_buf_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import dff_buf @@ -25,7 +24,6 @@ class dff_buf_test(openram_test): a = dff_buf.dff_buf(4, 8) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/11_dff_inv_array_test.py b/compiler/tests/11_dff_inv_array_test.py index 4781d199..3d2b8cac 100755 --- a/compiler/tests/11_dff_inv_array_test.py +++ b/compiler/tests/11_dff_inv_array_test.py @@ -17,7 +17,6 @@ class dff_inv_array_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import dff_inv_array @@ -33,7 +32,6 @@ class dff_inv_array_test(openram_test): a = dff_inv_array.dff_inv_array(rows=3, columns=1) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/11_dff_inv_test.py b/compiler/tests/11_dff_inv_test.py index a20f2df5..b09a6591 100755 --- a/compiler/tests/11_dff_inv_test.py +++ b/compiler/tests/11_dff_inv_test.py @@ -17,7 +17,6 @@ class dff_inv_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import dff_inv @@ -25,7 +24,6 @@ class dff_inv_test(openram_test): a = dff_inv.dff_inv(4) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/11_ms_flop_array_test.py b/compiler/tests/11_ms_flop_array_test.py index 050afd71..97ef6ece 100755 --- a/compiler/tests/11_ms_flop_array_test.py +++ b/compiler/tests/11_ms_flop_array_test.py @@ -17,7 +17,6 @@ class dff_array_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import ms_flop_array @@ -29,7 +28,6 @@ class dff_array_test(openram_test): a = ms_flop_array.ms_flop_array(columns=16, word_size=8) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/12_tri_gate_array_test.py b/compiler/tests/12_tri_gate_array_test.py index 9f61a5b6..08d1596d 100755 --- a/compiler/tests/12_tri_gate_array_test.py +++ b/compiler/tests/12_tri_gate_array_test.py @@ -17,7 +17,6 @@ class tri_gate_array_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import tri_gate_array @@ -29,7 +28,6 @@ class tri_gate_array_test(openram_test): a = tri_gate_array.tri_gate_array(columns=16, word_size=8) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/13_delay_chain_test.py b/compiler/tests/13_delay_chain_test.py index ef2d1a85..d8a2d67c 100755 --- a/compiler/tests/13_delay_chain_test.py +++ b/compiler/tests/13_delay_chain_test.py @@ -17,7 +17,6 @@ class delay_chain_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import delay_chain @@ -25,7 +24,6 @@ class delay_chain_test(openram_test): a = delay_chain.delay_chain(fanout_list=[4, 4, 4, 4]) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/14_replica_bitline_test.py b/compiler/tests/14_replica_bitline_test.py index 97598693..b393c136 100755 --- a/compiler/tests/14_replica_bitline_test.py +++ b/compiler/tests/14_replica_bitline_test.py @@ -17,7 +17,6 @@ class replica_bitline_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import replica_bitline @@ -34,7 +33,6 @@ class replica_bitline_test(openram_test): a = replica_bitline.replica_bitline(stages,fanout,rows) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/16_control_logic_test.py b/compiler/tests/16_control_logic_test.py index 231e2440..7aeb54c1 100755 --- a/compiler/tests/16_control_logic_test.py +++ b/compiler/tests/16_control_logic_test.py @@ -17,7 +17,6 @@ class control_logic_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import control_logic import tech @@ -26,7 +25,6 @@ class control_logic_test(openram_test): a = control_logic.control_logic(num_rows=128) self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/19_bank_select_test.py b/compiler/tests/19_bank_select_test.py index 025e4cc4..955c7b4e 100755 --- a/compiler/tests/19_bank_select_test.py +++ b/compiler/tests/19_bank_select_test.py @@ -17,7 +17,6 @@ class bank_select_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import bank_select @@ -25,7 +24,6 @@ class bank_select_test(openram_test): a = bank_select.bank_select() self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/19_multi_bank_test.py b/compiler/tests/19_multi_bank_test.py index 088b810b..1a900f4c 100755 --- a/compiler/tests/19_multi_bank_test.py +++ b/compiler/tests/19_multi_bank_test.py @@ -17,7 +17,6 @@ class multi_bank_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import bank @@ -37,7 +36,6 @@ class multi_bank_test(openram_test): a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="bank4_multi") self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/19_single_bank_test.py b/compiler/tests/19_single_bank_test.py index 4b4ba7df..5bbc60ad 100755 --- a/compiler/tests/19_single_bank_test.py +++ b/compiler/tests/19_single_bank_test.py @@ -17,7 +17,6 @@ class single_bank_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import bank @@ -38,7 +37,6 @@ class single_bank_test(openram_test): a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=1, name="bank4_single") self.local_check(a) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/20_sram_1bank_test.py b/compiler/tests/20_sram_1bank_test.py index 8289191b..6bc738dd 100755 --- a/compiler/tests/20_sram_1bank_test.py +++ b/compiler/tests/20_sram_1bank_test.py @@ -17,7 +17,6 @@ class sram_1bank_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import sram @@ -37,7 +36,6 @@ class sram_1bank_test(openram_test): # a = sram.sram(word_size=2, num_words=128, num_banks=1, name="sram4") # self.local_check(a, final_verification=True) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/20_sram_2bank_test.py b/compiler/tests/20_sram_2bank_test.py index 9334040a..7ae6bf13 100755 --- a/compiler/tests/20_sram_2bank_test.py +++ b/compiler/tests/20_sram_2bank_test.py @@ -18,7 +18,6 @@ class sram_2bank_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import sram @@ -38,7 +37,6 @@ class sram_2bank_test(openram_test): # a = sram.sram(word_size=2, num_words=256 num_banks=2, name="sram4") # self.local_check(a, final_verification=True) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/20_sram_4bank_test.py b/compiler/tests/20_sram_4bank_test.py index 2e8bfefc..3fb69dc9 100755 --- a/compiler/tests/20_sram_4bank_test.py +++ b/compiler/tests/20_sram_4bank_test.py @@ -18,7 +18,6 @@ class sram_4bank_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) global verify import verify - OPTS.check_lvsdrc = False import sram @@ -38,7 +37,6 @@ class sram_4bank_test(openram_test): # a = sram.sram(word_size=2, num_words=256, num_banks=4, name="sram4") # self.local_check(a, final_verification=True) - OPTS.check_lvsdrc = True globals.end_openram() # instantiate a copy of the class to actually run the test diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index 9ac3db2e..289f3934 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -15,9 +15,9 @@ class timing_sram_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - OPTS.check_lvsdrc = False OPTS.spice_name="hspice" OPTS.analytical_delay = False + # This is a hack to reload the characterizer __init__ with the spice version from importlib import reload @@ -35,7 +35,6 @@ class timing_sram_test(openram_test): num_banks=OPTS.num_banks, name="sram1") - OPTS.check_lvsdrc = True tempspice = OPTS.openram_temp + "temp.sp" s.sp_write(tempspice) @@ -85,12 +84,6 @@ class timing_sram_test(openram_test): else: self.isclose(data[k],golden_data[k],0.15) - - # reset these options - OPTS.check_lvsdrc = True - OPTS.analytical_delay = True - reload(characterizer) - globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/21_hspice_setuphold_test.py b/compiler/tests/21_hspice_setuphold_test.py index 78403a56..f9d8a01c 100755 --- a/compiler/tests/21_hspice_setuphold_test.py +++ b/compiler/tests/21_hspice_setuphold_test.py @@ -15,7 +15,6 @@ class timing_setup_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - OPTS.check_lvsdrc = False OPTS.spice_name="hspice" OPTS.analytical_delay = False @@ -27,7 +26,6 @@ class timing_setup_test(openram_test): if not OPTS.spice_exe: debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1) - import sram import tech slews = [tech.spice["rise_time"]*2] @@ -59,9 +57,6 @@ class timing_setup_test(openram_test): else: self.isclose(data[k],golden_data[k],0.15) - OPTS.check_lvsdrc = True - OPTS.analytical_delay = True - reload(characterizer) globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py index 7f7bfd39..739d63ea 100755 --- a/compiler/tests/21_ngspice_delay_test.py +++ b/compiler/tests/21_ngspice_delay_test.py @@ -15,7 +15,6 @@ class timing_sram_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - OPTS.check_lvsdrc = False OPTS.spice_name="ngspice" OPTS.analytical_delay = False @@ -84,12 +83,6 @@ class timing_sram_test(openram_test): else: self.isclose(data[k],golden_data[k],0.15) - # reset these options - OPTS.check_lvsdrc = True - OPTS.spice_name="hspice" - OPTS.analytical_delay = True - reload(characterizer) - globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/21_ngspice_setuphold_test.py b/compiler/tests/21_ngspice_setuphold_test.py index 9a8ff67c..24c69aa7 100755 --- a/compiler/tests/21_ngspice_setuphold_test.py +++ b/compiler/tests/21_ngspice_setuphold_test.py @@ -15,7 +15,6 @@ class timing_setup_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - OPTS.check_lvsdrc = False OPTS.spice_name="ngspice" OPTS.analytical_delay = False @@ -58,12 +57,7 @@ class timing_setup_test(openram_test): else: self.isclose(data[k],golden_data[k],0.15) - # reset these options - OPTS.check_lvsdrc = True - OPTS.spice_name="hspice" - OPTS.analytical_delay = True reload(characterizer) - globals.end_openram() # instantiate a copdsay of the class to actually run the test diff --git a/compiler/tests/22_pex_test.py b/compiler/tests/22_pex_test.py old mode 100644 new mode 100755 index fbde5145..24cb7733 --- a/compiler/tests/22_pex_test.py +++ b/compiler/tests/22_pex_test.py @@ -11,11 +11,22 @@ import globals from globals import OPTS import debug -@unittest.skip("SKIPPING 22_sram_func_test") +@unittest.skip("SKIPPING 22_sram_pex_test") class sram_func_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) + + 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) + global verify import verify @@ -31,14 +42,10 @@ class sram_func_test(openram_test): import tech debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") - OPTS.check_lvsdrc = False - OPTS.use_pex = True s = sram.sram(word_size=OPTS.word_size, num_words=OPTS.num_words, num_banks=OPTS.num_banks, name="test_sram1") - OPTS.check_lvsdrc = True - OPTS.use_pex = False tempspice = OPTS.openram_temp + "temp.sp" tempgds = OPTS.openram_temp + "temp.gds" @@ -90,7 +97,7 @@ class sram_func_test(openram_test): self.assertTrue(round(value1) > 0.5 * tech.spice["supply_voltage"]) self.assertTrue(round(value2) < 0.5 * tech.spice["supply_voltage"]) - OPTS.check_lvsdrc = True + def convert_voltage_unit(self, string): newstring = "" diff --git a/compiler/tests/22_sram_func_test.py b/compiler/tests/22_sram_func_test.py index 63b8bdd2..22443c5a 100755 --- a/compiler/tests/22_sram_func_test.py +++ b/compiler/tests/22_sram_func_test.py @@ -11,12 +11,11 @@ import globals from globals import OPTS import debug +@unittest.skip("SKIPPING 22_sram_func_test") class sram_func_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - OPTS.check_lvsdrc = False - OPTS.spice_name="" # Unset to use any simulator OPTS.analytical_delay = False # This is a hack to reload the characterizer __init__ with the spice version @@ -35,8 +34,6 @@ class sram_func_test(openram_test): num_banks=1, name="sram_func_test") - OPTS.check_lvsdrc = True - tempspice = OPTS.openram_temp + "temp.sp" s.sp_write(tempspice) @@ -45,7 +42,7 @@ class sram_func_test(openram_test): debug.info(1, "Probe address {0} probe data {1}".format(probe_address, probe_data)) corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - d = delay.delay(s,tempspice,corner) + d = delay(s,tempspice,corner) d.set_probe(probe_address,probe_data) # This will exit if it doesn't find a feasible period @@ -55,7 +52,7 @@ class sram_func_test(openram_test): feasible_period = d.find_feasible_period() os.remove(tempspice) - OPTS.analytical_delay = True + reload(characterizer) globals.end_openram() diff --git a/compiler/tests/23_lib_sram_model_test.py b/compiler/tests/23_lib_sram_model_test.py index 9eb8ac5b..2691de48 100755 --- a/compiler/tests/23_lib_sram_model_test.py +++ b/compiler/tests/23_lib_sram_model_test.py @@ -15,7 +15,6 @@ class lib_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - OPTS.check_lvsdrc = False import sram from characterizer import lib @@ -25,8 +24,7 @@ class lib_test(openram_test): num_words=16, num_banks=1, name="sram_2_16_1_{0}".format(OPTS.tech_name)) - OPTS.check_lvsdrc = True - + tempspice = OPTS.openram_temp + "temp.sp" s.sp_write(tempspice) diff --git a/compiler/tests/23_lib_sram_prune_test.py b/compiler/tests/23_lib_sram_prune_test.py index 4227bc44..b2f45d8a 100755 --- a/compiler/tests/23_lib_sram_prune_test.py +++ b/compiler/tests/23_lib_sram_prune_test.py @@ -15,8 +15,6 @@ class lib_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - OPTS.check_lvsdrc = False - OPTS.spice_name="" # Unset to use any simulator OPTS.analytical_delay = False OPTS.trim_netlist = True @@ -35,7 +33,6 @@ class lib_test(openram_test): num_words=16, num_banks=1, name="sram_2_16_1_{0}".format(OPTS.tech_name)) - OPTS.check_lvsdrc = True tempspice = OPTS.openram_temp + "temp.sp" s.sp_write(tempspice) @@ -54,7 +51,6 @@ class lib_test(openram_test): golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),newname) self.isapproxdiff(libname,golden,0.40) - OPTS.analytical_delay = True reload(characterizer) globals.end_openram() diff --git a/compiler/tests/23_lib_sram_test.py b/compiler/tests/23_lib_sram_test.py index 46750250..80f34064 100755 --- a/compiler/tests/23_lib_sram_test.py +++ b/compiler/tests/23_lib_sram_test.py @@ -15,8 +15,6 @@ class lib_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - OPTS.check_lvsdrc = False - OPTS.spice_name="" # Unset to use any simulator OPTS.analytical_delay = False OPTS.trim_netlist = False @@ -35,7 +33,6 @@ class lib_test(openram_test): num_words=16, num_banks=1, name="sram_2_16_1_{0}".format(OPTS.tech_name)) - OPTS.check_lvsdrc = True tempspice = OPTS.openram_temp + "temp.sp" s.sp_write(tempspice) @@ -53,8 +50,6 @@ class lib_test(openram_test): golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename) self.isapproxdiff(libname,golden,0.40) - OPTS.analytical_delay = True - OPTS.trim_netlist = True reload(characterizer) globals.end_openram() diff --git a/compiler/tests/24_lef_sram_test.py b/compiler/tests/24_lef_sram_test.py index 4cd654ae..fbd16034 100755 --- a/compiler/tests/24_lef_sram_test.py +++ b/compiler/tests/24_lef_sram_test.py @@ -15,8 +15,6 @@ class lef_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - # we will manually run lvs/drc - OPTS.check_lvsdrc = False import sram @@ -26,8 +24,6 @@ class lef_test(openram_test): num_banks=OPTS.num_banks, name="sram_2_16_1_{0}".format(OPTS.tech_name)) - OPTS.check_lvsdrc = True - gdsfile = s.name + ".gds" leffile = s.name + ".lef" gdsname = OPTS.openram_temp + gdsfile diff --git a/compiler/tests/25_verilog_sram_test.py b/compiler/tests/25_verilog_sram_test.py index 8ceb093b..fe0be3d9 100755 --- a/compiler/tests/25_verilog_sram_test.py +++ b/compiler/tests/25_verilog_sram_test.py @@ -15,8 +15,6 @@ class verilog_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - # we will manually run lvs/drc - OPTS.check_lvsdrc = False import sram @@ -26,8 +24,6 @@ class verilog_test(openram_test): num_banks=OPTS.num_banks, name="sram_2_16_1_{0}".format(OPTS.tech_name)) - OPTS.check_lvsdrc = True - vfile = s.name + ".v" vname = OPTS.openram_temp + vfile s.verilog_write(vname) diff --git a/compiler/tests/30_openram_test.py b/compiler/tests/30_openram_test.py index 02fa4759..51546ae3 100755 --- a/compiler/tests/30_openram_test.py +++ b/compiler/tests/30_openram_test.py @@ -12,6 +12,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +import getpass class openram_test(openram_test): @@ -72,10 +73,7 @@ class openram_test(openram_test): shutil.rmtree(out_path, ignore_errors=True) self.assertEqual(os.path.exists(out_path),False) - # The default was on, so disable it. - OPTS.check_lvsdrc=False globals.end_openram() - OPTS.check_lvsdrc=True # instantiate a copy of the class to actually run the test if __name__ == "__main__": diff --git a/compiler/tests/regress.py b/compiler/tests/regress.py index daf9f3b6..d97def2b 100755 --- a/compiler/tests/regress.py +++ b/compiler/tests/regress.py @@ -27,5 +27,13 @@ modules = map(__import__, moduleNames) suite = unittest.TestSuite() load = unittest.defaultTestLoader.loadTestsFromModule suite.addTests(map(load, modules)) -ret = not unittest.TextTestRunner(verbosity=2).run(suite).wasSuccessful() -sys.exit(ret) + +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() + +sys.exit(not test_result.wasSuccessful()) diff --git a/compiler/tests/testutils.py b/compiler/tests/testutils.py index caef7211..7949e113 100644 --- a/compiler/tests/testutils.py +++ b/compiler/tests/testutils.py @@ -1,5 +1,5 @@ import unittest,warnings -import sys,os,glob +import sys,os,glob,copy sys.path.append(os.path.join(sys.path[0],"..")) from globals import OPTS import debug @@ -8,17 +8,23 @@ class openram_test(unittest.TestCase): """ Base unit test that we have some shared classes in. """ def local_drc_check(self, w): + + self.reset() + tempgds = OPTS.openram_temp + "temp.gds" w.gds_write(tempgds) import verify - self.assertFalse(verify.run_drc(w.name, tempgds)) - files = glob.glob(OPTS.openram_temp + '*') - for f in files: - os.remove(f) + result=verify.run_drc(w.name, tempgds) + if result != 0: + self.fail("DRC failed: {}".format(a.name)) + + self.cleanup() def local_check(self, a, final_verification=False): + self.reset() + tempspice = OPTS.openram_temp + "temp.sp" tempgds = OPTS.openram_temp + "temp.gds" @@ -27,19 +33,12 @@ class openram_test(unittest.TestCase): import verify result=verify.run_drc(a.name, tempgds) - self.reset() - try: - self.assertTrue(result==0) - except: + if result != 0: self.fail("DRC failed: {}".format(a.name)) result=verify.run_lvs(a.name, tempgds, tempspice, final_verification) - self.reset() - try: - self.assertTrue(result==0) - except: - self.reset() + if result != 0: self.fail("LVS mismatch: {}".format(a.name)) if OPTS.purge_temp: @@ -54,9 +53,14 @@ class openram_test(unittest.TestCase): os.remove(f) def reset(self): - """ Reset the static duplicate name checker for unit tests """ - import design - design.design.name_map=[] + """ + Reset everything after each test. + """ + # Reset the static duplicate name checker for unit tests. + import hierarchy_design + hierarchy_design.hierarchy_design.name_map=[] + + def isclose(self, value1,value2,error_tolerance=1e-2): """ This is used to compare relative values. """ diff --git a/compiler/verify/__init__.py b/compiler/verify/__init__.py index a83629b0..2199e765 100644 --- a/compiler/verify/__init__.py +++ b/compiler/verify/__init__.py @@ -13,7 +13,7 @@ import debug from globals import OPTS,find_exe,get_tool import sys -debug.info(2,"Initializing verify...") +debug.info(1,"Initializing verify...") if not OPTS.check_lvsdrc: debug.info(1,"LVS/DRC/PEX disabled.") @@ -21,6 +21,7 @@ if not OPTS.check_lvsdrc: OPTS.lvs_exe = None OPTS.pex_exe = None else: + debug.info(1, "Finding DRC/LVS/PEX tools.") OPTS.drc_exe = get_tool("DRC",["calibre","assura","magic"]) OPTS.lvs_exe = get_tool("LVS",["calibre","assura","netgen"]) OPTS.pex_exe = get_tool("PEX",["calibre","magic"]) @@ -31,22 +32,22 @@ if OPTS.check_lvsdrc and OPTS.tech_name == "freepdk45": if OPTS.drc_exe == None: pass elif "calibre"==OPTS.drc_exe[0]: - from .calibre import run_drc + from .calibre import run_drc,print_drc_stats elif "assura"==OPTS.drc_exe[0]: - from .assura import run_drc + from .assura import run_drc,print_drc_stats elif "magic"==OPTS.drc_exe[0]: - from .magic import run_drc + from .magic import run_drc,print_drc_stats else: debug.warning("Did not find a supported DRC tool.") if OPTS.lvs_exe == None: pass elif "calibre"==OPTS.lvs_exe[0]: - from .calibre import run_lvs + from .calibre import run_lvs,print_lvs_stats elif "assura"==OPTS.lvs_exe[0]: - from .assura import run_lvs + from .assura import run_lvs,print_lvs_stats elif "netgen"==OPTS.lvs_exe[0]: - from .magic import run_lvs + from .magic import run_lvs,print_lvs_stats else: debug.warning("Did not find a supported LVS tool.") @@ -54,9 +55,9 @@ else: if OPTS.pex_exe == None: pass elif "calibre"==OPTS.pex_exe[0]: - from .calibre import run_pex + from .calibre import run_pex,print_pex_stats elif "magic"==OPTS.pex_exe[0]: - from .magic import run_pex + from .magic import run_pex,print_pex_stats else: debug.warning("Did not find a supported PEX tool.") diff --git a/compiler/verify/assura.py b/compiler/verify/assura.py index 27949721..d3c605f3 100644 --- a/compiler/verify/assura.py +++ b/compiler/verify/assura.py @@ -25,10 +25,18 @@ import time import debug from globals import OPTS +# Keep track of statistics +num_drc_runs = 0 +num_lvs_runs = 0 +num_pex_runs = 0 + def run_drc(name, gds_name): """Run DRC check on a given top-level name which is implemented in gds_name.""" + global num_drc_runs + num_drc_runs += 1 + from tech import drc drc_rules = drc["drc_rules"] drc_runset = OPTS.openram_temp + name + ".rsf" @@ -88,6 +96,10 @@ def run_drc(name, gds_name): def run_lvs(name, gds_name, sp_name): """Run LVS check on a given top-level name which is implemented in gds_name and sp_name. """ + + global num_lvs_runs + num_lvs_runs += 1 + from tech import drc lvs_rules = drc["lvs_rules"] lvs_runset = OPTS.openram_temp + name + ".rsf" @@ -170,3 +182,13 @@ def run_pex(name, gds_name, sp_name, output=None): """Run pex on a given top-level name which is implemented in gds_name and sp_name. """ debug.error("PEX extraction not implemented with Assura.",-1) + + global num_pex_runs + num_pex_runs += 1 + +def print_drc_stats(): + debug.info(1,"DRC runs: {0}".format(num_drc_runs)) +def print_lvs_stats(): + debug.info(1,"LVS runs: {0}".format(num_lvs_runs)) +def print_pex_stats(): + debug.info(1,"PEX runs: {0}".format(num_pex_runs)) diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 38e92a2c..a7cd9290 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -65,10 +65,17 @@ import debug from globals import OPTS import subprocess +# Keep track of statistics +num_drc_runs = 0 +num_lvs_runs = 0 +num_pex_runs = 0 def run_drc(cell_name, gds_name): """Run DRC check on a given top-level name which is implemented in gds_name.""" + + global num_drc_runs + num_drc_runs += 1 # the runset file contains all the options to run calibre from tech import drc @@ -141,7 +148,10 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): """Run LVS check on a given top-level name which is implemented in gds_name and sp_name. Final verification will ensure that there are no remaining virtual conections. """ - + + global num_lvs_runs + num_lvs_runs += 1 + from tech import drc lvs_rules = drc["lvs_rules"] lvs_runset = { @@ -258,6 +268,10 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): def run_pex(cell_name, gds_name, sp_name, output=None): """Run pex on a given top-level name which is implemented in gds_name and sp_name. """ + + global num_pex_runs + num_pex_runs += 1 + from tech import drc if output == None: output = name + ".pex.netlist" @@ -354,3 +368,10 @@ def correct_port(name, output_file_name, ref_file_name): output_file.write(circuit_title) output_file.write(part2) output_file.close() + +def print_drc_stats(): + debug.info(1,"DRC runs: {0}".format(num_drc_runs)) +def print_lvs_stats(): + debug.info(1,"LVS runs: {0}".format(num_lvs_runs)) +def print_pex_stats(): + debug.info(1,"PEX runs: {0}".format(num_pex_runs)) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index f438bad8..319d159a 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -64,6 +64,11 @@ import debug from globals import OPTS import subprocess +# Keep track of statistics +num_drc_runs = 0 +num_lvs_runs = 0 +num_pex_runs = 0 + def write_magic_script(cell_name, gds_name, extract=False): """ Write a magic script to perform DRC and optionally extraction. """ @@ -148,6 +153,9 @@ def write_netgen_script(cell_name, sp_name): def run_drc(cell_name, gds_name, extract=False): """Run DRC check on a cell which is implemented in gds_name.""" + global num_drc_runs + num_drc_runs += 1 + write_magic_script(cell_name, gds_name, extract) # run drc @@ -198,6 +206,9 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): implemented in gds_name and sp_name. Final verification will ensure that there are no remaining virtual conections. """ + global num_lvs_runs + num_lvs_runs += 1 + run_drc(cell_name, gds_name, extract=True) write_netgen_script(cell_name, sp_name) @@ -270,6 +281,9 @@ def run_pex(name, gds_name, sp_name, output=None): """Run pex on a given top-level name which is implemented in gds_name and sp_name. """ + global num_pex_runs + num_pex_runs += 1 + debug.warning("PEX using magic not implemented.") return 1 @@ -337,3 +351,9 @@ def run_pex(name, gds_name, sp_name, output=None): return out_errors +def print_drc_stats(): + debug.info(1,"DRC runs: {0}".format(num_drc_runs)) +def print_lvs_stats(): + debug.info(1,"LVS runs: {0}".format(num_lvs_runs)) +def print_pex_stats(): + debug.info(1,"PEX runs: {0}".format(num_pex_runs))