def run_simulation(self, period, load, slew): """ This tries to simulate a period and checks if the result works. If so, it returns True and the delays and slews.""" # Checking from not data_value to data_value self.write_stimulus(period, load, slew) stimuli.run_sim() delay0 = ch.convert_to_float(ch.parse_output("timing", "delay0")) delay1 = ch.convert_to_float(ch.parse_output("timing", "delay1")) slew0 = ch.convert_to_float(ch.parse_output("timing", "slew0")) slew1 = ch.convert_to_float(ch.parse_output("timing", "slew1")) # if it failed or the read was longer than a period if type(delay0) != float or type(delay1) != float or type( slew1) != float or type(slew0) != float: return (False, 0, 0, 0, 0) delay0 *= 1e9 delay1 *= 1e9 slew0 *= 1e9 slew1 *= 1e9 if delay0 > period or delay1 > period or slew0 > period or slew1 > period: return (False, 0, 0, 0, 0) else: debug.info( 2, "Successful simulation: period {0} load {1} slew {2}, delay0={3}n delay1={4}ns slew0={5}n slew1={6}n" .format(period, load, slew, delay0, delay1, slew0, slew1)) #key=raw_input("press return to continue") # The delay is from the negative edge for our SRAM return (True, delay1, slew1, delay0, slew0)
def try_period(self, period, load, slew, feasible_delay1, feasible_delay0): """ This tries to simulate a period and checks if the result works. If it does and the delay is within 5% still, it returns True.""" # Checking from not data_value to data_value self.write_stimulus(period,load,slew) stimuli.run_sim() delay0 = ch.convert_to_float(ch.parse_output("timing", "delay0")) delay1 = ch.convert_to_float(ch.parse_output("timing", "delay1")) slew0 = ch.convert_to_float(ch.parse_output("timing", "slew0")) slew1 = ch.convert_to_float(ch.parse_output("timing", "slew1")) # if it failed or the read was longer than a period if type(delay0)!=float or type(delay1)!=float or type(slew1)!=float or type(slew0)!=float: debug.info(2,"Invalid measures: Period {0}, delay0={1}ns, delay1={2}ns slew0={3}ns slew1={4}ns".format(period, delay0, delay1, slew0, slew1)) return False delay0 *= 1e9 delay1 *= 1e9 slew0 *= 1e9 slew1 *= 1e9 if delay0>period or delay1>period or slew0>period or slew1>period: debug.info(2,"Too long delay/slew: Period {0}, delay0={1}ns, delay1={2}ns slew0={3}ns slew1={4}ns".format(period, delay0, delay1, slew0, slew1)) return False else: if not ch.relative_compare(delay1,feasible_delay1,error_tolerance=0.05): debug.info(2,"Delay too big {0} vs {1}".format(delay1,feasible_delay1)) return False elif not ch.relative_compare(delay0,feasible_delay0,error_tolerance=0.05): debug.info(2,"Delay too big {0} vs {1}".format(delay0,feasible_delay0)) return False #key=raw_input("press return to continue") debug.info(2,"Successful period {0}, delay0={1}ns, delay1={2}ns slew0={3}ns slew1={4}ns".format(period, delay0, delay1, slew0, slew1)) return True
def try_period(self, period, load, slew, feasible_delay1, feasible_delay0): """ This tries to simulate a period and checks if the result works. If it does and the delay is within 5% still, it returns True.""" # Checking from not data_value to data_value self.write_stimulus(period,load,slew) stimuli.run_sim() delay0 = ch.convert_to_float(ch.parse_output("timing", "delay0")) delay1 = ch.convert_to_float(ch.parse_output("timing", "delay1")) if type(delay0)==float: delay0 *= 1e9 if type(delay1)==float: delay1 *= 1e9 debug.info(2,"Period {0}, delay0={1}ns, delay1={2}ns".format(period,delay0, delay1)) # if it failed or the read was longer than a period if type(delay0)!=float or type(delay1)!=float: return False else: if ch.relative_compare(delay1*1e9,feasible_delay1,error_tolerance=0.05): return False elif ch.relative_compare(delay0*1e9,feasible_delay0,error_tolerance=0.05): return False #key=raw_input("press return to continue") return True
def try_period(self, feasible_period, target_period, data_value): """ This tries to simulate a period and checks if the result works. If so, it returns True. If not, it it doubles the period and returns False.""" # Checking from not data_value to data_value self.write_stimulus(feasible_period, target_period, data_value) stimuli.run_sim() delay_value = ch.convert_to_float(ch.parse_output("timing", "delay")) # if it failed or the read was longer than a period if type(delay_value)!=float or delay_value*1e9>target_period: debug.info(2,"Infeasible period " + str(target_period) + " delay " + str(delay_value*1e9) + "ns") return (False, "NA") else: debug.info(2,"Feasible period " + str(feasible_period) \ + ", target period " + str(target_period) \ + ", read/write of " + str(data_value) \ + ", delay=" + str(delay_value*1e9) + "ns") #key=raw_input("press return to continue") return (True, delay_value*1e9)
def bidir_search(self, correct_value, mode): """ 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 depending on whether we are doing setup or hold. """ # NOTE: The feasible bound is always feasible. This is why they are different for setup and hold. # The clock will always be offset by 2*period from the start, so we want to look before and after # 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 else: 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) stimuli.run_sim() ideal_clk_to_q = ch.convert_to_float(ch.parse_output("timing", "clk2q_delay")) setuphold_time = ch.convert_to_float(ch.parse_output("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) 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, setuphold_time, feasible_bound, 2*self.period)) #raw_input("Press Enter to continue...") while True: 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)) stimuli.run_sim() clk_to_q = ch.convert_to_float(ch.parse_output("timing", "clk2q_delay")) setuphold_time = ch.convert_to_float(ch.parse_output("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 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)) 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)) infeasible_bound = target_time #raw_input("Press Enter to continue...") if ch.relative_compare(feasible_bound, infeasible_bound, error_tolerance=0.001): 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)) return passing_setuphold_time
def bidir_search(self, correct_value, noise_margin, measure_name, mode): """ 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 depending on whether we are doing setup or hold. """ period = tech.spice["feasible_period"] # The clock will start being offset by a period, so we want to look before and after # theis time. if mode == "HOLD": target_time = 1.5 * period lower_bound = 0.5 * period upper_bound = 1.5 * period else: target_time = 0.5 * period lower_bound = 0.5 * period upper_bound = 1.5 * period previous_time = target_time # Initial Check if reference setup time passes for correct_value self.write_stimulus(mode=mode, target_time=target_time, correct_value=correct_value, period=period, noise_margin=noise_margin) stimuli.run_sim() output_value = ch.convert_to_float( ch.parse_output("timing", measure_name)) debug.info( 3, "Correct: {0} Output: {1} NM: {2}".format(correct_value, output_value, noise_margin)) if mode == "HOLD": setuphold_time = target_time - period else: setuphold_time = period - target_time debug.info( 3, "Target time: {0} Low: {1} Up: {2} Measured: {3}".format( target_time, lower_bound, upper_bound, setuphold_time)) if not self.pass_fail_test(output_value, correct_value, noise_margin): debug.error("Initial period/target hold time fails for data value", 2) # We already found it feasible, so advance one step first thing. if mode == "HOLD": target_time -= 0.5 * (upper_bound - lower_bound) else: target_time += 0.5 * (upper_bound - lower_bound) while True: self.write_stimulus(mode=mode, target_time=target_time, correct_value=correct_value, period=period, noise_margin=noise_margin) if mode == "HOLD": setuphold_time = target_time - period else: setuphold_time = period - target_time debug.info( 3, "Target time: {0} Low: {1} Up: {2} Measured: {3}".format( target_time, lower_bound, upper_bound, setuphold_time)) stimuli.run_sim() output_value = ch.convert_to_float( ch.parse_output("timing", measure_name)) debug.info( 3, "Correct: {0} Output: {1} NM: {2}".format( correct_value, output_value, noise_margin)) if self.pass_fail_test(output_value, correct_value, noise_margin): debug.info(3, "PASS") if ch.relative_compare(target_time, previous_time): debug.info( 3, "CONVERGE " + str(target_time) + " " + str(previous_time)) break previous_time = target_time if mode == "HOLD": upper_bound = target_time target_time -= 0.5 * (upper_bound - lower_bound) else: lower_bound = target_time target_time += 0.5 * (upper_bound - lower_bound) else: debug.info(3, "FAIL") if mode == "HOLD": lower_bound = target_time target_time += 0.5 * (upper_bound - lower_bound) else: upper_bound = target_time target_time -= 0.5 * (upper_bound - lower_bound) #raw_input("Press Enter to continue...") # the clock starts offset by one clock period, # so we always measure our setup or hold relative to this time if mode == "HOLD": setuphold_time = target_time - period else: setuphold_time = period - target_time return setuphold_time