diff --git a/compiler/characterizer/__init__.py b/compiler/characterizer/__init__.py index 93dd5bcb5..9ceefde66 100644 --- a/compiler/characterizer/__init__.py +++ b/compiler/characterizer/__init__.py @@ -28,7 +28,7 @@ if OPTS.spice_exe=="" or OPTS.spice_exe==None: debug.error("{0} not found. Unable to perform characterization.".format(OPTS.spice_name),1) else: - (OPTS.spice_name,OPTS.spice_exe) = get_tool("spice",["hspice", "ngspice", "ngspice.exe", "xa"]) + (OPTS.spice_name,OPTS.spice_exe) = get_tool("spice",["hspice", "ngspice", "ngspice.exe", "xa", "alps"]) # set the input dir for spice files if using ngspice if OPTS.spice_name == "ngspice": diff --git a/compiler/characterizer/charutils.py b/compiler/characterizer/charutils.py index fa49b1ed9..a0ca63a6a 100644 --- a/compiler/characterizer/charutils.py +++ b/compiler/characterizer/charutils.py @@ -20,6 +20,9 @@ def parse_spice_list(filename, key): if OPTS.spice_name == "xa" : # customsim has a different output file name full_filename="{0}xa.meas".format(OPTS.openram_temp) + elif OPTS.spice_name == "alps": + # alps using a .measure + full_filename="{0}{1}.measure".format(OPTS.openram_temp, filename) else: # ngspice/hspice using a .lis file full_filename="{0}{1}.lis".format(OPTS.openram_temp, filename) diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 3f5d61afd..847e1c35a 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -581,8 +581,8 @@ def get_power_measure_variants(self, port, power_obj, operation): """Get the measurement values that can either vary port to port (time delays)""" # Return value is intended to match the power measure format: t_initial, t_final, port - t_initial = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]] - t_final = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]+1] + t_initial = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]]-self.slew/2-self.period*0.05 + t_final = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]+1]-self.slew/2-self.period*0.05 return (t_initial, t_final, port) @@ -666,7 +666,7 @@ def write_power_measures(self): t_final = 2*self.period self.stim.gen_meas_power(meas_name="leakage_power", t_initial=t_initial, - t_final=t_final) + t_final=t_final, leakage=True) def find_feasible_period_one_port(self, port): """ diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index 525f2180c..ae263c1ef 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -325,16 +325,18 @@ def write_bus(self): self.lib.write(" base_type : array;\n") self.lib.write(" data_type : bit;\n") self.lib.write(" bit_width : {0};\n".format(self.sram.word_size)) - self.lib.write(" bit_from : 0;\n") - self.lib.write(" bit_to : {0};\n".format(self.sram.word_size - 1)) + self.lib.write(" bit_from : {0};\n".format(self.sram.word_size - 1)) + self.lib.write(" bit_to : 0;\n") + self.lib.write(" downto : true;\n") self.lib.write(" }\n\n") self.lib.write(" type (addr){\n") self.lib.write(" base_type : array;\n") self.lib.write(" data_type : bit;\n") self.lib.write(" bit_width : {0};\n".format(self.sram.addr_size)) - self.lib.write(" bit_from : 0;\n") - self.lib.write(" bit_to : {0};\n".format(self.sram.addr_size - 1)) + self.lib.write(" bit_from : {0};\n".format(self.sram.addr_size - 1)) + self.lib.write(" bit_to : 0;\n") + self.lib.write(" downto : true;\n") self.lib.write(" }\n\n") if self.sram.write_size: @@ -342,8 +344,9 @@ def write_bus(self): self.lib.write(" base_type : array;\n") self.lib.write(" data_type : bit;\n") self.lib.write(" bit_width : {0};\n".format(self.sram.num_wmasks)) - self.lib.write(" bit_from : 0;\n") - self.lib.write(" bit_to : {0};\n".format(self.sram.num_wmasks - 1)) + self.lib.write(" bit_from : {0};\n".format(self.sram.num_wmasks - 1)) + self.lib.write(" bit_to : 0;\n") + self.lib.write(" downto : true;\n") self.lib.write(" }\n\n") diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index 11dc449a0..915a4071d 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -192,18 +192,29 @@ def gen_meas_find_voltage_at_time(self, meas_name, targ_name, time_at): targ_name, time_at)) - def gen_meas_power(self, meas_name, t_initial, t_final): + def gen_meas_power(self, meas_name, t_initial, t_final, leakage=False): """ Creates the .meas statement for the measurement of avg power """ # power mea cmd is different in different spice: if OPTS.spice_name == "hspice": power_exp = "power" else: power_exp = "par('(-1*v(" + str(self.vdd_name) + ")*I(v" + str(self.vdd_name) + "))')" - self.sf.write(".meas tran {0} avg {1} from={2}n to={3}n\n\n".format(meas_name, - power_exp, - t_initial, - t_final)) - + if leakage: + self.sf.write(".meas tran {0} avg {1} from={2}n to={3}n\n".format(meas_name, + power_exp, + t_initial, + t_final)) + else: + self.sf.write(".meas tran {0}_total avg {1} from={2}n to={3}n\n".format(meas_name, + power_exp, + t_initial, + t_final)) + self.sf.write(".meas tran {0}_leakage avg {1} from={2}n to={3}n\n".format(meas_name, + power_exp, + t_final-0.05*(t_final-t_initial), + t_final)) + self.sf.write(".meas tran {0} param='{0}_total - {0}_leakage'\n\n".format(meas_name)) + def gen_meas_value(self, meas_name, dout, t_intital, t_final): measure_string=".meas tran {0} AVG v({1}) FROM={2}n TO={3}n\n\n".format(meas_name, dout, t_intital, t_final) self.sf.write(measure_string) @@ -230,9 +241,11 @@ def write_control(self, end_time, runlvl=4): # which is more accurate, but slower than the default trapezoid method # Do not remove this or it may not converge due to some "pa_00" nodes # unless you figure out what these are. - self.sf.write(".OPTIONS POST=1 RELTOL={0} PROBE method=gear\n".format(reltol)) + self.sf.write(".OPTIONS POST={1} RELTOL={0} PROBE method=gear\n".format(reltol, 0 if OPTS.purge_temp else 1)) + elif OPTS.spice_name == "alps": + self.sf.write(".OPTIONS POST={2} RUNLVL={0} RELTOL={1} PROBE LEAST_DISK_SPACE=2000\n".format(runlvl, reltol, 0 if OPTS.purge_temp else 1)) else: - self.sf.write(".OPTIONS POST=1 RUNLVL={0} PROBE\n".format(runlvl)) + self.sf.write(".OPTIONS POST={1} RUNLVL={0} PROBE\n".format(runlvl, 0 if OPTS.purge_temp else 1)) # create plots for all signals self.sf.write("* probe is used for hspice/xa, while plot is used in ngspice\n") @@ -297,7 +310,15 @@ def run_sim(self): valid_retcode=0 elif OPTS.spice_name == "hspice": # TODO: Should make multithreading parameter a configuration option - cmd = "{0} -mt 2 -i {1} -o {2}timing".format(OPTS.spice_exe, + cmd = "{0} -mt {1} -i {2} -o {3}timing".format(OPTS.spice_exe, + OPTS.num_threads, + temp_stim, + OPTS.openram_temp) + valid_retcode=0 + elif OPTS.spice_name == "alps": + # TODO: Should make multithreading parameter a configuration option + cmd = "{0} -mt {1} -i {2} -o {3}timing".format(OPTS.spice_exe, + OPTS.num_threads, temp_stim, OPTS.openram_temp) valid_retcode=0 diff --git a/compiler/globals.py b/compiler/globals.py index dd4ac1779..342b5fd19 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -82,7 +82,11 @@ def parse_args(): "--dontpurge", action="store_false", dest="purge_temp", - help="Don't purge the contents of the temp directory after a successful run") + help="Don't purge the contents of the temp directory after a successful run"), + optparse.make_option( + "--num_threads", + dest="num_threads", + help="Number of threads used by simulator. Default is 2") # -h --help is implicit. } diff --git a/compiler/options.py b/compiler/options.py index d97ea3009..26c18960d 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -102,6 +102,9 @@ class options(optparse.Values): spice_name = "" # The spice executable being used which is derived from the user PATH. spice_exe = "" + + # Thread number for hspice and alps + num_threads = 2 # Variable to select the variant of drc, lvs, pex drc_name = "" lvs_name = "" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..6bad10388 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +numpy +scipy