From a8e1abdce89f716d553995a3fbeed6aa543313b3 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 5 Feb 2018 11:36:46 -0800 Subject: [PATCH] Use method=gear for ngspice to improve convergence. Split TD for trig and targ in measure statements. Start waiting for clk neg edge trigger at clk pos edge. --- compiler/characterizer/delay.py | 28 ++++++++++++++++------------ compiler/characterizer/lib.py | 8 ++++---- compiler/characterizer/setup_hold.py | 6 ++++-- compiler/characterizer/stimuli.py | 15 +++++++++++---- compiler/characterizer/trim_spice.py | 5 ++++- 5 files changed, 39 insertions(+), 23 deletions(-) diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 2ffc2d6e..c848ec5d 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -40,9 +40,9 @@ class delay(): def write_stimulus(self, period, load, slew): - """Creates a stimulus file for simulations to probe a certain bitcell, given an address and data-position of the data-word - (probe-address form: '111010000' LSB=0, MSB=1) - (probe_data form: number corresponding to the bit position of data-bus, begins with position 0) + """ Creates a stimulus file for simulations to probe a bitcell at a given clock period. + Address and bit were previously set with set_probe(). + Input slew (in ns) and output capacitive load (in fF) are required for charaterization. """ self.check_arguments() @@ -52,7 +52,7 @@ class delay(): # creates and opens stimulus file for writing temp_stim = "{0}/stim.sp".format(OPTS.openram_temp) self.sf = open(temp_stim, "w") - self.sf.write("* Stimulus for period of {0}n load={1} slew={2}\n\n".format(period,load,slew)) + self.sf.write("* Stimulus for period of {0}n load={1}fF slew={2}ns\n\n".format(period,load,slew)) # include files in stimulus file model_list = tech.spice["fet_models"] + [self.sram_sp_file] @@ -141,7 +141,8 @@ class delay(): targ_val=targ_val, trig_dir="FALL", targ_dir="FALL", - td=self.cycle_times[self.read0_cycle]+0.5*period) + trig_td=self.cycle_times[self.read0_cycle], + targ_td=self.cycle_times[self.read0_cycle]+0.5*period) stimuli.gen_meas_delay(stim_file=self.sf, meas_name="DELAY1", @@ -151,27 +152,30 @@ class delay(): targ_val=targ_val, trig_dir="FALL", targ_dir="RISE", - td=self.cycle_times[self.read1_cycle]+0.5*period) + trig_td=self.cycle_times[self.read1_cycle], + targ_td=self.cycle_times[self.read1_cycle]+0.5*period) stimuli.gen_meas_delay(stim_file=self.sf, meas_name="SLEW0", trig_name=targ_name, targ_name=targ_name, - trig_val=0.9*self.vdd, - targ_val=0.1*self.vdd, + trig_val=0.8*self.vdd, + targ_val=0.2*self.vdd, trig_dir="FALL", targ_dir="FALL", - td=self.cycle_times[self.read0_cycle]+0.5*period) + trig_td=self.cycle_times[self.read0_cycle], + targ_td=self.cycle_times[self.read0_cycle]+0.5*period) stimuli.gen_meas_delay(stim_file=self.sf, meas_name="SLEW1", trig_name=targ_name, targ_name=targ_name, - trig_val=0.1*self.vdd, - targ_val=0.9*self.vdd, + trig_val=0.2*self.vdd, + targ_val=0.8*self.vdd, trig_dir="RISE", targ_dir="RISE", - td=self.cycle_times[self.read1_cycle]+0.5*period) + trig_td=self.cycle_times[self.read1_cycle], + targ_td=self.cycle_times[self.read1_cycle]+0.5*period) # add measure statements for power t_initial = self.cycle_times[self.write0_cycle] diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index b2a87479..3716b51b 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -116,10 +116,10 @@ class lib: self.lib.write(" output_threshold_pct_fall : 50.0 ;\n") self.lib.write(" input_threshold_pct_rise : 50.0 ;\n") self.lib.write(" output_threshold_pct_rise : 50.0 ;\n") - self.lib.write(" slew_lower_threshold_pct_fall : 10.0 ;\n") - self.lib.write(" slew_upper_threshold_pct_fall : 90.0 ;\n") - self.lib.write(" slew_lower_threshold_pct_rise : 10.0 ;\n") - self.lib.write(" slew_upper_threshold_pct_rise : 90.0 ;\n\n") + self.lib.write(" slew_lower_threshold_pct_fall : 20.0 ;\n") + self.lib.write(" slew_upper_threshold_pct_fall : 80.0 ;\n") + self.lib.write(" slew_lower_threshold_pct_rise : 20.0 ;\n") + self.lib.write(" slew_upper_threshold_pct_rise : 80.0 ;\n\n") self.lib.write(" default_cell_leakage_power : 0.0 ;\n") self.lib.write(" default_leakage_power_density : 0.0 ;\n") diff --git a/compiler/characterizer/setup_hold.py b/compiler/characterizer/setup_hold.py index 919bb9b9..a184ffcb 100644 --- a/compiler/characterizer/setup_hold.py +++ b/compiler/characterizer/setup_hold.py @@ -145,7 +145,8 @@ class setup_hold(): targ_val=targ_val, trig_dir="RISE", targ_dir=dout_rise_or_fall, - 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 @@ -158,7 +159,8 @@ class setup_hold(): targ_val=targ_val, trig_dir="RISE", targ_dir=din_rise_or_fall, - td=1.2*self.period) + trig_td=1.2*self.period, + targ_td=1.2*self.period) diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index 7ffd9e85..e4d81d30 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -218,17 +218,18 @@ def get_inverse_value(value): debug.error("Invalid value to get an inverse of: {0}".format(value)) -def gen_meas_delay(stim_file, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, td): +def gen_meas_delay(stim_file, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, trig_td, targ_td): """Creates the .meas statement for the measurement of delay""" - measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={7}n TARG v({4}) VAL={5} {6}=1 TD={7}n\n\n" + measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={4}n TARG v({5}) VAL={6} {7}=1 TD={8}n\n\n" stim_file.write(measure_string.format(meas_name, trig_name, trig_val, trig_dir, + trig_td, targ_name, targ_val, targ_dir, - td)) + targ_td)) def gen_meas_power(stim_file, meas_name, t_initial, t_final): """Creates the .meas statement for the measurement of avg power""" @@ -246,7 +247,13 @@ def gen_meas_power(stim_file, meas_name, t_initial, t_final): def write_control(stim_file, end_time): # UIC is needed for ngspice to converge stim_file.write(".TRAN 5p {0}n UIC\n".format(end_time)) - stim_file.write(".OPTIONS POST=1 RUNLVL=4 PROBE\n") + if OPTS.spice_name == "ngspice": + # ngspice sometimes has convergence problems if not using gear method + # which is more accurate, but slower than the default trapezoid method + stim_file.write(".OPTIONS POST=1 RUNLVL=4 PROBE method=gear\n") + else: + stim_file.write(".OPTIONS POST=1 RUNLVL=4 PROBE\n") + # create plots for all signals stim_file.write("* probe is used for hspice/xa, while plot is used in ngspice\n") if OPTS.debug_level>0: diff --git a/compiler/characterizer/trim_spice.py b/compiler/characterizer/trim_spice.py index 30f041a4..f53ac184 100644 --- a/compiler/characterizer/trim_spice.py +++ b/compiler/characterizer/trim_spice.py @@ -48,7 +48,10 @@ class trim_spice(): # Split up the address and convert to an int wl_address = int(address[self.col_addr_size:],2) - col_address = int(address[0:self.col_addr_size],2) + if self.col_addr_size>1: + col_address = int(address[0:self.col_addr_size],2) + else: + col_address = 0 # 1. Keep cells in the bitcell array based on WL and BL wl_name = "wl[{}]".format(wl_address) bl_name = "bl[{}]".format(self.words_per_row*data_bit + col_address)