Beispiel #1
0
    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)
Beispiel #2
0
    def analyze(self, probe_address, probe_data, slews, loads):
        """main function to calculate the min period for a low_to_high
        transistion and a high_to_low transistion returns a dictionary
        that contains all both the min period and associated delays
        Dictionary Keys: min_period1, delay1, min_period0, delay0
        """

        self.set_probe(probe_address, probe_data)

        (feasible_period, feasible_delay1,
         feasible_delay0) = self.find_feasible_period(max(loads), max(slews))
        debug.check(feasible_delay1 > 0, "Negative delay may not be possible")
        debug.check(feasible_delay0 > 0, "Negative delay may not be possible")

        # The power variables are just scalars. These use the final feasible period simulation
        # which should have worked.
        read0_power = ch.convert_to_float(
            ch.parse_output("timing", "read0_power"))
        write0_power = ch.convert_to_float(
            ch.parse_output("timing", "write0_power"))
        read1_power = ch.convert_to_float(
            ch.parse_output("timing", "read1_power"))
        write1_power = ch.convert_to_float(
            ch.parse_output("timing", "write1_power"))

        LH_delay = []
        HL_delay = []
        LH_slew = []
        HL_slew = []
        for slew in slews:
            for load in loads:
                (success, delay1, slew1, delay0,
                 slew0) = self.run_simulation(feasible_period, load, slew)
                debug.check(success, "Couldn't run a simulation properly.\n")
                LH_delay.append(delay1)
                HL_delay.append(delay0)
                LH_slew.append(slew1)
                HL_slew.append(slew0)

        # finds the minimum period without degrading the delays by X%
        min_period = self.find_min_period(feasible_period, max(loads),
                                          max(slews), feasible_delay1,
                                          feasible_delay0)
        debug.check(type(min_period) == float, "Couldn't find minimum period.")
        debug.info(
            1, "Min Period: {0}n with a delay of {1}".format(
                min_period, feasible_delay1))

        data = {
            "min_period": ch.round_time(min_period),
            "delay1": LH_delay,
            "delay0": HL_delay,
            "slew1": LH_slew,
            "slew0": HL_slew,
            "read0_power": read0_power * 1e3,
            "read1_power": read1_power * 1e3,
            "write0_power": write0_power * 1e3,
            "write1_power": write1_power * 1e3
        }
        return data
Beispiel #3
0
    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
Beispiel #4
0
    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
Beispiel #5
0
    def analyze(self,probe_address, probe_data):
        """main function to calculate the min period for a low_to_high
        transistion and a high_to_low transistion returns a dictionary
        that contains all both the min period and associated delays
        Dictionary Keys: min_period1, delay1, min_period0, delay0
        """
        self.set_probe(probe_address, probe_data)

        (min_period1, delay1) = self.find_min_period(tech.spice["supply_voltage"])
        if (min_period1 == None) or (delay1 == None):
            return None
        debug.info(1, "Min Period for low_to_high transistion: {0}n with a delay of {1}".format(min_period1, delay1))
        (min_period0, delay0) = self.find_min_period(tech.spice["gnd_voltage"])
        if (min_period0 == None) or (delay0 == None):
            return None
        debug.info(1, "Min Period for high_to_low transistion: {0}n with a delay of {1}".format(min_period0, delay0))
        read_power=ch.convert_to_float(ch.parse_output("timing", "power_read"))
	write_power=ch.convert_to_float(ch.parse_output("timing", "power_write"))

	data = {"min_period1": min_period1,  # period in ns
                "delay1": delay1, # delay in s
                "min_period0": min_period0,
                "delay0": delay0,
                "read_power": read_power,
                "write_power": write_power
                }
	return data
Beispiel #6
0
    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)
Beispiel #7
0
    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
Beispiel #8
0
    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