Exemplo n.º 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)
Exemplo n.º 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
Exemplo n.º 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"))
        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
Exemplo n.º 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"))
        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
Exemplo n.º 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
Exemplo n.º 6
0
    def try_period(self, feasible_delay_lh, feasible_delay_hl):
        """ 
        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_delay_stimulus()
        self.stim.run_sim()
        delay_hl = ch.parse_output("timing", "delay_hl")
        delay_lh = ch.parse_output("timing", "delay_lh")
        slew_hl = ch.parse_output("timing", "slew_hl")
        slew_lh = ch.parse_output("timing", "slew_lh")
        # if it failed or the read was longer than a period
        if type(delay_hl) != float or type(delay_lh) != float or type(
                slew_lh) != float or type(slew_hl) != float:
            debug.info(
                2,
                "Invalid measures: Period {0}, delay_hl={1}ns, delay_lh={2}ns slew_hl={3}ns slew_lh={4}ns"
                .format(self.period, delay_hl, delay_lh, slew_hl, slew_lh))
            return False
        delay_hl *= 1e9
        delay_lh *= 1e9
        slew_hl *= 1e9
        slew_lh *= 1e9
        if delay_hl > self.period or delay_lh > self.period or slew_hl > self.period or slew_lh > self.period:
            debug.info(
                2,
                "Too long delay/slew: Period {0}, delay_hl={1}ns, delay_lh={2}ns slew_hl={3}ns slew_lh={4}ns"
                .format(self.period, delay_hl, delay_lh, slew_hl, slew_lh))
            return False
        else:
            if not ch.relative_compare(
                    delay_lh, feasible_delay_lh, error_tolerance=0.05):
                debug.info(
                    2,
                    "Delay too big {0} vs {1}".format(delay_lh,
                                                      feasible_delay_lh))
                return False
            elif not ch.relative_compare(
                    delay_hl, feasible_delay_hl, error_tolerance=0.05):
                debug.info(
                    2,
                    "Delay too big {0} vs {1}".format(delay_hl,
                                                      feasible_delay_hl))
                return False

        #key=raw_input("press return to continue")

        debug.info(
            2,
            "Successful period {0}, delay_hl={1}ns, delay_lh={2}ns slew_hl={3}ns slew_lh={4}ns"
            .format(self.period, delay_hl, delay_lh, slew_hl, slew_lh))
        return True
Exemplo n.º 7
0
    def run_power_simulation(self):
        """ 
        This simulates a disabled SRAM to get the leakage power when it is off.
        
        """

        self.write_power_stimulus(trim=False)
        self.stim.run_sim()
        leakage_power = ch.parse_output("timing", "leakage_power")
        debug.check(leakage_power != "Failed",
                    "Could not measure leakage power.")

        self.write_power_stimulus(trim=True)
        self.stim.run_sim()
        trim_leakage_power = ch.parse_output("timing", "leakage_power")
        debug.check(trim_leakage_power != "Failed",
                    "Could not measure leakage power.")

        # For debug, you sometimes want to inspect each simulation.
        #key=raw_input("press return to continue")
        return (leakage_power * 1e3, trim_leakage_power * 1e3)
Exemplo n.º 8
0
    def run_delay_simulation(self):
        """
        This tries to simulate a period and checks if the result works. If
        so, it returns True and the delays, slews, and powers.  It
        works on the trimmed netlist by default, so powers do not
        include leakage of all cells.
        """

        # Checking from not data_value to data_value
        self.write_delay_stimulus()
        self.stim.run_sim()
        delay_hl = ch.parse_output("timing", "delay_hl")
        delay_lh = ch.parse_output("timing", "delay_lh")
        slew_hl = ch.parse_output("timing", "slew_hl")
        slew_lh = ch.parse_output("timing", "slew_lh")
        delays = (delay_hl, delay_lh, slew_hl, slew_lh)

        read0_power = ch.parse_output("timing", "read0_power")
        write0_power = ch.parse_output("timing", "write0_power")
        read1_power = ch.parse_output("timing", "read1_power")
        write1_power = ch.parse_output("timing", "write1_power")

        if not self.check_valid_delays(delays):
            return (False, {})

        # For debug, you sometimes want to inspect each simulation.
        #key=raw_input("press return to continue")

        # Scale results to ns and mw, respectively
        result = {
            "delay_hl": delay_hl * 1e9,
            "delay_lh": delay_lh * 1e9,
            "slew_hl": slew_hl * 1e9,
            "slew_lh": slew_lh * 1e9,
            "read0_power": read0_power * 1e3,
            "read1_power": read1_power * 1e3,
            "write0_power": write0_power * 1e3,
            "write1_power": write1_power * 1e3
        }

        # The delay is from the negative edge for our SRAM
        return (True, result)
Exemplo n.º 9
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)
Exemplo n.º 10
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
Exemplo n.º 11
0
    def run_sim(self, load, slew):
        """Run hsim & VCS in batch mode and output rawfile to parse."""

        self.dut_generator(self.addr_bit, self.data_bit, load, self.name,
                           self.w_per_row, self.num_rows)
        self.spice_deck(slew, load)
        self.verilog_testbench(self.addr_bit, self.data_bit)
        self.source_generator(self.addr_bit, self.data_bit,
                              tech.spice["inv_delay"], slew)
        self.cosim_config()

        self.make.write("\n")
        self.make.write("all:\n")
        self.make.write(
            "\tvcs -full64 +vpi -ad_hsim=cosim.cfg -load libvcshsim.so:cs_vpi_startup +cli+3 test.v\n"
        )
        self.make.write("\t./simv +nsda+cosim.cfg 2>&1 | tee -i simv.log\n")
        self.make.write("clean:\n")
        self.make.write("\trm -rf ucli.key\n")
        self.make.write("\trm -rf simv.log\n")
        self.make.write("\trm -rf simv.daidir\n")
        self.make.write("\trm -rf simv\n")
        self.make.write("\trm -rf nsda_cosim.sp\n")
        self.make.close()

        for myfile in [
                "cosim.cfg", "test.sp", "test.v", "source.v", "dut.sp",
                "Makefile"
        ]:
            filename = "{0}{1}".format(OPTS.AMC_temp, myfile)
            while not path.exists(filename):
                time.sleep(1)
            else:
                os.chmod(filename, 0o777)

        os.chdir(OPTS.AMC_temp)
        spice_stdout = open("{0}spice_stdout.log".format(OPTS.AMC_temp), 'w')
        spice_stderr = open("{0}spice_stderr.log".format(OPTS.AMC_temp), 'w')

        retcode = subprocess.call("make",
                                  shell=True,
                                  stdout=spice_stdout,
                                  stderr=spice_stderr)
        spice_stdout.close()
        spice_stderr.close()

        if (retcode > 1):
            debug.error("Spice simulation error: " + cmd, -1)

        filename = "{0}{1}".format(OPTS.AMC_temp, "hsim.mt")
        while not path.exists(filename):
            time.sleep(1)

        #Parse the hsim.mt file to repoert delay and power values.
        write_delay = charutils.parse_output("hsim", "write_delay")
        read_delay = charutils.parse_output("hsim", "read_delay")
        read_write_delay = charutils.parse_output("hsim", "read_write_delay")
        slew_hl = charutils.parse_output("hsim", "slew_hl")
        slew_lh = charutils.parse_output("hsim", "slew_lh")
        leakage_power = charutils.parse_output("hsim", "leakage_power")
        write_power = charutils.parse_output("hsim", "write_power")
        read_power = charutils.parse_output("hsim", "read_power")
        read_write_power = charutils.parse_output("hsim", "read_write_power")

        self.result = {
            "write_delay_lh": write_delay * (10**9),
            "write_delay_hl": write_delay * (10**9),
            "read_delay_lh": read_delay * (10**9),
            "read_delay_hl": read_delay * (10**9),
            "read_write_delay_lh": read_write_delay * (10**9),
            "read_write_delay_hl": read_write_delay * (10**9),
            "slew_hl": slew_hl * (10**9),
            "slew_lh": slew_lh * 1e9,
            "leakage_power": leakage_power * (10**3),
            "read_power": read_power * (10**3),
            "write_power": write_power * (10**3),
            "read_write_power": read_write_power * (10**3)
        }
        return self.result
Exemplo n.º 12
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