Include leakage of non-trimmed array. Back out leakage of trimmed, add back leakage of nontrimmed. Reorgs simulation of delay and power a bit.

This commit is contained in:
Matt Guthaus 2018-02-21 13:38:43 -08:00
parent 0aba4ee483
commit 7d2f4386e2
4 changed files with 272 additions and 132 deletions

View File

@ -27,7 +27,7 @@ def parse_output(filename, key):
if val != None: if val != None:
debug.info(4, "Key = " + key + " Val = " + val.group(1)) debug.info(4, "Key = " + key + " Val = " + val.group(1))
return val.group(1) return convert_to_float(val.group(1))
else: else:
return "Failed" return "Failed"

View File

@ -1,25 +1,39 @@
import sys import sys,re,shutil
import re
import debug import debug
import tech import tech
import math import math
import stimuli import stimuli
from trim_spice import trim_spice
import charutils as ch import charutils as ch
import utils import utils
from globals import OPTS from globals import OPTS
class delay(): class delay():
""" """Functions to measure the delay and power of an SRAM at a given address and
Functions to measure the delay of an SRAM at a given address and
data bit. data bit.
In general, this will perform the following actions:
1) Trim the netlist to remove unnecessary logic.
2) Find a feasible clock period using max load/slew on the trimmed netlist.
3) Characterize all loads/slews and consider fail when delay is greater than 5% of feasible delay using trimmed netlist.
4) Measure the leakage during the last cycle of the trimmed netlist when there is no operation.
5) Measure the leakage of the whole netlist (untrimmed) in each corner.
6) Subtract the trimmed leakage and add the untrimmed leakage to the power.
Netlist trimming can be removed by setting OPTS.trim_netlist to
False, but this is VERY slow.
""" """
def __init__(self,sram,spfile, corner): def __init__(self, sram, spfile, corner):
self.sram = sram
self.name = sram.name self.name = sram.name
self.num_words = sram.num_words self.word_size = self.sram.word_size
self.word_size = sram.word_size self.addr_size = self.sram.addr_size
self.addr_size = sram.addr_size self.num_cols = self.sram.num_cols
self.sram_sp_file = spfile self.num_rows = self.sram.num_rows
self.num_banks = self.sram.num_banks
self.sp_file = spfile
self.set_corner(corner) self.set_corner(corner)
@ -27,7 +41,6 @@ class delay():
""" Set the corner values """ """ Set the corner values """
self.corner = corner self.corner = corner
(self.process, self.vdd_voltage, self.temperature) = corner (self.process, self.vdd_voltage, self.temperature) = corner
self.gnd_voltage = 0
def check_arguments(self): def check_arguments(self):
@ -43,27 +56,10 @@ class delay():
if not isinstance(self.probe_data, int) or self.probe_data>self.word_size or self.probe_data<0: if not isinstance(self.probe_data, int) or self.probe_data>self.word_size or self.probe_data<0:
debug.error("Given probe_data is not an integer to specify a data bit",1) debug.error("Given probe_data is not an integer to specify a data bit",1)
def write_generic_stimulus(self, load):
def write_stimulus(self, period, load, slew): """ Create the instance, supplies, loads, and access transistors. """
""" 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()
# obtains list of time-points for each rising clk edge
self.obtain_cycle_times(period)
# 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}fF slew={2}ns\n\n".format(period,load,slew))
self.stim = stimuli.stimuli(self.sf, self.corner)
# include files in stimulus file
self.stim.write_include(self.sram_sp_file)
# add vdd/gnd statements # add vdd/gnd statements
self.sf.write("\n* Global Power Supplies\n") self.sf.write("\n* Global Power Supplies\n")
self.stim.write_supply() self.stim.write_supply()
@ -80,7 +76,28 @@ class delay():
# add access transistors for data-bus # add access transistors for data-bus
self.sf.write("\n* Transmission Gates for data-bus and control signals\n") self.sf.write("\n* Transmission Gates for data-bus and control signals\n")
self.stim.inst_accesstx(dbits=self.word_size) self.stim.inst_accesstx(dbits=self.word_size)
def write_delay_stimulus(self, period, load, slew):
""" 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()
# obtains list of time-points for each rising clk edge
self.obtain_cycle_times(period)
# 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("* Delay stimulus for period of {0}n load={1}fF slew={2}ns\n\n".format(period,load,slew))
self.stim = stimuli.stimuli(self.sf, self.corner)
# include files in stimulus file
self.stim.write_include(self.trim_sp_file)
self.write_generic_stimulus(load)
# generate data and addr signals # generate data and addr signals
self.sf.write("\n* Generation of data and address signals\n") self.sf.write("\n* Generation of data and address signals\n")
for i in range(self.word_size): for i in range(self.word_size):
@ -91,7 +108,7 @@ class delay():
slew=slew) slew=slew)
else: else:
self.stim.gen_constant(sig_name="d[{0}]".format(i), self.stim.gen_constant(sig_name="d[{0}]".format(i),
v_val=self.gnd_voltage) v_val=0)
self.gen_addr(clk_times=self.cycle_times, self.gen_addr(clk_times=self.cycle_times,
addr=self.probe_address, addr=self.probe_address,
@ -106,21 +123,70 @@ class delay():
self.sf.write("\n* Generation of global clock signal\n") self.sf.write("\n* Generation of global clock signal\n")
self.stim.gen_pulse(sig_name="CLK", self.stim.gen_pulse(sig_name="CLK",
v1=self.gnd_voltage, v1=0,
v2=self.vdd_voltage, v2=self.vdd_voltage,
offset=period, offset=period,
period=period, period=period,
t_rise=slew, t_rise=slew,
t_fall=slew) t_fall=slew)
self.write_measures(period) self.write_delay_measures(period)
# run until the end of the cycle time # run until the end of the cycle time
self.stim.write_control(self.cycle_times[-1] + period) self.stim.write_control(self.cycle_times[-1] + period)
self.sf.close() self.sf.close()
def write_measures(self,period):
def write_power_stimulus(self, period, load, trim):
""" Creates a stimulus file to measure leakage power only.
This works on the *untrimmed netlist*.
"""
self.check_arguments()
# obtains list of time-points for each rising clk edge
self.obtain_cycle_times(period)
# 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("* Power stimulus for period of {0}n\n\n".format(period))
self.stim = stimuli.stimuli(self.sf, self.corner)
# include UNTRIMMED files in stimulus file
if trim:
self.stim.write_include(self.trim_sp_file)
else:
self.stim.write_include(self.sim_sp_file)
self.write_generic_stimulus(load)
# generate data and addr signals
self.sf.write("\n* Generation of data and address signals\n")
for i in range(self.word_size):
self.stim.gen_constant(sig_name="d[{0}]".format(i),
v_val=0)
for i in range(self.addr_size):
self.stim.gen_constant(sig_name="A[{0}]".format(i),
v_val=0)
# generate control signals
self.sf.write("\n* Generation of control signals\n")
self.stim.gen_constant(sig_name="CSb", v_val=self.vdd_voltage)
self.stim.gen_constant(sig_name="WEb", v_val=self.vdd_voltage)
self.stim.gen_constant(sig_name="OEb", v_val=self.vdd_voltage)
self.sf.write("\n* Generation of global clock signal\n")
self.stim.gen_constant(sig_name="CLK", v_val=0)
self.write_power_measures(period)
# run until the end of the cycle time
self.stim.write_control(2*period)
self.sf.close()
def write_delay_measures(self,period):
""" """
Write the measure statements to quantify the delay and power results. Write the measure statements to quantify the delay and power results.
""" """
@ -202,6 +268,21 @@ class delay():
self.stim.gen_meas_power(meas_name="READ1_POWER", self.stim.gen_meas_power(meas_name="READ1_POWER",
t_initial=t_initial, t_initial=t_initial,
t_final=t_final) t_final=t_final)
def write_power_measures(self,period):
"""
Write the measure statements to quantify the leakage power only.
"""
self.sf.write("\n* Measure statements for idle leakage power\n")
# add measure statements for power
t_initial = period
t_final = 2*period
self.stim.gen_meas_power(meas_name="LEAKAGE_POWER",
t_initial=t_initial,
t_final=t_final)
def find_feasible_period(self, load, slew): def find_feasible_period(self, load, slew):
""" """
@ -221,7 +302,11 @@ class delay():
if (time_out <= 0): if (time_out <= 0):
debug.error("Timed out, could not find a feasible period.",2) debug.error("Timed out, could not find a feasible period.",2)
(success, feasible_delay1, feasible_slew1, feasible_delay0, feasible_slew0)=self.run_simulation(feasible_period,load,slew) (success, results)=self.run_delay_simulation(feasible_period,load,slew)
feasible_delay1 = results["delay1"]
feasible_slew1 = results["slew1"]
feasible_delay0 = results["delay0"]
feasible_slew0 = results["slew0"]
if not success: if not success:
feasible_period = 2 * feasible_period feasible_period = 2 * feasible_period
continue continue
@ -234,20 +319,72 @@ class delay():
return (feasible_period, feasible_delay1, feasible_delay0) return (feasible_period, feasible_delay1, feasible_delay0)
def run_simulation(self, period, load, slew): def run_delay_simulation(self, period, load, slew):
""" """
This tries to simulate a period and checks if the result This tries to simulate a period and checks if the result works. If
works. If so, it returns True and the delays and slews. 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 # Checking from not data_value to data_value
self.write_stimulus(period, load, slew) self.write_delay_stimulus(period, load, slew)
self.stim.run_sim() self.stim.run_sim()
delay0 = ch.convert_to_float(ch.parse_output("timing", "delay0")) delay0 = ch.parse_output("timing", "delay0")
delay1 = ch.convert_to_float(ch.parse_output("timing", "delay1")) delay1 = ch.parse_output("timing", "delay1")
slew0 = ch.convert_to_float(ch.parse_output("timing", "slew0")) slew0 = ch.parse_output("timing", "slew0")
slew1 = ch.convert_to_float(ch.parse_output("timing", "slew1")) slew1 = ch.parse_output("timing", "slew1")
delays = (delay0, delay1, slew0, slew1)
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(period, load, slew, 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 = { "delay0" : delay0*1e9,
"delay1" : delay1*1e9,
"slew0" : slew0*1e9,
"slew1" : slew1*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)
def run_power_simulation(self, period, load):
"""
This simulates a disabled SRAM to get the leakage power when it is off.
"""
self.write_power_stimulus(period, load, 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(period, load, 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)
def check_valid_delays(self, period, load, slew, (delay0, delay1, slew0, slew1)):
""" Check if the measurements are defined and if they are valid. """
# if it failed or the read was longer than a period # 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: if type(delay0)!=float or type(delay1)!=float or type(slew1)!=float or type(slew0)!=float:
debug.info(2,"Failed simulation: period {0} load {1} slew {2}, delay0={3}n delay1={4}ns slew0={5}n slew1={6}n".format(period, debug.info(2,"Failed simulation: period {0} load {1} slew {2}, delay0={3}n delay1={4}ns slew0={5}n slew1={6}n".format(period,
@ -257,7 +394,7 @@ class delay():
delay1, delay1,
slew0, slew0,
slew1)) slew1))
return (False,0,0,0,0) return False
# Scale delays to ns (they previously could have not been floats) # Scale delays to ns (they previously could have not been floats)
delay0 *= 1e9 delay0 *= 1e9
delay1 *= 1e9 delay1 *= 1e9
@ -271,7 +408,7 @@ class delay():
delay1, delay1,
slew0, slew0,
slew1)) slew1))
return (False,0,0,0,0) return False
else: 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, 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, load,
@ -280,13 +417,9 @@ class delay():
delay1, delay1,
slew0, slew0,
slew1)) slew1))
# For debug, you sometimes want to inspect each simulation.
#key=raw_input("press return to continue")
# The delay is from the negative edge for our SRAM
return (True,delay1,slew1,delay0,slew0)
return True
def find_min_period(self,feasible_period, load, slew, feasible_delay1, feasible_delay0): def find_min_period(self,feasible_period, load, slew, feasible_delay1, feasible_delay0):
""" """
@ -326,12 +459,12 @@ class delay():
""" """
# Checking from not data_value to data_value # Checking from not data_value to data_value
self.write_stimulus(period,load,slew) self.write_delay_stimulus(period,load,slew)
self.stim.run_sim() self.stim.run_sim()
delay0 = ch.convert_to_float(ch.parse_output("timing", "delay0")) delay0 = ch.parse_output("timing", "delay0")
delay1 = ch.convert_to_float(ch.parse_output("timing", "delay1")) delay1 = ch.parse_output("timing", "delay1")
slew0 = ch.convert_to_float(ch.parse_output("timing", "slew0")) slew0 = ch.parse_output("timing", "slew0")
slew1 = ch.convert_to_float(ch.parse_output("timing", "slew1")) slew1 = ch.parse_output("timing", "slew1")
# if it failed or the read was longer than a period # 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: 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, debug.info(2,"Invalid measures: Period {0}, delay0={1}ns, delay1={2}ns slew0={3}ns slew1={4}ns".format(period,
@ -375,12 +508,35 @@ class delay():
self.probe_address = probe_address self.probe_address = probe_address
self.probe_data = probe_data self.probe_data = probe_data
self.prepare_netlist()
def prepare_netlist(self):
""" Prepare a trimmed netlist and regular netlist. """
# Set up to trim the netlist here if that is enabled
if OPTS.trim_netlist:
self.trim_sp_file = "{}reduced.sp".format(OPTS.openram_temp)
self.trimsp=trim_spice(self.sp_file, self.trim_sp_file)
self.trimsp.set_configuration(self.num_banks,
self.num_rows,
self.num_cols,
self.word_size)
self.trimsp.trim(self.probe_address,self.probe_data)
else:
# The non-reduced netlist file when it is disabled
self.trim_sp_file = "{}sram.sp".format(OPTS.openram_temp)
# The non-reduced netlist file for power simulation
self.sim_sp_file = "{}sram.sp".format(OPTS.openram_temp)
# Make a copy in temp for debugging
shutil.copy(self.sp_file, self.sim_sp_file)
def analyze(self,probe_address, probe_data, slews, loads): 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 Main function to characterize an SRAM for a table. Computes both delay and power characterization.
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) self.set_probe(probe_address, probe_data)
@ -395,49 +551,53 @@ class delay():
# self.try_period(target_period, load, slew, feasible_delay1, feasible_delay0) # self.try_period(target_period, load, slew, feasible_delay1, feasible_delay0)
# sys.exit(1) # sys.exit(1)
# 1) Find a feasible period and it's corresponding delays using the trimmed array.
(feasible_period, feasible_delay1, feasible_delay0) = self.find_feasible_period(max(loads), max(slews)) (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_delay1>0,"Negative delay may not be possible")
debug.check(feasible_delay0>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 # 2) Measure the delay, slew and power for all slew/load pairs.
# which should have worked. # Make a list for each type of measurement to append results to
read0_power=ch.convert_to_float(ch.parse_output("timing", "read0_power")) char_data = {}
write0_power=ch.convert_to_float(ch.parse_output("timing", "write0_power")) for m in ["delay1", "delay0", "slew1", "slew0", "read0_power",
read1_power=ch.convert_to_float(ch.parse_output("timing", "read1_power")) "read1_power", "write0_power", "write1_power", "leakage_power"]:
write1_power=ch.convert_to_float(ch.parse_output("timing", "write1_power")) char_data[m]=[]
full_array_leakage = []
LH_delay = [] trim_array_leakage = []
HL_delay = [] for load in loads:
LH_slew = [] # 2a) Find the leakage power of the trimmmed and UNtrimmed arrays.
HL_slew = [] (full_leak, trim_leak)=self.run_power_simulation(feasible_period, load)
for slew in slews: full_array_leakage.append(full_leak)
for load in loads: trim_array_leakage.append(trim_leak)
(success, delay1, slew1, delay0, slew0) = self.run_simulation(feasible_period, load, slew) print full_leak,trim_leak
for slew in slews:
# 2c) Find the delay, dynamic power, and leakage power of the trimmed array.
(success, delay_results) = self.run_delay_simulation(feasible_period, load, slew)
debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(slew,load)) debug.check(success,"Couldn't run a simulation. slew={0} load={1}\n".format(slew,load))
LH_delay.append(delay1) print delay_results
HL_delay.append(delay0) for k,v in delay_results.items():
LH_slew.append(slew1) print k,v
HL_slew.append(slew0) if "power" in k:
# Subtract partial array leakage and add full array leakage for the power measures
# finds the minimum period without degrading the delays by X% char_data[k].append(v - trim_array_leakage[-1] + full_array_leakage[-1])
char_data["leakage_power"].append(full_array_leakage[-1])
else:
char_data[k].append(v)
# 3) 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) 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.check(type(min_period)==float,"Couldn't find minimum period.")
debug.info(1, "Min Period: {0}n with a delay of {1} / {2}".format(min_period, feasible_delay1, feasible_delay0)) debug.info(1, "Min Period: {0}n with a delay of {1} / {2}".format(min_period, feasible_delay1, feasible_delay0))
# 4) Pack up the final measurements
char_data["min_period"] = ch.round_time(min_period)
return char_data
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
def obtain_cycle_times(self, period): def obtain_cycle_times(self, period):
"""Returns a list of key time-points [ns] of the waveform (each rising edge) """Returns a list of key time-points [ns] of the waveform (each rising edge)
@ -496,6 +656,7 @@ class delay():
t_current, t_current,
msg)) msg))
self.cycle_times.append(t_current) self.cycle_times.append(t_current)
self.idle_cycle=len(self.cycle_times)-1
t_current += period t_current += period
# One period # One period
@ -534,7 +695,7 @@ class delay():
def analytical_model(self,sram, slews, loads): def analytical_delay(self,sram, slews, loads):
""" Just return the analytical model results for the SRAM. """ Just return the analytical model results for the SRAM.
""" """
LH_delay = [] LH_delay = []

