diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index dfd845e9..dfb05db3 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -306,7 +306,8 @@ class delay(simulation): self.create_test_cycles() # creates and opens stimulus file for writing - temp_stim = "{0}/stim.sp".format(OPTS.openram_temp) + self.delay_stim_sp = "delay_stim.sp" + temp_stim = "{0}/{1}".format(OPTS.openram_temp, self.delay_stim_sp) self.sf = open(temp_stim, "w") self.sf.write("* Delay stimulus for period of {0}n load={1}fF slew={2}ns\n\n".format(self.period, self.load, @@ -350,7 +351,8 @@ class delay(simulation): self.check_arguments() # creates and opens stimulus file for writing - temp_stim = "{0}/stim.sp".format(OPTS.openram_temp) + self.power_stim_sp = "power_stim.sp" + temp_stim = "{0}/{1}".format(OPTS.openram_temp, self.power_stim_sp) self.sf = open(temp_stim, "w") self.sf.write("* Power stimulus for period of {0}n\n\n".format(self.period)) self.stim = stimuli(self.sf, self.corner) @@ -616,7 +618,7 @@ class delay(simulation): self.write_delay_stimulus() - self.stim.run_sim() + self.stim.run_sim(self.delay_stim_sp) return self.check_measurements() @@ -772,7 +774,7 @@ class delay(simulation): debug.info(1, "Performing leakage power simulations.") self.write_power_stimulus(trim=False) - self.stim.run_sim() + self.stim.run_sim(self.power_stim_sp) leakage_power=parse_spice_list("timing", "leakage_power") debug.check(leakage_power!="Failed", "Could not measure leakage power.") debug.info(1, "Leakage power of full array is {0} mW".format(leakage_power * 1e3)) @@ -780,7 +782,7 @@ class delay(simulation): # sys.exit(1) self.write_power_stimulus(trim=True) - self.stim.run_sim() + self.stim.run_sim(self.power_stim_sp) trim_leakage_power=parse_spice_list("timing", "leakage_power") debug.check(trim_leakage_power!="Failed", "Could not measure leakage power.") debug.info(1, "Leakage power of trimmed array is {0} mW".format(trim_leakage_power * 1e3)) diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index 4ec218fc..8a511c42 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -21,13 +21,24 @@ class functional(simulation): for successful SRAM operation. """ - def __init__(self, sram, spfile, corner, cycles=15): + def __init__(self, sram, spfile, corner=None, cycles=15, period=None, output_path=None): super().__init__(sram, spfile, corner) # Seed the characterizer with a constant seed for unit tests if OPTS.is_unit_test: random.seed(12345) + if not corner: + corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) + + if period: + self.period = period + + if not output_path: + self.output_path = OPTS.openram_temp + else: + self.output_path = output_path + if self.write_size: self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) else: @@ -58,15 +69,14 @@ class functional(simulation): self.read_check = [] self.read_results = [] - def run(self, feasible_period=None): - if feasible_period: # period defaults to tech.py feasible period otherwise. - self.period = feasible_period # Generate a random sequence of reads and writes self.create_random_memory_sequence() - # Run SPICE simulation + # Write SPICE simulation self.write_functional_stimulus() - self.stim.run_sim() + + def run(self): + self.stim.run_sim(self.stim_sp) # read dout values from SPICE simulation. If the values do not fall within the noise margins, return the error. (success, error) = self.read_stim_results() @@ -330,7 +340,8 @@ class functional(simulation): def write_functional_stimulus(self): """ Writes SPICE stimulus. """ - temp_stim = "{0}/stim.sp".format(OPTS.openram_temp) + self.stim_sp = "functional_stim.sp" + temp_stim = "{0}/{1}".format(self.output_path, self.stim_sp) self.sf = open(temp_stim, "w") self.sf.write("* Functional test stimulus file for {}ns period\n\n".format(self.period)) self.stim = stimuli(self.sf, self.corner) diff --git a/compiler/characterizer/setup_hold.py b/compiler/characterizer/setup_hold.py index 377ead67..f3b9541c 100644 --- a/compiler/characterizer/setup_hold.py +++ b/compiler/characterizer/setup_hold.py @@ -27,23 +27,22 @@ class setup_hold(): self.model_location = OPTS.openram_tech + "sp_lib/dff.sp" self.period = tech.spice["feasible_period"] - debug.info(2,"Feasible period from technology file: {0} ".format(self.period)) + debug.info(2, "Feasible period from technology file: {0} ".format(self.period)) self.set_corner(corner) - - def set_corner(self,corner): + def set_corner(self, corner): """ Set the corner values """ self.corner = corner (self.process, self.vdd_voltage, self.temperature) = corner self.gnd_voltage = 0 - def write_stimulus(self, mode, target_time, correct_value): """Creates a stimulus file for SRAM setup/hold time calculation""" # creates and opens the stimulus file for writing - temp_stim = OPTS.openram_temp + "stim.sp" + self.stim_sp = "sh_stim.sp" + temp_stim = OPTS.openram_temp + self.stim_sp self.sf = open(temp_stim, "w") self.stim = stimuli(self.sf, self.corner) @@ -63,8 +62,7 @@ class setup_hold(): self.write_measures(mode=mode, correct_value=correct_value) - - self.stim.write_control(4*self.period) + self.stim.write_control(4 * self.period) self.sf.close() @@ -79,7 +77,6 @@ class setup_hold(): self.sf.write("\n* Global Power Supplies\n") self.stim.write_supply() - def write_data(self, mode, target_time, correct_value): """Create the data signals for setup/hold analysis. First period is to initialize it to the opposite polarity. Second period is used for @@ -113,14 +110,12 @@ class setup_hold(): # without using .IC on an internal node. # Return input to value after one period. # The second pulse is the characterization one at 2*period - clk_times=[0, 0.1*self.period,self.period,2*self.period], + clk_times=[0, 0.1 * self.period, self.period, 2 * self.period], data_values=[0, 1, 0, 1], - period=2*self.period, + period=2 * self.period, slew=self.constrained_input_slew, setup=0) - - def write_measures(self, mode, correct_value): """ Measure statements for setup/hold with right phases. """ @@ -139,7 +134,6 @@ class setup_hold(): else: din_rise_or_fall = "RISE" - self.sf.write("\n* Measure statements for pass/fail verification\n") trig_name = "clk" targ_name = "dout" @@ -152,8 +146,8 @@ class setup_hold(): targ_val=targ_val, trig_dir="RISE", targ_dir=dout_rise_or_fall, - trig_td=1.9*self.period, - targ_td=1.9*self.period) + trig_td=1.9 * self.period, + targ_td=1.9 * self.period) targ_name = "data" # Start triggers right after initialize value is returned to normal @@ -165,11 +159,8 @@ class setup_hold(): targ_val=targ_val, trig_dir="RISE", targ_dir=din_rise_or_fall, - trig_td=1.2*self.period, - targ_td=1.2*self.period) - - - + trig_td=1.2 * self.period, + targ_td=1.2 * self.period) def bidir_search(self, correct_value, mode): """ This will perform a bidirectional search for either setup or hold times. @@ -182,23 +173,26 @@ class setup_hold(): # this time. They are also unbalanced so that the average won't be right on the clock edge in the # first iteration. if mode == "SETUP": - feasible_bound = 1.25*self.period - infeasible_bound = 2.5*self.period + feasible_bound = 1.25 * self.period + infeasible_bound = 2.5 * self.period else: - infeasible_bound = 1.5*self.period - feasible_bound = 2.75*self.period + infeasible_bound = 1.5 * self.period + feasible_bound = 2.75 * self.period # Initial check if reference feasible bound time passes for correct_value, if not, we can't start the search! self.write_stimulus(mode=mode, target_time=feasible_bound, correct_value=correct_value) - self.stim.run_sim() + self.stim.run_sim(self.stim_sp) ideal_clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay")) setuphold_time = convert_to_float(parse_spice_list("timing", "setup_hold_time")) debug.info(2,"*** {0} CHECK: {1} Ideal Clk-to-Q: {2} Setup/Hold: {3}".format(mode, correct_value,ideal_clk_to_q,setuphold_time)) if type(ideal_clk_to_q)!=float or type(setuphold_time)!=float: - debug.error("Initial hold time fails for data value feasible bound {0} Clk-to-Q {1} Setup/Hold {2}".format(feasible_bound,ideal_clk_to_q,setuphold_time),2) + debug.error("Initial hold time fails for data value feasible bound {0} Clk-to-Q {1} Setup/Hold {2}".format(feasible_bound, + ideal_clk_to_q, + setuphold_time), + 2) if mode == "SETUP": # SETUP is clk-din, not din-clk setuphold_time *= -1e9 @@ -206,57 +200,53 @@ class setup_hold(): setuphold_time *= 1e9 passing_setuphold_time = setuphold_time - debug.info(2,"Checked initial {0} time {1}, data at {2}, clock at {3} ".format(mode, - setuphold_time, - feasible_bound, - 2*self.period)) + debug.info(2, "Checked initial {0} time {1}, data at {2}, clock at {3} ".format(mode, + setuphold_time, + feasible_bound, + 2 * self.period)) #raw_input("Press Enter to continue...") while True: - target_time = (feasible_bound + infeasible_bound)/2 + target_time = (feasible_bound + infeasible_bound) / 2 self.write_stimulus(mode=mode, target_time=target_time, correct_value=correct_value) - debug.info(2,"{0} value: {1} Target time: {2} Infeasible: {3} Feasible: {4}".format(mode, - correct_value, - target_time, - infeasible_bound, - feasible_bound)) + debug.info(2, "{0} value: {1} Target time: {2} Infeasible: {3} Feasible: {4}".format(mode, + correct_value, + target_time, + infeasible_bound, + feasible_bound)) - - self.stim.run_sim() + self.stim.run_sim(self.stim_sp) clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay")) setuphold_time = convert_to_float(parse_spice_list("timing", "setup_hold_time")) - if type(clk_to_q)==float and (clk_to_q<1.1*ideal_clk_to_q) and type(setuphold_time)==float: + if type(clk_to_q) == float and (clk_to_q < 1.1 * ideal_clk_to_q) and type(setuphold_time)==float: if mode == "SETUP": # SETUP is clk-din, not din-clk setuphold_time *= -1e9 else: setuphold_time *= 1e9 - debug.info(2,"PASS Clk-to-Q: {0} Setup/Hold: {1}".format(clk_to_q,setuphold_time)) + debug.info(2, "PASS Clk-to-Q: {0} Setup/Hold: {1}".format(clk_to_q, setuphold_time)) passing_setuphold_time = setuphold_time feasible_bound = target_time else: - debug.info(2,"FAIL Clk-to-Q: {0} Setup/Hold: {1}".format(clk_to_q,setuphold_time)) + debug.info(2, "FAIL Clk-to-Q: {0} Setup/Hold: {1}".format(clk_to_q, setuphold_time)) infeasible_bound = target_time - #raw_input("Press Enter to continue...") if relative_compare(feasible_bound, infeasible_bound, error_tolerance=0.001): - debug.info(3,"CONVERGE {0} vs {1}".format(feasible_bound,infeasible_bound)) + debug.info(3, "CONVERGE {0} vs {1}".format(feasible_bound, infeasible_bound)) break - debug.info(2,"Converged on {0} time {1}.".format(mode,passing_setuphold_time)) + debug.info(2, "Converged on {0} time {1}.".format(mode, passing_setuphold_time)) return passing_setuphold_time - def setup_LH_time(self): """Calculates the setup time for low-to-high transition for a DFF """ return self.bidir_search(1, "SETUP") - def setup_HL_time(self): """Calculates the setup time for high-to-low transition for a DFF """ @@ -272,7 +262,6 @@ class setup_hold(): """ return self.bidir_search(0, "HOLD") - def analyze(self, related_slews, constrained_slews): """main function to calculate both setup and hold time for the DFF and returns a dictionary that contains 4 lists for both @@ -301,10 +290,10 @@ class setup_hold(): # } # return times - for self.related_input_slew in related_slews: for self.constrained_input_slew in constrained_slews: - debug.info(1, "Clock slew: {0} Data slew: {1}".format(self.related_input_slew,self.constrained_input_slew)) + debug.info(1, "Clock slew: {0} Data slew: {1}".format(self.related_input_slew, + self.constrained_input_slew)) LH_setup_time = self.setup_LH_time() debug.info(1, " Setup Time for low_to_high transition: {0}".format(LH_setup_time)) HL_setup_time = self.setup_HL_time() @@ -325,7 +314,7 @@ class setup_hold(): } return times - def analytical_setuphold(self,related_slews, constrained_slews): + def analytical_setuphold(self, related_slews, constrained_slews): """ Just return the fixed setup/hold times from the technology. """ LH_setup = [] @@ -336,10 +325,10 @@ class setup_hold(): for self.related_input_slew in related_slews: for self.constrained_input_slew in constrained_slews: # convert from ps to ns - LH_setup.append(tech.spice["dff_setup"]/1e3) - HL_setup.append(tech.spice["dff_setup"]/1e3) - LH_hold.append(tech.spice["dff_hold"]/1e3) - HL_hold.append(tech.spice["dff_hold"]/1e3) + LH_setup.append(tech.spice["dff_setup"] / 1e3) + HL_setup.append(tech.spice["dff_setup"] / 1e3) + LH_hold.append(tech.spice["dff_hold"] / 1e3) + HL_hold.append(tech.spice["dff_hold"] / 1e3) times = {"setup_times_LH": LH_setup, "setup_times_HL": HL_setup, diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index a354e353..b7a84cb6 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -285,10 +285,7 @@ class stimuli(): includes = self.device_models + [circuit] for item in list(includes): - if os.path.isfile(item): - self.sf.write(".include \"{0}\"\n".format(item)) - else: - debug.error("Could not find spice model: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item)) + self.sf.write(".include \"{0}\"\n".format(item)) def write_supply(self): """ Writes supply voltage statements """ @@ -299,9 +296,9 @@ class stimuli(): self.sf.write("\n*Nodes gnd and 0 are the same global ground node in ngspice/hspice/xa. Otherwise, this source may be needed.\n") self.sf.write("*V{0} {0} {1} {2}\n".format(self.gnd_name, gnd_node_name, 0.0)) - def run_sim(self): + def run_sim(self, name): """ Run hspice in batch mode and output rawfile to parse. """ - temp_stim = "{0}stim.sp".format(OPTS.openram_temp) + temp_stim = "{0}{1}".format(OPTS.openram_temp, name) import datetime start_time = datetime.datetime.now() debug.check(OPTS.spice_exe != "", "No spice simulator has been found.") diff --git a/compiler/globals.py b/compiler/globals.py index 23bb5bfb..c6980d9e 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -469,7 +469,7 @@ def set_default_corner(): if OPTS.nominal_corner_only: OPTS.process_corners = ["TT"] else: - OPTS.process_corners = tech.spice["fet_models"].keys() + OPTS.process_corners = list(tech.spice["fet_models"].keys()) if (OPTS.supply_voltages == ""): if OPTS.nominal_corner_only: diff --git a/compiler/sram/sram.py b/compiler/sram/sram.py index 7b30ccc2..f86081b3 100644 --- a/compiler/sram/sram.py +++ b/compiler/sram/sram.py @@ -6,7 +6,10 @@ # All rights reserved. # import datetime +import os import debug +import verify +from characterizer import functional from globals import OPTS, print_time @@ -84,6 +87,11 @@ class sram(): gdsname = OPTS.output_path + self.s.name + ".gds" debug.print_raw("GDS: Writing to {0}".format(gdsname)) self.gds_write(gdsname) + 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 @@ -98,6 +106,9 @@ class sram(): 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), + output_path=OPTS.output_path) print_time("Spice writing", datetime.datetime.now(), start_time) # Save the LVS file @@ -105,11 +116,16 @@ class sram(): 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: + 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: - import verify start_time = datetime.datetime.now() # Output the extracted design if requested pexname = OPTS.output_path + self.s.name + ".pex.sp" @@ -121,6 +137,8 @@ class sram(): # 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 diff --git a/compiler/tests/22_psram_1bank_2mux_func_test.py b/compiler/tests/22_psram_1bank_2mux_func_test.py index 3876e69b..ecb3bdf3 100755 --- a/compiler/tests/22_psram_1bank_2mux_func_test.py +++ b/compiler/tests/22_psram_1bank_2mux_func_test.py @@ -56,8 +56,7 @@ class psram_1bank_2mux_func_test(openram_test): tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) - corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - f = functional(s.s, tempspice, corner) + f = functional(s.s, tempspice) (fail, error) = f.run() self.assertTrue(fail, error) diff --git a/compiler/tests/22_psram_1bank_8mux_func_test.py b/compiler/tests/22_psram_1bank_8mux_func_test.py index 345e50e0..d94b0660 100755 --- a/compiler/tests/22_psram_1bank_8mux_func_test.py +++ b/compiler/tests/22_psram_1bank_8mux_func_test.py @@ -57,8 +57,7 @@ class psram_1bank_8mux_func_test(openram_test): tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) - corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - f = functional(s.s, tempspice, corner) + f = functional(s.s, tempspice) (fail, error) = f.run() self.assertTrue(fail, error) diff --git a/compiler/tests/22_psram_1bank_nomux_func_test.py b/compiler/tests/22_psram_1bank_nomux_func_test.py index 3fe522ea..f9d400e3 100755 --- a/compiler/tests/22_psram_1bank_nomux_func_test.py +++ b/compiler/tests/22_psram_1bank_nomux_func_test.py @@ -56,8 +56,7 @@ class psram_1bank_nomux_func_test(openram_test): tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) - corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - f = functional(s.s, tempspice, corner) + f = functional(s.s, tempspice) (fail, error) = f.run() self.assertTrue(fail, error) diff --git a/compiler/tests/22_sram_1bank_2mux_func_test.py b/compiler/tests/22_sram_1bank_2mux_func_test.py index 3c48787f..bc1a430c 100755 --- a/compiler/tests/22_sram_1bank_2mux_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_func_test.py @@ -46,8 +46,7 @@ class sram_1bank_2mux_func_test(openram_test): tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) - corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - f = functional(s.s, tempspice, corner) + f = functional(s.s, tempspice) (fail, error) = f.run() self.assertTrue(fail, error) diff --git a/compiler/tests/22_sram_1bank_2mux_global_func_test.py b/compiler/tests/22_sram_1bank_2mux_global_func_test.py index e012bf23..e815c826 100755 --- a/compiler/tests/22_sram_1bank_2mux_global_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_global_func_test.py @@ -48,8 +48,7 @@ class sram_1bank_2mux_func_test(openram_test): tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) - corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - f = functional(s.s, tempspice, corner) + f = functional(s.s, tempspice) (fail, error) = f.run() self.assertTrue(fail, error) diff --git a/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py b/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py index 1ce68a54..887608e5 100755 --- a/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py +++ b/compiler/tests/22_sram_1bank_2mux_sparecols_func_test.py @@ -48,8 +48,7 @@ class sram_1bank_2mux_sparecols_func_test(openram_test): tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) - corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - f = functional(s.s, tempspice, corner) + f = functional(s.s, tempspice) (fail, error) = f.run() self.assertTrue(fail, error) diff --git a/compiler/tests/22_sram_1bank_4mux_func_test.py b/compiler/tests/22_sram_1bank_4mux_func_test.py index ee7795c0..2065a4a2 100755 --- a/compiler/tests/22_sram_1bank_4mux_func_test.py +++ b/compiler/tests/22_sram_1bank_4mux_func_test.py @@ -46,8 +46,7 @@ class sram_1bank_4mux_func_test(openram_test): tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) - corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - f = functional(s.s, tempspice, corner) + f = functional(s.s, tempspice) (fail, error) = f.run() self.assertTrue(fail, error) diff --git a/compiler/tests/22_sram_1bank_8mux_func_test.py b/compiler/tests/22_sram_1bank_8mux_func_test.py index 7600b7c0..a4f2ca31 100755 --- a/compiler/tests/22_sram_1bank_8mux_func_test.py +++ b/compiler/tests/22_sram_1bank_8mux_func_test.py @@ -49,8 +49,7 @@ class sram_1bank_8mux_func_test(openram_test): tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) - corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - f = functional(s.s, tempspice, corner) + f = functional(s.s, tempspice) (fail, error) = f.run() self.assertTrue(fail, error) diff --git a/compiler/tests/22_sram_1bank_nomux_1rw_1r_func_test.py b/compiler/tests/22_sram_1bank_nomux_1rw_1r_func_test.py index fbeb08c5..4f3368c2 100755 --- a/compiler/tests/22_sram_1bank_nomux_1rw_1r_func_test.py +++ b/compiler/tests/22_sram_1bank_nomux_1rw_1r_func_test.py @@ -49,8 +49,7 @@ class psram_1bank_nomux_func_test(openram_test): tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) - corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - f = functional(s.s, tempspice, corner) + f = functional(s.s, tempspice) (fail, error) = f.run() self.assertTrue(fail, error) diff --git a/compiler/tests/22_sram_1bank_nomux_func_test.py b/compiler/tests/22_sram_1bank_nomux_func_test.py index 27dfc4e5..17d3c951 100755 --- a/compiler/tests/22_sram_1bank_nomux_func_test.py +++ b/compiler/tests/22_sram_1bank_nomux_func_test.py @@ -45,8 +45,7 @@ class sram_1bank_nomux_func_test(openram_test): tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) - corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - f = functional(s.s, tempspice, corner) + f = functional(s.s, tempspice) (fail, error) = f.run() self.assertTrue(fail, error) diff --git a/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py b/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py index 0df39226..5199da62 100755 --- a/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py +++ b/compiler/tests/22_sram_1bank_nomux_sparecols_func_test.py @@ -46,8 +46,7 @@ class sram_1bank_nomux_sparecols_func_test(openram_test): tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) - corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - f = functional(s.s, tempspice, corner) + f = functional(s.s, tempspice) (fail, error) = f.run() self.assertTrue(fail, error) diff --git a/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py b/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py index f5573ae2..1af4846d 100755 --- a/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py +++ b/compiler/tests/22_sram_1bank_wmask_1rw_1r_func_test.py @@ -52,8 +52,7 @@ class sram_wmask_1w_1r_func_test(openram_test): tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) - corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - f = functional(s.s, tempspice, corner) + f = functional(s.s, tempspice) (fail, error) = f.run() self.assertTrue(fail, error) diff --git a/compiler/tests/22_sram_wmask_func_test.py b/compiler/tests/22_sram_wmask_func_test.py index dd3ac8d7..d921ade8 100755 --- a/compiler/tests/22_sram_wmask_func_test.py +++ b/compiler/tests/22_sram_wmask_func_test.py @@ -48,8 +48,7 @@ class sram_wmask_func_test(openram_test): tempspice = OPTS.openram_temp + "sram.sp" s.sp_write(tempspice) - corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0]) - f = functional(s.s, tempspice, corner) + f = functional(s.s, tempspice) (fail, error) = f.run() self.assertTrue(fail, error) diff --git a/compiler/tests/26_hspice_pex_pinv_test.py b/compiler/tests/26_hspice_pex_pinv_test.py index 74f1ae9c..425c14fe 100755 --- a/compiler/tests/26_hspice_pex_pinv_test.py +++ b/compiler/tests/26_hspice_pex_pinv_test.py @@ -77,7 +77,7 @@ class hspice_pex_pinv_test(openram_test): sim_file = OPTS.openram_temp + "stim.sp" log_file_name = "timing" test_sim = self.write_simulation(sim_file, test_module, top_level_name) - test_sim.run_sim() + test_sim.run_sim("stim.sp") delay = parse_spice_list(log_file_name, "pinv_delay") return delay diff --git a/compiler/tests/26_ngspice_pex_pinv_test.py b/compiler/tests/26_ngspice_pex_pinv_test.py index 7e3800ec..233e3f5e 100755 --- a/compiler/tests/26_ngspice_pex_pinv_test.py +++ b/compiler/tests/26_ngspice_pex_pinv_test.py @@ -76,7 +76,7 @@ class ngspice_pex_pinv_test(openram_test): sim_file = OPTS.openram_temp + "stim.sp" log_file_name = "timing" test_sim = self.write_simulation(sim_file, test_module, top_level_name) - test_sim.run_sim() + test_sim.run_sim("stim.sp") delay = parse_spice_list(log_file_name, "pinv_delay") return delay diff --git a/compiler/verify/__init__.py b/compiler/verify/__init__.py index 8da102aa..8b7a6233 100644 --- a/compiler/verify/__init__.py +++ b/compiler/verify/__init__.py @@ -40,36 +40,36 @@ else: OPTS.magic_exe = get_tool("GDS", ["magic"]) if not OPTS.drc_exe: - from .none import run_drc, print_drc_stats + from .none import run_drc, print_drc_stats, write_drc_script elif "calibre"==OPTS.drc_exe[0]: - from .calibre import run_drc, print_drc_stats + from .calibre import run_drc, print_drc_stats, write_drc_script elif "assura"==OPTS.drc_exe[0]: - from .assura import run_drc, print_drc_stats + from .assura import run_drc, print_drc_stats, write_drc_script elif "magic"==OPTS.drc_exe[0]: - from .magic import run_drc, print_drc_stats + from .magic import run_drc, print_drc_stats, write_drc_script else: debug.error("Did not find a supported DRC tool." + "Disable DRC/LVS with check_lvsdrc=False to ignore.", 2) if not OPTS.lvs_exe: - from .none import run_lvs, print_lvs_stats + from .none import run_lvs, print_lvs_stats, write_lvs_script elif "calibre"==OPTS.lvs_exe[0]: - from .calibre import run_lvs, print_lvs_stats + from .calibre import run_lvs, print_lvs_stats, write_lvs_script elif "assura"==OPTS.lvs_exe[0]: - from .assura import run_lvs, print_lvs_stats + from .assura import run_lvs, print_lvs_stats, write_lvs_script elif "netgen"==OPTS.lvs_exe[0]: - from .magic import run_lvs, print_lvs_stats + from .magic import run_lvs, print_lvs_stats, write_lvs_script else: debug.warning("Did not find a supported LVS tool." + "Disable DRC/LVS with check_lvsdrc=False to ignore.", 2) if not OPTS.pex_exe: - from .none import run_pex,print_pex_stats + from .none import run_pex, print_pex_stats elif "calibre"==OPTS.pex_exe[0]: - from .calibre import run_pex,print_pex_stats + from .calibre import run_pex, print_pex_stats elif "magic"==OPTS.pex_exe[0]: - from .magic import run_pex,print_pex_stats + from .magic import run_pex, print_pex_stats else: debug.warning("Did not find a supported PEX tool." + "Disable DRC/LVS with check_lvsdrc=False to ignore.", 2) diff --git a/compiler/verify/assura.py b/compiler/verify/assura.py index 439f833d..bd8c9c10 100644 --- a/compiler/verify/assura.py +++ b/compiler/verify/assura.py @@ -28,7 +28,7 @@ inserted in the runset. import os import re -import time +from run_script import * import debug from globals import OPTS @@ -37,16 +37,11 @@ num_drc_runs = 0 num_lvs_runs = 0 num_pex_runs = 0 -def run_drc(name, gds_name, final_verification=False): - """Run DRC check on a given top-level name which is - implemented in gds_name.""" - - global num_drc_runs - num_drc_runs += 1 +def write_drc_script(cell_name, gds_name, extract, final_verification, output_path): from tech import drc drc_rules = drc["drc_rules"] - drc_runset = OPTS.openram_temp + name + ".rsf" + drc_runset = output_path + cell_name + ".rsf" drc_log_file = "{0}{1}.log".format(OPTS.openram_temp, name) # write the runset file @@ -64,8 +59,8 @@ def run_drc(name, gds_name, final_verification=False): f.write("\n") f.write("avParameters(\n") f.write(" ?inputLayout ( \"gds2\" \"{}\" )\n".format(gds_name)) - f.write(" ?cellName \"{}\"\n".format(name)) - f.write(" ?workingDirectory \"{}\"\n".format(OPTS.openram_temp)) + f.write(" ?cellName \"{}\"\n".format(cell_name)) + f.write(" ?workingDirectory \"{}\"\n".format(output_path)) f.write(" ?rulesFile \"{}\"\n".format(drc_rules)) f.write(" ?set ( \"GridCheck\" )\n") f.write(" ?avrpt t\n") @@ -73,26 +68,37 @@ def run_drc(name, gds_name, final_verification=False): f.close() # run drc - cwd = os.getcwd() - os.chdir(OPTS.openram_temp) - cmd = "assura {0} 2> {1} 1> {2}".format(drc_runset, drc_log_file, drc_log_file) - debug.info(1, cmd) - os.system(cmd) - os.chdir(cwd) + run_file = output_path + "/run_drc.sh" + f = open(run_file, "w") + f.write("#!/bin/sh\n") + f.write("assura {0} 2> {1} 1> {2}\n".format(drc_runset, drc_log_file, drc_log_file)) + f.close() + + +def run_drc(name, gds_name, final_verification=False): + """Run DRC check on a given top-level name which is + implemented in gds_name.""" + global num_drc_runs + num_drc_runs += 1 + + write_drc_script(name, gds_name, True, final_verification, OPTS.openram_temp) + + (outfile, errfile, resultsfile) = run_script(name, "drc") + # count and report errors errors = 0 try: - f = open(OPTS.openram_temp+name+".err", "r") + f = open(OPTS.openram_temp + name +".err", "r") except: - debug.error("Unable to retrieve DRC results file.",1) + debug.error("Unable to retrieve DRC results file.", 1) results = f.readlines() f.close() for line in results: if re.match("Rule No.", line): if re.search("# INFO:", line) == None: - errors = errors + 1 - debug.info(1, line) + errors = errors + 1 + debug.info(1, line) if errors > 0: debug.error("Errors: {}".format(errors)) @@ -100,23 +106,18 @@ def run_drc(name, gds_name, final_verification=False): return errors -def run_lvs(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. """ - - global num_lvs_runs - num_lvs_runs += 1 +def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path): from tech import drc lvs_rules = drc["lvs_rules"] - lvs_runset = OPTS.openram_temp + name + ".rsf" + lvs_runset = output_path + name + ".rsf" # The LVS compare rules must be defined in the tech file for Assura. lvs_compare = drc["lvs_compare"] # Define the must-connect names for disconnected LVS nets for Assura lvs_bindings = drc["lvs_bindings"] - lvs_log_file = "{0}{1}.log".format(OPTS.openram_temp, name) + lvs_log_file = "{0}{1}.log".format(output_path, name) # Needed when FET models are sub-circuits - if drc.has_key("lvs_subcircuits"): + if "lvs_subcircuits" in drc: lvs_sub_file = drc["lvs_subcircuits"] else: lvs_sub_file = "" @@ -128,7 +129,7 @@ def run_lvs(name, gds_name, sp_name, final_verification=False): f.write("avParameters(\n") f.write(" ?inputLayout ( \"gds2\" \"{}\" )\n".format(gds_name)) f.write(" ?cellName \"{}\"\n".format(name)) - f.write(" ?workingDirectory \"{}\"\n".format(OPTS.openram_temp)) + f.write(" ?workingDirectory \"{}\"\n".format(output_path)) f.write(" ?rulesFile \"{}\"\n".format(lvs_rules)) f.write(" ?autoGrid nil\n") f.write(" ?avrpt t\n") @@ -160,27 +161,38 @@ def run_lvs(name, gds_name, sp_name, final_verification=False): f.write("avLVS()\n") f.close() - # run lvs - cwd = os.getcwd() - os.chdir(OPTS.openram_temp) - cmd = "assura {0} 2> {1} 1> {2}".format(lvs_runset, lvs_log_file, lvs_log_file) - debug.info(1, cmd) - os.system(cmd) - os.chdir(cwd) + # run drc + run_file = output_path + "/run_vls.sh" + f = open(run_file, "w") + f.write("#!/bin/sh\n") + f.write("assura {0} 2> {1} 1> {2}\n".format(lvs_runset, lvs_log_file, lvs_log_file)) + f.close() + +def run_lvs(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. """ + + global num_lvs_runs + num_lvs_runs += 1 + + write_lvs_script(name, gds_name, sp_name, final_verification, OPTS.openram_temp) + + (outfile, errfile, resultsfile) = run_script(name, "drc") + errors = 0 try: - f = open(OPTS.openram_temp+name+".csm", "r") + f = open(OPTS.openram_temp + name + ".csm", "r") except: - debug.error("Unable to retrieve LVS results file.",1) + debug.error("Unable to retrieve LVS results file.", 1) results = f.readlines() f.close() for line in results: if re.search("errors", line): - errors = errors + 1 - debug.info(1, line) + errors = errors + 1 + debug.info(1, line) elif re.search("Schematic and Layout", line): - debug.info(1, line) + debug.info(1, line) return errors @@ -188,14 +200,19 @@ def run_lvs(name, gds_name, sp_name, final_verification=False): def run_pex(name, gds_name, sp_name, output=None, final_verification=False): """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) + 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)) + debug.info(1, "DRC runs: {0}".format(num_drc_runs)) + + def print_lvs_stats(): - debug.info(1,"LVS runs: {0}".format(num_lvs_runs)) + debug.info(1, "LVS runs: {0}".format(num_lvs_runs)) + + def print_pex_stats(): - debug.info(1,"PEX runs: {0}".format(num_pex_runs)) + debug.info(1, "PEX runs: {0}".format(num_pex_runs)) diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 6970b271..68a2af8a 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -30,7 +30,7 @@ num_lvs_runs = 0 num_pex_runs = 0 -def write_calibre_drc_script(cell_name, extract, final_verification, gds_name): +def write_drc_script(cell_name, gds_name, extract, final_verification, output_path): """ Write a Calibre runset file and script to run DRC """ # the runset file contains all the options to run calibre from tech import drc @@ -38,7 +38,7 @@ def write_calibre_drc_script(cell_name, extract, final_verification, gds_name): drc_runset = { 'drcRulesFile': drc_rules, - 'drcRunDir': OPTS.openram_temp, + 'drcRunDir': output_path, 'drcLayoutPaths': gds_name, 'drcLayoutPrimary': cell_name, 'drcLayoutSystem': 'GDSII', @@ -50,17 +50,17 @@ def write_calibre_drc_script(cell_name, extract, final_verification, gds_name): } # write the runset file - f = open(OPTS.openram_temp + "drc_runset", "w") + f = open(output_path + "drc_runset", "w") for k in sorted(iter(drc_runset.keys())): f.write("*{0}: {1}\n".format(k, drc_runset[k])) f.close() # Create an auxiliary script to run calibre with the runset - run_file = OPTS.openram_temp + "run_drc.sh" + run_file = output_path + "run_drc.sh" f = open(run_file, "w") f.write("#!/bin/sh\n") cmd = "{0} -gui -drc {1}drc_runset -batch".format(OPTS.drc_exe[1], - OPTS.openram_temp) + output_path) f.write(cmd) f.write("\n") f.close() @@ -68,14 +68,14 @@ def write_calibre_drc_script(cell_name, extract, final_verification, gds_name): return drc_runset -def write_calibre_lvs_script(cell_name, final_verification, gds_name, sp_name): +def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path): """ Write a Calibre runset file and script to run LVS """ from tech import drc lvs_rules = drc["lvs_rules"] lvs_runset = { 'lvsRulesFile': lvs_rules, - 'lvsRunDir': OPTS.openram_temp, + 'lvsRunDir': output_path, 'lvsLayoutPaths': gds_name, 'lvsLayoutPrimary': cell_name, 'lvsSourcePath': sp_name, @@ -111,19 +111,19 @@ def write_calibre_lvs_script(cell_name, final_verification, gds_name, sp_name): # write the runset file - f = open(OPTS.openram_temp + "lvs_runset", "w") + f = open(output_path + "lvs_runset", "w") for k in sorted(iter(lvs_runset.keys())): f.write("*{0}: {1}\n".format(k, lvs_runset[k])) f.close() # Create an auxiliary script to run calibre with the runset - run_file = OPTS.openram_temp + "run_lvs.sh" + run_file = output_path + "run_lvs.sh" f = open(run_file, "w") f.write("#!/bin/sh\n") PDK_DIR=os.environ.get("PDK_DIR") f.write("export PDK_DIR={}\n".format(PDK_DIR)) cmd = "{0} -gui -lvs {1}lvs_runset -batch".format(OPTS.lvs_exe[1], - OPTS.openram_temp) + output_path) f.write(cmd) f.write("\n") f.close() @@ -132,16 +132,16 @@ def write_calibre_lvs_script(cell_name, final_verification, gds_name, sp_name): return lvs_runset -def write_calibre_pex_script(cell_name, extract, output, final_verification): +def write_pex_script(cell_name, extract, output, final_verification, output_path): """ Write a pex script that can either just extract the netlist or the netlist+parasitics """ if output == None: output = cell_name + ".pex.sp" # check if lvs report has been done # if not run drc and lvs - if not os.path.isfile(OPTS.openram_temp + cell_name + ".lvs.report"): - gds_name = OPTS.openram_temp +"/"+ cell_name + ".gds" - sp_name = OPTS.openram_temp +"/"+ cell_name + ".sp" + if not os.path.isfile(output_path + cell_name + ".lvs.report"): + gds_name = output_path +"/"+ cell_name + ".gds" + sp_name = output_path +"/"+ cell_name + ".sp" run_drc(cell_name, gds_name) run_lvs(cell_name, gds_name, sp_name) @@ -149,7 +149,7 @@ def write_calibre_pex_script(cell_name, extract, output, final_verification): pex_rules = drc["xrc_rules"] pex_runset = { 'pexRulesFile': pex_rules, - 'pexRunDir': OPTS.openram_temp, + 'pexRunDir': output_path, 'pexLayoutPaths': cell_name + ".gds", 'pexLayoutPrimary': cell_name, 'pexSourcePath': cell_name + ".sp", @@ -162,13 +162,13 @@ def write_calibre_pex_script(cell_name, extract, output, final_verification): } # write the runset file - f = open(OPTS.openram_temp + "pex_runset", "w") + f = open(output_path + "pex_runset", "w") for k in sorted(iter(pex_runset.keys())): f.write("*{0}: {1}\n".format(k, pex_runset[k])) f.close() # Create an auxiliary script to run calibre with the runset - run_file = OPTS.openram_temp + "run_pex.sh" + run_file = output_path + "run_pex.sh" f = open(run_file, "w") f.write("#!/bin/sh\n") cmd = "{0} -gui -pex {1}pex_runset -batch".format(OPTS.pex_exe[1], @@ -198,7 +198,7 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False): if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)): shutil.copy(gds_name, OPTS.openram_temp) - drc_runset = write_calibre_drc_script(cell_name, extract, final_verification, gds_name) + drc_runset = write_drc_script(cell_name, gds_name, extract, final_verification, OPTS.openram_temp) if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)): shutil.copy(gds_name, OPTS.openram_temp + os.path.basename(gds_name)) @@ -212,7 +212,7 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False): try: f = open(OPTS.openram_temp + drc_runset['drcSummaryFile'], "r") except: - debug.error("Unable to retrieve DRC results file. Is calibre set up?",1) + debug.error("Unable to retrieve DRC results file. Is calibre set up?", 1) results = f.readlines() f.close() # those lines should be the last 3 @@ -241,7 +241,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): global num_lvs_runs num_lvs_runs += 1 - lvs_runset = write_calibre_lvs_script(cell_name, final_verification, gds_name, sp_name) + lvs_runset = write_lvs_script(cell_name, gds_name, sp_name, final_verification, OPTS.openram_temp) # Copy file to local dir if it isn't already if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)): @@ -328,7 +328,7 @@ def run_pex(cell_name, gds_name, sp_name, output=None, final_verification=False) global num_pex_runs num_pex_runs += 1 - write_calibre_pex_script(cell_name, True, output, final_verification) + write_pex_script(cell_name, True, output, final_verification, OPTS.openram_temp) # Copy file to local dir if it isn't already if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)): @@ -390,9 +390,14 @@ def correct_port(name, output_file_name, ref_file_name): output_file.write(part2) output_file.close() + def print_drc_stats(): - debug.info(1,"DRC runs: {0}".format(num_drc_runs)) + debug.info(1, "DRC runs: {0}".format(num_drc_runs)) + + def print_lvs_stats(): - debug.info(1,"LVS runs: {0}".format(num_lvs_runs)) + debug.info(1, "LVS runs: {0}".format(num_lvs_runs)) + + def print_pex_stats(): - debug.info(1,"PEX runs: {0}".format(num_pex_runs)) + debug.info(1, "PEX runs: {0}".format(num_pex_runs)) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 245d1408..04d9a4ac 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -66,12 +66,19 @@ def filter_gds(cell_name, input_gds, output_gds): (outfile, errfile, resultsfile) = run_script(cell_name, "filter") -def write_magic_script(cell_name, extract=False, final_verification=False): +def write_drc_script(cell_name, gds_name, extract, final_verification, output_path): """ Write a magic script to perform DRC and optionally extraction. """ global OPTS - run_file = OPTS.openram_temp + "run_drc.sh" + # Copy .magicrc file into the directory + magic_file = OPTS.openram_tech + "tech/.magicrc" + if os.path.exists(magic_file): + shutil.copy(magic_file, output_path) + else: + debug.warning("Could not locate .magicrc file: {}".format(magic_file)) + + run_file = output_path + "run_drc.sh" f = open(run_file, "w") f.write("#!/bin/sh\n") f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1])) @@ -79,7 +86,7 @@ def write_magic_script(cell_name, extract=False, final_verification=False): f.write("gds warning default\n") f.write("gds flatten true\n") f.write("gds readonly true\n") - f.write("gds read {}.gds\n".format(cell_name)) + f.write("gds read {}\n".format(gds_name)) f.write("load {}\n".format(cell_name)) # Flatten the cell to get rid of DRCs spanning multiple layers # (e.g. with routes) @@ -131,32 +138,6 @@ def write_magic_script(cell_name, extract=False, final_verification=False): os.system("chmod u+x {}".format(run_file)) -def write_netgen_script(cell_name): - """ Write a netgen script to perform LVS. """ - - global OPTS - - setup_file = "setup.tcl" - full_setup_file = OPTS.openram_tech + "tech/" + setup_file - if os.path.exists(full_setup_file): - # Copy setup.tcl file into temp dir - shutil.copy(full_setup_file, OPTS.openram_temp) - else: - setup_file = 'nosetup' - - run_file = OPTS.openram_temp + "run_lvs.sh" - f = open(run_file, "w") - f.write("#!/bin/sh\n") - f.write("{} -noconsole << EOF\n".format(OPTS.lvs_exe[1])) - f.write("readnet spice {0}.spice\n".format(cell_name)) - f.write("readnet spice {0}.sp\n".format(cell_name)) - f.write("lvs {{{0}.spice {0}}} {{{0}.sp {0}}} {1} {0}.lvs.report -json\n".format(cell_name, setup_file)) - f.write("quit\n") - f.write("EOF\n") - f.close() - os.system("chmod u+x {}".format(run_file)) - - def run_drc(cell_name, gds_name, extract=True, final_verification=False): """Run DRC check on a cell which is implemented in gds_name.""" @@ -167,14 +148,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False): if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): shutil.copy(gds_name, OPTS.openram_temp) - # Copy .magicrc file into temp dir - magic_file = OPTS.openram_tech + "tech/.magicrc" - if os.path.exists(magic_file): - shutil.copy(magic_file, OPTS.openram_temp) - else: - debug.warning("Could not locate .magicrc file: {}".format(magic_file)) - - write_magic_script(cell_name, extract, final_verification) + write_drc_script(cell_name, gds_name, extract, final_verification, OPTS.openram_temp) (outfile, errfile, resultsfile) = run_script(cell_name, "drc") @@ -214,6 +188,32 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False): return errors +def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path): + """ Write a netgen script to perform LVS. """ + + global OPTS + + setup_file = "setup.tcl" + full_setup_file = OPTS.openram_tech + "tech/" + setup_file + if os.path.exists(full_setup_file): + # Copy setup.tcl file into temp dir + shutil.copy(full_setup_file, output_path) + else: + setup_file = 'nosetup' + + run_file = output_path + "/run_lvs.sh" + f = open(run_file, "w") + f.write("#!/bin/sh\n") + f.write("{} -noconsole << EOF\n".format(OPTS.lvs_exe[1])) + # f.write("readnet spice {0}.spice\n".format(cell_name)) + # f.write("readnet spice {0}\n".format(sp_name)) + f.write("lvs {{{0}.spice {0}}} {{{1} {0}}} {2} {0}.lvs.report -json\n".format(cell_name, sp_name, setup_file)) + f.write("quit\n") + f.write("EOF\n") + f.close() + os.system("chmod u+x {}".format(run_file)) + + 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 @@ -228,7 +228,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): if os.path.dirname(sp_name)!=OPTS.openram_temp.rstrip('/'): shutil.copy(sp_name, OPTS.openram_temp) - write_netgen_script(cell_name) + write_lvs_script(cell_name, gds_name, sp_name, final_verification, OPTS.openram_temp) (outfile, errfile, resultsfile) = run_script(cell_name, "lvs") @@ -238,7 +238,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): try: f = open(resultsfile, "r") except FileNotFoundError: - debug.error("Unable to load LVS results from {}".format(resultsfile),1) + debug.error("Unable to load LVS results from {}".format(resultsfile), 1) results = f.readlines() f.close() @@ -249,7 +249,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): if "Subcircuit summary:" in line: break else: - final_results.insert(0,line) + final_results.insert(0, line) # There were property errors in any module. test = re.compile("Property errors were found.") diff --git a/compiler/verify/none.py b/compiler/verify/none.py index f82d59ae..28a5a47b 100644 --- a/compiler/verify/none.py +++ b/compiler/verify/none.py @@ -17,6 +17,10 @@ lvs_warned = False pex_warned = False +def write_drc_script(cell_name, gds_name, extract, final_verification, output_path): + pass + + def run_drc(cell_name, gds_name, extract=False, final_verification=False): global drc_warned if not drc_warned: @@ -26,6 +30,10 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False): return 1 +def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path): + pass + + def run_lvs(cell_name, gds_name, sp_name, final_verification=False): global lvs_warned if not lvs_warned: diff --git a/compiler/verify/run_script.py b/compiler/verify/run_script.py index 3bc8d2d8..f7bb2d9f 100644 --- a/compiler/verify/run_script.py +++ b/compiler/verify/run_script.py @@ -13,6 +13,7 @@ import os import debug from globals import OPTS + def run_script(cell_name, script="lvs"): """ Run script and create output files. """ @@ -30,5 +31,5 @@ def run_script(cell_name, script="lvs"): os.system(cmd) os.chdir(cwd) - return (outfile,errfile,resultsfile) + return (outfile, errfile, resultsfile)