Exemple #1
0
    def __init__(self, sram_config, name):

        sram_config.set_local_config(self)

        # reset the static duplicate name checker for unit tests
        # in case we create more than one SRAM
        from design import design
        design.name_map = []

        debug.info(
            2,
            "create sram of size {0} with {1} num of words {2} banks".format(
                self.word_size, self.num_words, self.num_banks))
        start_time = datetime.datetime.now()

        self.name = name

        if self.num_banks == 1:
            from sram_1bank import sram_1bank as sram
        elif self.num_banks == 2:
            from sram_2bank import sram_2bank as sram
        else:
            debug.error("Invalid number of banks.", -1)

        self.s = sram(name, sram_config)
        self.s.create_netlist()
        if not OPTS.netlist_only:
            self.s.create_layout()

        if not OPTS.is_unit_test:
            print_time("SRAM creation", datetime.datetime.now(), start_time)
    def escape_route(self, pin_names):
        """
        Takes a list of tuples (name, side) and routes them. After routing,
        it removes the old pin and places a new one on the perimeter.
        """
        self.create_routing_grid(signal_grid)

        start_time = datetime.now()
        self.find_pins_and_blockages(pin_names)
        print_time("Finding pins and blockages", datetime.now(), start_time, 3)

        # Order the routes by closest to the perimeter first
        # This prevents some pins near the perimeter from being blocked by other pins
        ordered_pin_names = sorted(pin_names,
                                   key=lambda x: self.perimeter_dist(x))

        # Route the supply pins to the supply rails
        # Route vdd first since we want it to be shorter
        start_time = datetime.now()
        for pin_name in ordered_pin_names:
            self.route_signal(pin_name)
            #if pin_name == "dout1[1]":
            #    self.write_debug_gds("postroute.gds", False)

        print_time("Maze routing pins", datetime.now(), start_time, 3)

        # self.write_debug_gds("final_escape_router.gds",False)

        return True
    def route(self, vdd_name="vdd", gnd_name="gnd"):
        """
        Add power supply rails and connect all pins to these rails.
        """
        debug.info(1, "Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
        self.vdd_name = vdd_name
        self.gnd_name = gnd_name

        # Clear the pins if we have previously routed
        if (hasattr(self, 'rg')):
            self.clear_pins()
        else:
            # Creat a routing grid over the entire area
            # FIXME: This could be created only over the routing region,
            # but this is simplest for now.
            self.create_routing_grid(supply_grid)

        # Get the pin shapes
        start_time = datetime.now()
        self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
        print_time("Finding pins and blockages", datetime.now(), start_time, 3)
        # Add the supply rails in a mesh network and connect H/V with vias
        start_time = datetime.now()
        # Block everything
        self.prepare_blockages()
        self.clear_blockages(self.gnd_name)
        
        
        # Determine the rail locations
        self.route_supply_rails(self.gnd_name, 0)

        # Block everything
        self.prepare_blockages()
        self.clear_blockages(self.vdd_name)        
        # Determine the rail locations
        self.route_supply_rails(self.vdd_name, 1)
        print_time("Routing supply rails", datetime.now(), start_time, 3)

        start_time = datetime.now()
        self.route_simple_overlaps(vdd_name)
        self.route_simple_overlaps(gnd_name)
        print_time("Simple overlap routing", datetime.now(), start_time, 3)

        # Route the supply pins to the supply rails
        # Route vdd first since we want it to be shorter
        start_time = datetime.now()
        self.route_pins_to_rails(vdd_name)
        self.route_pins_to_rails(gnd_name)
        print_time("Maze routing supplies", datetime.now(), start_time, 3)
        # self.write_debug_gds("final.gds", False)

        # Did we route everything??
        if not self.check_all_routed(vdd_name):
            return False
        if not self.check_all_routed(gnd_name):
            return False

        return True
Exemple #4
0
    def create_netlist(self):
        """ Netlist creation """

        start_time = datetime.datetime.now()

        # Must create the control logic before pins to get the pins
        self.add_modules()
        self.add_pins()
        self.create_modules()

        # This is for the lib file if we don't create layout
        self.width = 0
        self.height = 0

        if not OPTS.is_unit_test:
            print_time("Submodules", datetime.datetime.now(), start_time)
    def __init__(self, layers, design, gds_filename=None, bbox=None):
        """
        This will route on layers in design. It will get the blockages from
        either the gds file name or the design itself (by saving to a gds file).
        """
        start_time = datetime.now()

        # Power rail width in minimum wire widths
        self.route_track_width = 2

        router.__init__(self, layers, design, gds_filename, bbox, self.route_track_width)

        # The list of supply rails (grid sets) that may be routed
        self.supply_rails = {}
        # This is the same as above but as a sigle set for the all the rails
        self.supply_rail_tracks = {}

        print_time("Init supply router", datetime.now(), start_time, 3)
Exemple #6
0
    def create_layout(self):
        """ Layout creation """    
        start_time = datetime.now()
        self.place_instances()
        if not OPTS.is_unit_test:
            print_time("Placement",datetime.now(), start_time)

        start_time = datetime.now()
        self.route_layout()
        self.route_supplies()
        if not OPTS.is_unit_test:
            print_time("Routing",datetime.now(), start_time)

        self.add_lvs_correspondence_points()
        
        self.offset_all_coordinates()

        highest_coord = self.find_highest_coords()
        self.width = highest_coord[0]
        self.height = highest_coord[1]

        start_time = datetime.now()
        self.DRC_LVS(final_verification=True)
        if not OPTS.is_unit_test:
            print_time("Verification",datetime.now(), start_time)
Exemple #7
0
    def create_layout(self):
        """ Layout creation """
        start_time = datetime.datetime.now()
        self.place_instances()
        if not OPTS.is_unit_test:
            print_time("Placement", datetime.datetime.now(), start_time)

        start_time = datetime.datetime.now()
        self.route_layout()

        if not OPTS.is_unit_test:
            print_time("Routing", datetime.datetime.now(), start_time)

        self.add_lvs_correspondence_points()

        #self.offset_all_coordinates()

        highest_coord = self.find_highest_coords()
        self.width = highest_coord[0]
        self.height = highest_coord[1]
        if OPTS.use_pex:
            self.add_global_pex_labels()
        self.add_boundary(ll=vector(0, 0),
                          ur=vector(self.width, self.height))

        start_time = datetime.datetime.now()
        if not OPTS.is_unit_test:
            # We only enable final verification if we have routed the design
            # Only run this if not a unit test, because unit test will also verify it.
            self.DRC_LVS(final_verification=OPTS.route_supplies, force_check=OPTS.check_lvsdrc)
            print_time("Verification", datetime.datetime.now(), start_time)
Exemple #8
0
    def create_layout(self):
        """ Layout creation """
        start_time = datetime.datetime.now()
        self.place_instances()
        if not OPTS.is_unit_test:
            print_time("Placement", datetime.datetime.now(), start_time)

        start_time = datetime.datetime.now()
        self.route_layout()
        self.route_supplies()
        if not OPTS.is_unit_test:
            print_time("Routing", datetime.datetime.now(), start_time)

        self.add_lvs_correspondence_points()

        self.offset_all_coordinates()

        highest_coord = self.find_highest_coords()
        self.width = highest_coord[0]
        self.height = highest_coord[1]
        self.add_boundary(ll=vector(0, 0), ur=vector(self.width, self.height))

        start_time = datetime.datetime.now()
        # We only enable final verification if we have routed the design
        self.DRC_LVS(final_verification=OPTS.route_supplies, force_check=True)
        if not OPTS.is_unit_test:
            print_time("Verification", datetime.datetime.now(), start_time)
    def route(self, vdd_name="vdd", gnd_name="gnd"):
        """
        Route the two nets in a single layer)
        """
        debug.info(1,"Running supply router on {0} and {1}...".format(vdd_name, gnd_name))
        self.vdd_name = vdd_name
        self.gnd_name = gnd_name

        # Clear the pins if we have previously routed
        if (hasattr(self,'rg')):
            self.clear_pins()
        else:
            # Creat a routing grid over the entire area
            # FIXME: This could be created only over the routing region,
            # but this is simplest for now.
            self.create_routing_grid(signal_grid)

        # Get the pin shapes
        start_time = datetime.now()
        self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
        print_time("Finding pins and blockages",datetime.now(), start_time, 3)

        # Route the supply pins to the supply rails
        # Route vdd first since we want it to be shorter
        start_time = datetime.now()
        self.route_pins(vdd_name)
        self.route_pins(gnd_name)
        print_time("Maze routing supplies",datetime.now(), start_time, 3)

        # self.write_debug_gds("final_tree_router.gds",False)

        # Did we route everything??
        if not self.check_all_routed(vdd_name):
            return False
        if not self.check_all_routed(gnd_name):
            return False

        return True
Exemple #10
0
    def __init__(self, sram_config, name):

        sram_config.set_local_config(self)

        # FIXME: adjust this to not directly change OPTS.
        # Word-around to have values relevant to OPTS be displayed if not directly set.
        OPTS.words_per_row = self.words_per_row
        debug.info(1, "Changed OPTS wpr={}".format(self.words_per_row))
        debug.info(1, "OPTS wpr={}".format(OPTS.words_per_row))

        # reset the static duplicate name checker for unit tests
        # in case we create more than one SRAM
        from design import design
        design.name_map = []

        debug.info(
            2,
            "create sram of size {0} with {1} num of words {2} banks".format(
                self.word_size, self.num_words, self.num_banks))
        start_time = datetime.datetime.now()

        self.name = name

        if self.num_banks == 1:
            from sram_1bank import sram_1bank as sram
        elif self.num_banks == 2:
            from sram_2bank import sram_2bank as sram
        else:
            debug.error("Invalid number of banks.", -1)

        self.s = sram(name, sram_config)
        self.s.create_netlist()
        if not OPTS.netlist_only:
            self.s.create_layout()

        if not OPTS.is_unit_test:
            print_time("SRAM creation", datetime.datetime.now(), start_time)
Exemple #11
0
    def save_output(self):
        """ Save spice, gds and lef files while reporting time to do it as well. """

        # Write spice
        start_time = datetime.datetime.now()
        spname = OPTS.output_path + "AMC_BIST.sp"
        print("\n BIST SP: Writing to {0}".format(spname))
        self.sp_write(spname)
        print_time("BIST Spice writing", datetime.datetime.now(), start_time)

        # Write layout
        start_time = datetime.datetime.now()
        gdsname = OPTS.output_path + "AMC_BIST.gds"
        print("\n BIST GDS: Writing to {0}".format(gdsname))
        self.gds_write(gdsname)
        print_time("BIST GDS writing", datetime.datetime.now(), start_time)

        # Write lef
        start_time = datetime.datetime.now()
        lefname = OPTS.output_path + "AMC_BIST.lef"
        print("\n BIST LEF: Writing to {0}".format(lefname))
        self.lef_write(lefname)
        print_time("LEF", datetime.datetime.now(), start_time)
Exemple #12
0
    def find_pins_and_blockages(self, pin_list):
        """
        Find the pins and blockages in the design
        """
        # This finds the pin shapes and sorts them into "groups" that
        # are connected. This must come before the blockages, so we
        # can not count the pins themselves
        # as blockages.
        start_time = datetime.now()
        for pin_name in pin_list:
            self.retrieve_pins(pin_name)
        print_time("Retrieving pins", datetime.now(), start_time, 4)
        
        start_time = datetime.now()
        for pin_name in pin_list:
            self.analyze_pins(pin_name)
        print_time("Analyzing pins", datetime.now(), start_time, 4)

        # This will get all shapes as blockages and convert to grid units
        # This ignores shapes that were pins
        start_time = datetime.now()
        self.find_blockages()
        print_time("Finding blockages", datetime.now(), start_time, 4)

        # Convert the blockages to grid units
        start_time = datetime.now()
        self.convert_blockages()
        print_time("Converting blockages", datetime.now(), start_time, 4)
        
        # This will convert the pins to grid units
        # It must be done after blockages to ensure no DRCs
        # between expanded pins and blocked grids
        start_time = datetime.now()
        for pin in pin_list:
            self.convert_pins(pin)
        print_time("Converting pins", datetime.now(), start_time, 4)

        # Combine adjacent pins into pin groups to reduce run-time
        # by reducing the number of maze routes.
        # This algorithm is > O(n^2) so remove it for now
        # start_time = datetime.now()
        # for pin in pin_list:
        #     self.combine_adjacent_pins(pin)
        # print_time("Combining adjacent pins",datetime.now(), start_time, 4)


        # Separate any adjacent grids of differing net names
        # that overlap
        # Must be done before enclosing pins
        start_time = datetime.now()
        self.separate_adjacent_pins(0)
        print_time("Separating adjacent pins", datetime.now(), start_time, 4)
        
        # Enclose the continguous grid units in a metal
        # rectangle to fix some DRCs
        start_time = datetime.now()
        self.enclose_pins()
        print_time("Enclosing pins", datetime.now(), start_time, 4)
Exemple #13
0
    def save(self):
        """ Save all the output files while reporting time to do it as well. """

        # Save the spice file
        start_time = datetime.datetime.now()
        spname = OPTS.output_path + self.s.name + ".sp"
        debug.print_raw("SP: Writing to {0}".format(spname))
        self.sp_write(spname)
        functional(self.s,
                   os.path.basename(spname),
                   cycles=200,
                   output_path=OPTS.output_path)
        print_time("Spice writing", datetime.datetime.now(), start_time)

        if not OPTS.netlist_only:
            # Write the layout
            start_time = datetime.datetime.now()
            gdsname = OPTS.output_path + self.s.name + ".gds"
            debug.print_raw("GDS: Writing to {0}".format(gdsname))
            self.gds_write(gdsname)
            if OPTS.check_lvsdrc:
                verify.write_drc_script(cell_name=self.s.name,
                                        gds_name=os.path.basename(gdsname),
                                        extract=True,
                                        final_verification=True,
                                        output_path=OPTS.output_path)
            print_time("GDS", datetime.datetime.now(), start_time)

            # Create a LEF physical model
            start_time = datetime.datetime.now()
            lefname = OPTS.output_path + self.s.name + ".lef"
            debug.print_raw("LEF: Writing to {0}".format(lefname))
            self.lef_write(lefname)
            print_time("LEF", datetime.datetime.now(), start_time)

        # Save the LVS file
        start_time = datetime.datetime.now()
        lvsname = OPTS.output_path + self.s.name + ".lvs.sp"
        debug.print_raw("LVS: Writing to {0}".format(lvsname))
        self.lvs_write(lvsname)
        if not OPTS.netlist_only and OPTS.check_lvsdrc:
            verify.write_lvs_script(cell_name=self.s.name,
                                    gds_name=os.path.basename(gdsname),
                                    sp_name=os.path.basename(lvsname),
                                    final_verification=True,
                                    output_path=OPTS.output_path)
        print_time("LVS writing", datetime.datetime.now(), start_time)

        # Save the extracted spice file
        if OPTS.use_pex:
            start_time = datetime.datetime.now()
            # Output the extracted design if requested
            pexname = OPTS.output_path + self.s.name + ".pex.sp"
            spname = OPTS.output_path + self.s.name + ".sp"
            verify.run_pex(self.s.name, gdsname, spname, output=pexname)
            sp_file = pexname
            print_time("Extraction", datetime.datetime.now(), start_time)
        else:
            # Use generated spice file for characterization
            sp_file = spname

        # Save a functional simulation file

        # Characterize the design
        start_time = datetime.datetime.now()
        from characterizer import lib
        debug.print_raw("LIB: Characterizing... ")
        lib(out_dir=OPTS.output_path, sram=self.s, sp_file=sp_file)
        print_time("Characterization", datetime.datetime.now(), start_time)

        # Write the config file
        start_time = datetime.datetime.now()
        from shutil import copyfile
        copyfile(OPTS.config_file, OPTS.output_path + OPTS.output_name + '.py')
        debug.print_raw(
            "Config: Writing to {0}".format(OPTS.output_path +
                                            OPTS.output_name + '.py'))
        print_time("Config", datetime.datetime.now(), start_time)

        # Write the datasheet
        start_time = datetime.datetime.now()
        from datasheet_gen import datasheet_gen
        dname = OPTS.output_path + self.s.name + ".html"
        debug.print_raw("Datasheet: Writing to {0}".format(dname))
        datasheet_gen.datasheet_write(dname)
        print_time("Datasheet", datetime.datetime.now(), start_time)

        # Write a verilog model
        start_time = datetime.datetime.now()
        vname = OPTS.output_path + self.s.name + ".v"
        debug.print_raw("Verilog: Writing to {0}".format(vname))
        self.verilog_write(vname)
        print_time("Verilog", datetime.datetime.now(), start_time)

        # Write out options if specified
        if OPTS.output_extended_config:
            start_time = datetime.datetime.now()
            oname = OPTS.output_path + OPTS.output_name + "_extended.py"
            debug.print_raw("Extended Config: Writing to {0}".format(oname))
            self.extended_config_write(oname)
            print_time("Extended Config", datetime.datetime.now(), start_time)
Exemple #14
0
# These depend on arguments, so don't load them until now.
import debug

# Parse config file and set up all the options
g.init_openram(config_file=args[0], is_unit_test=False)

# Ensure that the right bitcell exists or use the parameterised one
g.setup_bitcell()

# Only print banner here so it's not in unit tests
g.print_banner()

# Keep track of running stats
start_time = datetime.datetime.now()
g.print_time("Start", start_time)

# Output info about this run
g.report_status()

from sram_config import sram_config


# Configure the SRAM organization
c = sram_config(word_size=OPTS.word_size,
                num_words=OPTS.num_words,
                write_size=OPTS.write_size)
debug.print_raw("Words per row: {}".format(c.words_per_row))

output_extensions = ["sp", "v", "lib", "py", "html", "log"]
# Only output lef/gds if back-end
Exemple #15
0
    def save(self):
        """ Save all the output files while reporting time to do it as well. """

        if not OPTS.netlist_only:
            # Create a LEF physical model
            start_time = datetime.datetime.now()
            lefname = OPTS.output_path + self.s.name + ".lef"
            debug.print_raw("LEF: Writing to {0}".format(lefname))
            self.lef_write(lefname)
            print_time("LEF", datetime.datetime.now(), start_time)

            # Write the layout
            start_time = datetime.datetime.now()
            gdsname = OPTS.output_path + self.s.name + ".gds"
            debug.print_raw("GDS: Writing to {0}".format(gdsname))
            self.gds_write(gdsname)
            print_time("GDS", datetime.datetime.now(), start_time)

        # Save the spice file
        start_time = datetime.datetime.now()
        spname = OPTS.output_path + self.s.name + ".sp"
        debug.print_raw("SP: Writing to {0}".format(spname))
        self.sp_write(spname)
        print_time("Spice writing", datetime.datetime.now(), start_time)

        # Save the LVS file
        start_time = datetime.datetime.now()
        spname = OPTS.output_path + self.s.name + ".lvs"
        debug.print_raw("LVS: Writing to {0}".format(spname))
        self.lvs_write(spname)
        print_time("LVS writing", datetime.datetime.now(), start_time)

        # Save the extracted spice file
        if OPTS.use_pex:
            import verify
            start_time = datetime.datetime.now()
            # Output the extracted design if requested
            sp_file = OPTS.output_path + "temp_pex.sp"
            verify.run_pex(self.s.name, gdsname, spname, output=sp_file)
            print_time("Extraction", datetime.datetime.now(), start_time)
        else:
            # Use generated spice file for characterization
            sp_file = spname

        # Characterize the design
        start_time = datetime.datetime.now()
        from characterizer import lib
        debug.print_raw("LIB: Characterizing... ")
        lib(out_dir=OPTS.output_path, sram=self.s, sp_file=sp_file)
        print_time("Characterization", datetime.datetime.now(), start_time)

        # Write the config file
        start_time = datetime.datetime.now()
        from shutil import copyfile
        copyfile(OPTS.config_file, OPTS.output_path + OPTS.output_name + '.py')
        debug.print_raw(
            "Config: Writing to {0}".format(OPTS.output_path +
                                            OPTS.output_name + '.py'))
        print_time("Config", datetime.datetime.now(), start_time)

        # Write the datasheet
        start_time = datetime.datetime.now()
        from datasheet_gen import datasheet_gen
        dname = OPTS.output_path + self.s.name + ".html"
        debug.print_raw("Datasheet: Writing to {0}".format(dname))
        datasheet_gen.datasheet_write(dname)
        print_time("Datasheet", datetime.datetime.now(), start_time)

        # Write a verilog model
        start_time = datetime.datetime.now()
        vname = OPTS.output_path + self.s.name + ".v"
        debug.print_raw("Verilog: Writing to {0}".format(vname))
        self.verilog_write(vname)
        print_time("Verilog", datetime.datetime.now(), start_time)
Exemple #16
0
    def save_output(self):
        """ Save all the output files while reporting time to do it as well. """

        # Save the spice file
        start_time = datetime.datetime.now()
        spname = OPTS.output_path + self.name + ".sp"
        print("SP: Writing to {0}".format(spname))
        self.sp_write(spname)
        print_time("Spice writing", datetime.datetime.now(), start_time)

        # Save the extracted spice file
        if OPTS.use_pex:
            start_time = datetime.datetime.now()
            # Output the extracted design if requested
            sp_file = OPTS.output_path + "temp_pex.sp"
            verify.run_pex(self.name, gdsname, spname, output=sp_file)
            print_time("Extraction", datetime.datetime.now(), start_time)
        else:
            # Use generated spice file for characterization
            sp_file = spname

        # Characterize the design
        start_time = datetime.datetime.now()
        from characterizer import lib
        print("LIB: Characterizing... ")
        if OPTS.analytical_delay:
            print("Using analytical delay models (no characterization)")
        else:
            if OPTS.spice_name != "":
                print("Performing simulation-based characterization with {}".
                      format(OPTS.spice_name))
            if OPTS.trim_netlist:
                print("Trimming netlist to speed up characterization.")
        lib.lib(out_dir=OPTS.output_path, sram=self, sp_file=sp_file)
        print_time("Characterization", datetime.datetime.now(), start_time)

        # Write the layout
        start_time = datetime.datetime.now()
        gdsname = OPTS.output_path + self.name + ".gds"
        print("GDS: Writing to {0}".format(gdsname))
        self.gds_write(gdsname)
        print_time("GDS", datetime.datetime.now(), start_time)

        # Create a LEF physical model
        start_time = datetime.datetime.now()
        lefname = OPTS.output_path + self.name + ".lef"
        print("LEF: Writing to {0}".format(lefname))
        self.lef_write(lefname)
        print_time("LEF", datetime.datetime.now(), start_time)

        # Write a verilog model
        start_time = datetime.datetime.now()
        vname = OPTS.output_path + self.name + ".v"
        print("Verilog: Writing to {0}".format(vname))
        self.verilog_write(vname)
        print_time("Verilog", datetime.datetime.now(), start_time)
Exemple #17
0
    def __init__(self, word_size, num_words, num_banks, name):

        c = reload(__import__(OPTS.control_logic))
        self.mod_control_logic = getattr(c, OPTS.control_logic)

        c = reload(__import__(OPTS.ms_flop_array))
        self.mod_ms_flop_array = getattr(c, OPTS.ms_flop_array)

        c = reload(__import__(OPTS.bitcell))
        self.mod_bitcell = getattr(c, OPTS.bitcell)
        self.bitcell = self.mod_bitcell()

        c = reload(__import__(OPTS.ms_flop))
        self.mod_ms_flop = getattr(c, OPTS.ms_flop)
        self.ms_flop = self.mod_ms_flop()

        # reset the static duplicate name checker for unit tests
        # in case we create more than one SRAM
        import design
        design.design.name_map = []

        self.word_size = word_size
        self.num_words = num_words
        self.num_banks = num_banks

        debug.info(
            2, "create sram of size {0} with {1} num of words".format(
                self.word_size, self.num_words))
        start_time = datetime.datetime.now()

        design.design.__init__(self, name)

        # For different layer width vias
        self.m2m3_offset_fix = vector(0, 0.5 * (self.m3_width - self.m2_width))

        # 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.control_size = 6
        self.bank_to_bus_distance = 5 * self.m3_width

        self.compute_sizes()
        self.add_pins()
        self.create_layout()

        # Can remove the following, but it helps for debug!
        self.add_lvs_correspondence_points()

        self.offset_all_coordinates()
        sizes = self.find_highest_coords()
        self.width = sizes[0]
        self.height = sizes[1]

        self.DRC_LVS(final_verification=True)

        if not OPTS.is_unit_test:
            print_time("SRAM creation", datetime.datetime.now(), start_time)