View File

@ -1,4 +1,4 @@
import os,sys,re,shutil import os,sys,re
import debug import debug
import math import math
import setup_hold import setup_hold
@ -6,7 +6,6 @@ import delay
import charutils as ch import charutils as ch
import tech import tech
import numpy as np import numpy as np
from trim_spice import trim_spice
from globals import OPTS from globals import OPTS
class lib: class lib:
@ -18,30 +17,12 @@ class lib:
self.sp_file = sp_file self.sp_file = sp_file
self.use_model = use_model self.use_model = use_model
self.prepare_netlist()
self.prepare_tables() self.prepare_tables()
self.create_corners() self.create_corners()
self.characterize_corners() self.characterize_corners()
def prepare_netlist(self):
""" Determine whether to use regular or trimmed netlist. """
# Set up to trim the netlist here if that is enabled
if OPTS.trim_netlist:
self.sim_sp_file = "{}reduced.sp".format(OPTS.openram_temp)
self.trimsp=trim_spice(self.sp_file, self.sim_sp_file)
self.trimsp.set_configuration(self.sram.num_banks,
self.sram.num_rows,
self.sram.num_cols,
self.sram.word_size)
else:
# Else, use the non-reduced netlist file for simulation
self.sim_sp_file = "{}sram.sp".format(OPTS.openram_temp)
# Make a copy in temp for debugging
shutil.copy(self.sp_file, self.sim_sp_file)
def prepare_tables(self): def prepare_tables(self):
""" Determine the load/slews if they aren't specified in the config file. """ """ Determine the load/slews if they aren't specified in the config file. """
@ -319,10 +300,10 @@ class lib:
self.lib.write(" internal_power(){\n") self.lib.write(" internal_power(){\n")
self.lib.write(" when : \"OEb & !clk\"; \n") self.lib.write(" when : \"OEb & !clk\"; \n")
self.lib.write(" rise_power(scalar){\n") self.lib.write(" rise_power(scalar){\n")
self.lib.write(" values(\"{0}\");\n".format(self.delay["write1_power"])) self.lib.write(" values(\"{0}\");\n".format(np.mean(self.char_results["write1_power"])))
self.lib.write(" }\n") self.lib.write(" }\n")
self.lib.write(" fall_power(scalar){\n") self.lib.write(" fall_power(scalar){\n")
self.lib.write(" values(\"{0}\");\n".format(self.delay["write0_power"])) self.lib.write(" values(\"{0}\");\n".format(np.mean(self.char_results["write0_power"])))
self.lib.write(" }\n") self.lib.write(" }\n")
self.lib.write(" }\n") self.lib.write(" }\n")
@ -331,10 +312,10 @@ class lib:
self.lib.write(" internal_power(){\n") self.lib.write(" internal_power(){\n")
self.lib.write(" when : \"!OEb & !clk\"; \n") self.lib.write(" when : \"!OEb & !clk\"; \n")
self.lib.write(" rise_power(scalar){\n") self.lib.write(" rise_power(scalar){\n")
self.lib.write(" values(\"{0}\");\n".format(self.delay["read1_power"])) self.lib.write(" values(\"{0}\");\n".format(np.mean(self.char_results["read1_power"])))
self.lib.write(" }\n") self.lib.write(" }\n")
self.lib.write(" fall_power(scalar){\n") self.lib.write(" fall_power(scalar){\n")
self.lib.write(" values(\"{0}\");\n".format(self.delay["read0_power"])) self.lib.write(" values(\"{0}\");\n".format(np.mean(self.char_results["read0_power"])))
self.lib.write(" }\n") self.lib.write(" }\n")
self.lib.write(" }\n") self.lib.write(" }\n")
self.lib.write(" timing(){ \n") self.lib.write(" timing(){ \n")
@ -342,19 +323,19 @@ class lib:
self.lib.write(" related_pin : \"clk\"; \n") self.lib.write(" related_pin : \"clk\"; \n")
self.lib.write(" timing_type : falling_edge; \n") self.lib.write(" timing_type : falling_edge; \n")
self.lib.write(" cell_rise(CELL_TABLE) {\n") self.lib.write(" cell_rise(CELL_TABLE) {\n")
rounded_values = map(ch.round_time,self.delay["delay1"]) rounded_values = map(ch.round_time,self.char_results["delay1"])
self.write_values(rounded_values,len(self.loads)," ") self.write_values(rounded_values,len(self.loads)," ")
self.lib.write(" }\n") self.lib.write(" }\n")
self.lib.write(" cell_fall(CELL_TABLE) {\n") self.lib.write(" cell_fall(CELL_TABLE) {\n")
rounded_values = map(ch.round_time,self.delay["delay0"]) rounded_values = map(ch.round_time,self.char_results["delay0"])
self.write_values(rounded_values,len(self.loads)," ") self.write_values(rounded_values,len(self.loads)," ")
self.lib.write(" }\n") self.lib.write(" }\n")
self.lib.write(" rise_transition(CELL_TABLE) {\n") self.lib.write(" rise_transition(CELL_TABLE) {\n")
rounded_values = map(ch.round_time,self.delay["slew1"]) rounded_values = map(ch.round_time,self.char_results["slew1"])
self.write_values(rounded_values,len(self.loads)," ") self.write_values(rounded_values,len(self.loads)," ")
self.lib.write(" }\n") self.lib.write(" }\n")
self.lib.write(" fall_transition(CELL_TABLE) {\n") self.lib.write(" fall_transition(CELL_TABLE) {\n")
rounded_values = map(ch.round_time,self.delay["slew0"]) rounded_values = map(ch.round_time,self.char_results["slew0"])
self.write_values(rounded_values,len(self.loads)," ") self.write_values(rounded_values,len(self.loads)," ")
self.lib.write(" }\n") self.lib.write(" }\n")
self.lib.write(" }\n") self.lib.write(" }\n")
@ -401,8 +382,8 @@ class lib:
self.lib.write(" clock : true;\n") self.lib.write(" clock : true;\n")
self.lib.write(" direction : input; \n") self.lib.write(" direction : input; \n")
self.lib.write(" capacitance : {0}; \n".format(tech.spice["msflop_in_cap"])) self.lib.write(" capacitance : {0}; \n".format(tech.spice["msflop_in_cap"]))
min_pulse_width = ch.round_time(self.delay["min_period"])/2.0 min_pulse_width = ch.round_time(self.char_results["min_period"])/2.0
min_period = ch.round_time(self.delay["min_period"]) min_period = ch.round_time(self.char_results["min_period"])
self.lib.write(" timing(){ \n") self.lib.write(" timing(){ \n")
self.lib.write(" timing_type :\"min_pulse_width\"; \n") self.lib.write(" timing_type :\"min_pulse_width\"; \n")
self.lib.write(" related_pin : clk; \n") self.lib.write(" related_pin : clk; \n")
@ -432,16 +413,14 @@ class lib:
try: try:
self.d self.d
except AttributeError: except AttributeError:
self.d = delay.delay(self.sram, self.sim_sp_file, self.corner) self.d = delay.delay(self.sram, self.sp_file, self.corner)
if self.use_model: if self.use_model:
self.delay = self.d.analytical_model(self.sram,self.slews,self.loads) self.char_results = self.d.analytical_delay(self.sram,self.slews,self.loads)
else: else:
probe_address = "1" * self.sram.addr_size probe_address = "1" * self.sram.addr_size
probe_data = self.sram.word_size - 1 probe_data = self.sram.word_size - 1
# We must trim based on a specific address and data bit self.char_results = self.d.analyze(probe_address, probe_data, self.slews, self.loads)
if OPTS.trim_netlist:
self.trimsp.trim(probe_address,probe_data)
self.delay = self.d.analyze(probe_address, probe_data, self.slews, self.loads)
def compute_setup_hold(self): def compute_setup_hold(self):
""" Do the analysis if we haven't characterized a FF yet """ """ Do the analysis if we haven't characterized a FF yet """
@ -451,7 +430,7 @@ class lib:
except AttributeError: except AttributeError:
self.sh = setup_hold.setup_hold(self.corner) self.sh = setup_hold.setup_hold(self.corner)
if self.use_model: if self.use_model:
self.times = self.sh.analytical_model(self.slews,self.loads) self.times = self.sh.analytical_setuphold(self.slews,self.loads)
else: else:
self.times = self.sh.analyze(self.slews,self.slews) self.times = self.sh.analyze(self.slews,self.slews)

View File

@ -299,7 +299,7 @@ class setup_hold():
} }
return times return times
def analytical_model(self,related_slews, constrained_slews): def analytical_setuphold(self,related_slews, constrained_slews):
""" Just return the fixed setup/hold times from the technology. """ Just return the fixed setup/hold times from the technology.
""" """
LH_setup = [] LH_setup = []