Remove setup/hold measure and compute it directly.

This commit is contained in:
mrg 2021-05-14 10:01:10 -07:00
parent d43edd95e4
commit 9555b52aaa
1 changed files with 30 additions and 49 deletions

View File

@ -76,10 +76,10 @@ class setup_hold():
self.stim.write_supply() self.stim.write_supply()
def write_data(self, mode, target_time, correct_value): def write_data(self, mode, target_time, correct_value):
"""Create the data signals for setup/hold analysis. First period is to """
Create the data signals for setup/hold analysis. First period is to
initialize it to the opposite polarity. Second period is used for initialize it to the opposite polarity. Second period is used for
characterization. characterization.
""" """
self.sf.write("\n* Generation of the data and clk signals\n") self.sf.write("\n* Generation of the data and clk signals\n")
if correct_value == 1: if correct_value == 1:
@ -106,8 +106,11 @@ class setup_hold():
setup=0) setup=0)
def write_clock(self): def write_clock(self):
""" Create the clock signal for setup/hold analysis. First period initializes the FF """
while the second is used for characterization.""" Create the clock signal for setup/hold analysis.
First period initializes the FF
while the second is used for characterization.
"""
self.stim.gen_pwl(sig_name="clk", self.stim.gen_pwl(sig_name="clk",
# initial clk edge is right after the 0 time to initialize a flop # initial clk edge is right after the 0 time to initialize a flop
@ -128,16 +131,6 @@ class setup_hold():
else: else:
dout_rise_or_fall = "FALL" dout_rise_or_fall = "FALL"
# in SETUP mode, the input mirrors what the output should be
if mode == "SETUP":
din_rise_or_fall = dout_rise_or_fall
else:
# in HOLD mode, however, the input should be opposite of the output
if correct_value == 1:
din_rise_or_fall = "FALL"
else:
din_rise_or_fall = "RISE"
self.sf.write("\n* Measure statements for pass/fail verification\n") self.sf.write("\n* Measure statements for pass/fail verification\n")
trig_name = "clk" trig_name = "clk"
targ_name = "Q" targ_name = "Q"
@ -153,19 +146,6 @@ class setup_hold():
trig_td=1.9 * self.period, trig_td=1.9 * self.period,
targ_td=1.9 * self.period) targ_td=1.9 * self.period)
targ_name = "D"
# Start triggers right after initialize value is returned to normal
# at one period
self.stim.gen_meas_delay(meas_name="setup_hold_time",
trig_name=trig_name,
targ_name=targ_name,
trig_val=trig_val,
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)
def bidir_search(self, correct_value, mode): def bidir_search(self, correct_value, mode):
""" This will perform a bidirectional search for either setup or hold times. """ This will perform a bidirectional search for either setup or hold times.
It starts with the feasible priod and looks a half period beyond or before it It starts with the feasible priod and looks a half period beyond or before it
@ -189,21 +169,24 @@ class setup_hold():
correct_value=correct_value) correct_value=correct_value)
self.stim.run_sim(self.stim_sp) self.stim.run_sim(self.stim_sp)
ideal_clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay")) 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")) # We use a 1/2 speed clock for some reason...
debug.info(2,"*** {0} CHECK: {1} Ideal Clk-to-Q: {2} Setup/Hold: {3}".format(mode, correct_value,ideal_clk_to_q,setuphold_time)) setuphold_time = (feasible_bound - 2 * self.period) / 1e9
if mode == "SETUP": # SETUP is clk-din, not din-clk
passing_setuphold_time = -1e9 * setuphold_time
else:
passing_setuphold_time = 1e9 * setuphold_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: if type(ideal_clk_to_q)!=float:
debug.error("Initial hold time fails for data value feasible bound {0} Clk-to-Q {1} Setup/Hold {2}".format(feasible_bound, 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, ideal_clk_to_q,
setuphold_time), setuphold_time),
2) 2)
if mode == "SETUP": # SETUP is clk-din, not din-clk
setuphold_time *= -1e9
else:
setuphold_time *= 1e9
passing_setuphold_time = setuphold_time
debug.info(2, "Checked initial {0} time {1}, data at {2}, clock at {3} ".format(mode, debug.info(2, "Checked initial {0} time {1}, data at {2}, clock at {3} ".format(mode,
setuphold_time, setuphold_time,
feasible_bound, feasible_bound,
@ -224,15 +207,14 @@ class setup_hold():
self.stim.run_sim(self.stim_sp) self.stim.run_sim(self.stim_sp)
clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay")) clk_to_q = convert_to_float(parse_spice_list("timing", "clk2q_delay"))
setuphold_time = convert_to_float(parse_spice_list("timing", "setup_hold_time")) # We use a 1/2 speed clock for some reason...
if type(clk_to_q) == float and (clk_to_q < 1.1 * ideal_clk_to_q) and type(setuphold_time)==float: setuphold_time = (target_time - 2 * self.period) / 1e9
if mode == "SETUP": # SETUP is clk-din, not din-clk if mode == "SETUP": # SETUP is clk-din, not din-clk
setuphold_time *= -1e9 passing_setuphold_time = -1e9 * setuphold_time
else: else:
setuphold_time *= 1e9 passing_setuphold_time = 1e9 * setuphold_time
if type(clk_to_q) == float and (clk_to_q < 1.1 * ideal_clk_to_q):
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 feasible_bound = target_time
else: 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))
@ -242,7 +224,6 @@ class setup_hold():
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 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 return passing_setuphold_time