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
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)
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)
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)
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
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)
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)
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)
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)
# 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
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)
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)
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)