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.

This commit is contained in:
Matt Guthaus 2018-02-05 11:36:46 -08:00
parent 92095e52f7
commit a8e1abdce8
5 changed files with 39 additions and 23 deletions

View File

@ -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]

View File

@ -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")

View File

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

View File

@ -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:

View File

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