Improved characterizer.

This commit is contained in:
Matt Guthaus 2017-07-06 08:42:25 -07:00
parent e92cb9ecef
commit 20d8c0bc45
40 changed files with 1511 additions and 1626 deletions

View File

@ -214,11 +214,6 @@ class bank(design.design):
word_size=self.word_size)
self.add_mod(self.msf_data_in)
self.msf_data_out = self.mod_ms_flop_array(name="msf_data_out",
columns=self.num_cols,
word_size=self.word_size)
self.add_mod(self.msf_data_out)
self.tri_gate_array = self.mod_tri_gate_array(columns=self.num_cols,
word_size=self.word_size)
self.add_mod(self.tri_gate_array)
@ -747,7 +742,7 @@ class bank(design.design):
""" Routing of sense amp output to tri_gate input """
for i in range(self.word_size):
# Connection of data_out of sense amp to data_ in of msf_data_out
tri_gate_in_position = (self.tri_gate_array.tri_in_positions[i].scale(1,-1)
tri_gate_in_position = (self.tri_gate_array.in_positions[i].scale(1,-1)
+ self.tri_gate_array_offset)
sa_data_out_position = (self.sens_amp_array_position
+ self.sens_amp_array.Data_out_positions[i])
@ -773,7 +768,7 @@ class bank(design.design):
def route_tri_gate_out(self):
""" Metal 3 routing of tri_gate output data """
for i in range(self.word_size):
tri_gate_out_position = (self.tri_gate_array.DATA_positions[i].scale(1,-1)
tri_gate_out_position = (self.tri_gate_array.out_positions[i].scale(1,-1)
+ self.tri_gate_array_offset)
data_line_position = [tri_gate_out_position.x - 0.5 * drc["minwidth_metal3"],
self.min_point]
@ -1511,24 +1506,21 @@ class bank(design.design):
y_offset],
mirror="R90")
def delay(self, slope):
def delay(self, slew, load):
""" return analytical delay of the bank"""
msf_addr_delay = self.msf_address.delay(slope,
self.decoder.input_load())
msf_addr_delay = self.msf_address.delay(slew, self.decoder.input_load())
decoder_delay = self.decoder.delay(msf_addr_delay.slope,
self.wordline_driver.input_load())
decoder_delay = self.decoder.delay(msf_addr_delay.slew, self.wordline_driver.input_load())
word_driver_delay = self.wordline_driver.delay(decoder_delay.slope,
self.bitcell_array.input_load())
word_driver_delay = self.wordline_driver.delay(decoder_delay.slew, self.bitcell_array.input_load())
bitcell_array_delay = self.bitcell_array.delay(word_driver_delay.slope)
bitcell_array_delay = self.bitcell_array.delay(word_driver_delay.slew)
bl_t_data_out_delay = self.sens_amp_array.delay(bitcell_array_delay.slope,
bl_t_data_out_delay = self.sens_amp_array.delay(bitcell_array_delay.slew,
self.bitcell_array.output_load())
# output load of bitcell_array is set to be only small part of bl for sense amp.
data_t_DATA_delay = self.tri_gate_array.delay(bl_t_data_out_delay.slope)
data_t_DATA_delay = self.tri_gate_array.delay(bl_t_data_out_delay.slew, load)
result = msf_addr_delay + decoder_delay + word_driver_delay \
+ bitcell_array_delay + bl_t_data_out_delay + data_t_DATA_delay

View File

@ -21,14 +21,14 @@ class bitcell(design.design):
self.width = bitcell.chars["width"]
self.height = bitcell.chars["height"]
def delay(self, slope, load=0, swing = 0.5):
def delay(self, slew, load=0, swing = 0.5):
# delay of bit cell is not like a driver(from WL)
# so the slope used should be 0
# it should not be slope dependent?
# so the slew used should be 0
# it should not be slew dependent?
# because the value is there
# the delay is only over half transsmission gate
from tech import spice
r = spice["min_tx_r"]*3
c_para = spice["min_tx_c_para"]#ff
result = self.cal_delay_with_rc(r = r, c = c_para+load, slope = slope, swing = swing)
c_para = spice["min_tx_drain_c"]
result = self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew, swing = swing)
return result

View File

@ -143,26 +143,22 @@ class bitcell_array(design.design):
# increments to the next column width
offset.x += self.cell.width
def delay(self, slope, load=0):
def delay(self, slew, load=0):
from tech import drc
wl_wire = self.gen_wl_wire()
wl_wire.return_delay_over_wire(slope)
wl_wire.return_delay_over_wire(slew)
wl_to_cell_delay = wl_wire.return_delay_over_wire(slope)
wl_to_cell_delay = wl_wire.return_delay_over_wire(slew)
# hypothetical delay from cell to bl end without sense amp
bl_wire = self.gen_bl_wire()
cell_load = 2 * bl_wire.return_input_cap() # we ingore the wire r
# hence just use the whole c
bl_swing = 0.1
cell_delay = self.cell.delay(wl_to_cell_delay.slope, cell_load, swing = bl_swing)
cell_delay = self.cell.delay(wl_to_cell_delay.slew, cell_load, swing = bl_swing)
#we do not consider the delay over the wire for now
#bl_wire_delay = bl_wire.return_delay_over_wire(cell_delay.slope, swing = bl_swing)
#return [wl_to_cell_delay, cell_delay, bl_wire_delay]
#return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay+bl_wire_delay.delay,
# bl_wire_delay.slope)
return self.return_delay(cell_delay.delay+wl_to_cell_delay.delay,
wl_to_cell_delay.slope)
wl_to_cell_delay.slew)
def gen_wl_wire(self):
wl_wire = self.generate_rc_net(int(self.column_size), self.width, drc["minwidth_metal1"])
@ -172,7 +168,7 @@ class bitcell_array(design.design):
def gen_bl_wire(self):
bl_pos = 0
bl_wire = self.generate_rc_net(int(self.row_size-bl_pos), self.height, drc["minwidth_metal1"])
bl_wire.wire_c =spice["min_tx_c_para"] + bl_wire.wire_c # 1 access tx d/s per cell
bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
return bl_wire
def output_load(self, bl_pos=0):

View File

@ -4,23 +4,8 @@ import debug
OPTS = globals.get_opts()
# 0.1% is the relative tolerance for convergence
error_tolerance = 0.001
# times are in ns, so this is how many digits of precision
# 3 digits = 1ps
# 4 digits = 0.1ps
# etc.
time_precision = 3
# voltages are in volts
# 3 digits = 1mv
# 4 digits = 0.1mv
# 5 digits = 0.01mv
# 6 digits = 1uv
# etc
voltage_precision = 5
def relative_compare(value1,value2):
def relative_compare(value1,value2,error_tolerance=0.001):
""" This is used to compare relative values for convergence. """
return (abs(value1 - value2) / max(value1,value2) <= error_tolerance)
@ -40,10 +25,20 @@ def parse_output(filename, key):
else:
return "Failed"
def round_time(time):
def round_time(time,time_precision=3):
# times are in ns, so this is how many digits of precision
# 3 digits = 1ps
# 4 digits = 0.1ps
# etc.
return round(time,time_precision)
def round_voltage(voltage):
def round_voltage(voltage,voltag_precision=5):
# voltages are in volts
# 3 digits = 1mv
# 4 digits = 0.1mv
# 5 digits = 0.01mv
# 6 digits = 1uv
# etc
return round(voltage,voltage_precision)
def convert_to_float(number):

View File

@ -22,7 +22,9 @@ class delay():
self.word_size = sram.word_size
self.addr_size = sram.addr_size
self.sram_sp_file = spfile
self.vdd = tech.spice["supply_voltage"]
self.gnd = tech.spice["gnd_voltage"]
def check_arguments(self):
"""Checks if arguments given for write_stimulus() meets requirements"""
@ -38,7 +40,7 @@ class delay():
debug.error("Given probe_data is not an integer to specify a data bit",1)
def write_stimulus(self, feasible_period, target_period, data_value):
def write_stimulus(self, period, load, slew):
"""Creates a stimulus file for simulations to probe a certain bitcell, given an address and data-position of the data-word
(probe-address form: '111010000' LSB=0, MSB=1)
(probe_data form: number corresponding to the bit position of data-bus, begins with position 0)
@ -46,28 +48,21 @@ class delay():
self.check_arguments()
# obtains list of time-points for each rising clk edge
self.obtain_cycle_times(slow_period=feasible_period,
fast_period=target_period)
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 data value of {0} for target period of {1}n\n".format(data_value, target_period))
self.sf.write("\n")
self.sf.write("* Stimulus for period of {0}n load={1} slew={2}\n\n".format(period,load,slew))
# include files in stimulus file
model_list = tech.spice["fet_models"] + [self.sram_sp_file]
stimuli.write_include(stim_file=self.sf, models=model_list)
self.sf.write("\n")
# add vdd/gnd statements
self.sf.write("* Global Power Supplies\n")
stimuli.write_supply(stim_file=self.sf,
vdd_name=tech.spice["vdd_name"],
gnd_name=tech.spice["gnd_name"],
vdd_voltage=tech.spice["supply_voltage"],
gnd_voltage=tech.spice["gnd_voltage"])
self.sf.write("\n")
stimuli.write_supply(self.sf)
# instantiate the sram
self.sf.write("* Instantiation of the SRAM\n")
@ -75,210 +70,144 @@ class delay():
abits=self.addr_size,
dbits=self.word_size,
sram_name=self.name)
self.sf.write("\n")
# create a buffer and an inverter
self.sf.write("* Buffers and inverter Initialization\n")
# FIXME: We should replace the clock buffer with the same
# 2x buffer for control signals. This needs the buffer to be
# added to the control logic though.
stimuli.create_buffer(stim_file=self.sf,
buffer_name="clk1_buffer",
size=[1, 4])
self.sf.write("\n")
stimuli.create_buffer(stim_file=self.sf,
buffer_name="clk2_buffer",
size=[8, 16])
self.sf.write("\n")
stimuli.create_buffer(stim_file=self.sf,
buffer_name="buffer",
size=[1, 2])
self.sf.write("\n")
stimuli.create_inverter(stim_file=self.sf)
self.sf.write("\n")
# add a buffer for each signal and an inverter for WEb
signal_list = []
self.sf.write("* SRAM output loads\n")
for i in range(self.word_size):
signal_list.append("D[{0}]".format(i))
for j in range(self.addr_size):
signal_list.append("A[{0}]".format(j))
for k in tech.spice["control_signals"]:
signal_list.append(k)
self.sf.write("*Buffers for each generated signal and Inv for WEb\n")
stimuli.add_buffer(stim_file=self.sf,
buffer_name="buffer",
signal_list=signal_list)
stimuli.add_buffer(stim_file=self.sf,
buffer_name="clk1_buffer",
signal_list=["clk"])
stimuli.add_buffer(stim_file=self.sf,
buffer_name="clk2_buffer",
signal_list=["clk_buf"])
stimuli.add_buffer(stim_file=self.sf,
buffer_name="buffer",
signal_list=["WEb_trans"])
stimuli.add_inverter(stim_file=self.sf,
signal_list=["WEb_trans"])
self.sf.write("\n")
self.sf.write("CD{0} D[{0}] 0 {1}f\n".format(i,load))
# add access transistors for data-bus
self.sf.write("* Transmission Gates for data-bus\n")
stimuli.add_accesstx(stim_file=self.sf, dbits=self.word_size)
self.sf.write("\n")
self.sf.write("* Transmission Gates for data-bus and control signals\n")
stimuli.inst_accesstx(stim_file=self.sf, dbits=self.word_size)
# generate data and addr signals
self.sf.write("*Generation of data and address signals\n")
if data_value == tech.spice["supply_voltage"]:
v_val = tech.spice["gnd_voltage"]
else:
v_val = tech.spice["supply_voltage"]
self.sf.write("* Generation of data and address signals\n")
for i in range(self.word_size):
if i == self.probe_data:
stimuli.gen_data_pwl(stim_file=self.sf,
key_times=self.cycle_times,
sig_name="D[{0}]".format(i),
data_value=data_value,
feasible_period=feasible_period,
target_period=target_period,
t_rise=tech.spice["rise_time"],
t_fall=tech.spice["fall_time"])
stimuli.gen_data(stim_file=self.sf,
clk_times=self.cycle_times,
sig_name="DATA[{0}]".format(i),
period=period,
slew=slew)
else:
stimuli.gen_constant(stim_file=self.sf,
sig_name="D[{0}]".format(i),
v_ref=tech.spice["gnd_voltage"],
v_val=v_val)
v_val=self.gnd)
stimuli.gen_addr_pwl(stim_file=self.sf,
key_times=self.cycle_times,
addr=self.probe_address,
feasible_period=feasible_period,
target_period=target_period,
t_rise=tech.spice["rise_time"],
t_fall=tech.spice["fall_time"])
self.sf.write("\n")
stimuli.gen_addr(self.sf,
clk_times=self.cycle_times,
addr=self.probe_address,
period=period,
slew=slew)
# generate control signals
self.sf.write("*Generation of control signals\n")
# CSb
(x_list, y_list) = stimuli.gen_csb_pwl(key_times=self.cycle_times,
feasible_period=feasible_period,
target_period=target_period,
t_rise=tech.spice["rise_time"],
t_fall=tech.spice["fall_time"])
stimuli.gen_pwl(stim_file=self.sf,
sig_name="CSb",
x_list=x_list,
y_list=y_list)
# WEb
(x_list, y_list) = stimuli.gen_web_pwl(key_times=self.cycle_times,
feasible_period=feasible_period,
target_period=target_period,
t_rise=tech.spice["rise_time"],
t_fall=tech.spice["fall_time"])
stimuli.gen_pwl(stim_file=self.sf,
sig_name="WEb",
x_list=x_list,
y_list=y_list)
# OEb
(x_list, y_list) = stimuli.gen_oeb_pwl(key_times=self.cycle_times,
feasible_period=feasible_period,
target_period=target_period,
t_rise=tech.spice["rise_time"],
t_fall=tech.spice["fall_time"])
stimuli.gen_pwl(stim_file=self.sf,
sig_name="OEb",
x_list=x_list,
y_list=y_list)
# WEb_transmission_gate
(x_list, y_list) = stimuli.gen_web_trans_pwl(key_times=self.cycle_times,
feasible_period=feasible_period,
target_period=target_period,
t_rise=tech.spice["rise_time"],
t_fall=tech.spice["fall_time"])
stimuli.gen_pwl(stim_file=self.sf,
sig_name="WEb_trans",
x_list=x_list,
y_list=y_list)
self.sf.write("\n")
self.sf.write("* Generation of control signals\n")
stimuli.gen_csb(self.sf, self.cycle_times, period, slew)
stimuli.gen_web(self.sf, self.cycle_times, period, slew)
stimuli.gen_oeb(self.sf, self.cycle_times, period, slew)
self.write_clock()
self.sf.write("* Generation of global clock signal\n")
stimuli.gen_pulse(stim_file=self.sf,
sig_name="CLK",
v1=self.gnd,
v2=self.vdd,
offset=period,
period=period,
t_rise = slew,
t_fall = slew)
self.write_measures(period)
self.write_measures(data_value)
self.write_control()
# run until the last cycle time
stimuli.write_control(self.sf,self.cycle_times[-1])
self.sf.close()
def write_clock(self):
# generate clk PWL based on the clock periods
self.sf.write("* Generation of global clock signal\n")
stimuli.gen_clk_pwl(stim_file=self.sf,
cycle_times=self.cycle_times,
t_rise=tech.spice["rise_time"],
t_fall=tech.spice["fall_time"])
self.sf.write("\n")
def write_measures(self, data_value):
def write_measures(self,period):
# meas statement for delay and power measurements
self.sf.write("* Measure statements for delay and power\n")
# add measure statments for delay
trig_name = tech.spice["clk"] + "_buf_buf"
targ_name = "{0}".format("DATA[{0}]".format(self.probe_data))
trig_val = targ_val = 0.5 * tech.spice["supply_voltage"]
trig_dir = self.read_cycle
targ_dir = "RISE" if data_value == tech.spice["supply_voltage"] else "FALL"
td = self.cycle_times[self.clear_bus_cycle]
trig_name = "clk"
targ_name = "{0}".format("D[{0}]".format(self.probe_data))
trig_val = targ_val = 0.5 * self.vdd
# add measure statments for delay0
# delay the target to measure after the negetive edge
stimuli.gen_meas_delay(stim_file=self.sf,
meas_name="DELAY",
meas_name="DELAY0",
trig_name=trig_name,
targ_name=targ_name,
trig_val=trig_val,
targ_val=targ_val,
trig_dir=trig_dir,
targ_dir=targ_dir,
td=td)
trig_dir="FALL",
targ_dir="FALL",
td=self.cycle_times[self.read0_cycle]+0.5*period)
stimuli.gen_meas_delay(stim_file=self.sf,
meas_name="DELAY1",
trig_name=trig_name,
targ_name=targ_name,
trig_val=trig_val,
targ_val=targ_val,
trig_dir="FALL",
targ_dir="RISE",
td=self.cycle_times[self.read1_cycle]+0.5*period)
stimuli.gen_meas_delay(stim_file=self.sf,
meas_name="SLEW0",
trig_name=targ_name,
targ_name=targ_name,
trig_val=0.9*self.vdd,
targ_val=0.1*self.vdd,
trig_dir="FALL",
targ_dir="FALL",
td=self.cycle_times[self.read0_cycle]+0.5*period)
stimuli.gen_meas_delay(stim_file=self.sf,
meas_name="SLEW1",
trig_name=targ_name,
targ_name=targ_name,
trig_val=0.1*self.vdd,
targ_val=0.9*self.vdd,
trig_dir="RISE",
targ_dir="RISE",
td=self.cycle_times[self.read1_cycle]+0.5*period)
# add measure statements for power
t_initial = self.cycle_times[self.write_cycle]
t_final = self.cycle_times[self.write_cycle+1]
t_initial = self.cycle_times[self.write0_cycle]
t_final = self.cycle_times[self.write0_cycle+1]
stimuli.gen_meas_power(stim_file=self.sf,
meas_name="POWER_WRITE",
meas_name="WRITE0_POWER",
t_initial=t_initial,
t_final=t_final)
t_initial = self.cycle_times[self.read_cycle]
t_final = self.cycle_times[self.read_cycle+1]
t_initial = self.cycle_times[self.write1_cycle]
t_final = self.cycle_times[self.write1_cycle+1]
stimuli.gen_meas_power(stim_file=self.sf,
meas_name="POWER_READ",
meas_name="WRITE1_POWER",
t_initial=t_initial,
t_final=t_final)
t_initial = self.cycle_times[self.read0_cycle]
t_final = self.cycle_times[self.read0_cycle+1]
stimuli.gen_meas_power(stim_file=self.sf,
meas_name="READ0_POWER",
t_initial=t_initial,
t_final=t_final)
self.sf.write("\n")
def write_control(self):
# run until the last cycle time
end_time = self.cycle_times[-1]
self.sf.write(".TRAN 5p {0}n\n".format(end_time))
self.sf.write(".OPTIONS POST=1 PROBE\n")
# create plots for all signals
self.sf.write(".probe V(*)\n")
# end the stimulus file
self.sf.write(".end\n")
def find_feasible_period(self,initial_period):
t_initial = self.cycle_times[self.read1_cycle]
t_final = self.cycle_times[self.read1_cycle+1]
stimuli.gen_meas_power(stim_file=self.sf,
meas_name="READ1_POWER",
t_initial=t_initial,
t_final=t_final)
def find_feasible_period(self, load, slew):
"""Uses an initial period and finds a feasible period before we
run the binary search algorithm to find min period. We check if
the given clock period is valid and if it's not, we continue to
double the period until we find a valid period to use as a
starting point. """
feasible_period = initial_period
feasible_period = tech.spice["feasible_period"]
time_out = 8
while True:
debug.info(1, "Finding feasible period: {0}ns".format(feasible_period))
@ -287,52 +216,47 @@ class delay():
if (time_out <= 0):
debug.error("Timed out, could not find a feasible period.",2)
(success, delay_out)=self.try_period(feasible_period,feasible_period,tech.spice["supply_voltage"])
(success, feasible_delay1, feasible_slew1, feasible_delay0, feasible_slew0)=self.run_simulation(feasible_period,load,slew)
if not success:
feasible_period = 2 * feasible_period
continue
(success, delay_out)=self.try_period(feasible_period,feasible_period,tech.spice["gnd_voltage"])
if not success:
feasible_period = 2 * feasible_period
continue
debug.info(1, "Starting Binary Search Algorithm with feasible_period: {0}ns".format(feasible_period))
return feasible_period
debug.info(1, "Found feasible_period: {0}ns feasible_delay1/0 {1}ns/{2}ns".format(feasible_period,feasible_delay1,feasible_delay0))
return (feasible_period, feasible_delay1, feasible_delay0)
def try_period(self, feasible_period, target_period, data_value):
def run_simulation(self, period, load, slew):
""" 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."""
works. If so, it returns True and the delays and slews."""
# Checking from not data_value to data_value
self.write_stimulus(feasible_period, target_period, data_value)
self.write_stimulus(period, load, slew)
stimuli.run_sim()
delay_value = ch.convert_to_float(ch.parse_output("timing", "delay"))
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(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")
if type(delay0)!=float or type(delay1)!=float or type(slew1)!=float or type(slew0)!=float:
return (False,0,0,0,0)
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")
delay0 *= 1e9
delay1 *= 1e9
slew0 *= 1e9
slew1 *= 1e9
debug.info(2,"Simulation w/ period {0}, delay0={1}n delay1={2}ns".format(period,delay0,delay1))
#key=raw_input("press return to continue")
return (True, delay_value*1e9)
# The delay is from the negative edge for our SRAM
return (True,delay1,slew1,delay0,slew0)
def find_min_period(self,data_value):
"""Creates a spice test and instantiates a single SRAM for
testing. Returns a tuple of the lowest period and its
clk-to-q delay for the specified data_value."""
# Find a valid and feasible period before starting the binary search
# We just try 2.0ns here, but any value would work albeit slower.
feasible_period = self.find_feasible_period(tech.spice["feasible_period"])
def find_min_period(self,feasible_period, load, slew, feasible_delay1, feasible_delay0):
"""Searches for the smallest period with output delays being within 5% of
long period. """
previous_period = ub_period = feasible_period
lb_period = 0.0
@ -348,93 +272,145 @@ class delay():
ub_period,
lb_period))
(success, delay_out) = self.try_period(feasible_period, target_period, data_value)
if success:
if self.try_period(target_period, load, slew, feasible_delay1, feasible_delay0):
ub_period = target_period
else:
lb_period = target_period
if ch.relative_compare(ub_period, lb_period):
# use the two values to compare, but only return the ub since it is guaranteed feasible
(success, delay_out) = self.try_period(feasible_period, ub_period, data_value)
return (ub_period, delay_out)
if ch.relative_compare(ub_period, lb_period, error_tolerance=0.05):
# ub_period is always feasible
return ub_period
self.error("Should not reach here.",-1)
return (target_period, delay_out)
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 set_probe(self,probe_address, probe_data):
""" Probe address and data can be set separately to utilize other
functions in this characterizer besides analyze."""
self.probe_address = probe_address
self.probe_data = probe_data
def analyze(self,probe_address, probe_data):
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)
(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"))
(feasible_period, feasible_delay1, feasible_delay0) = self.find_feasible_period(loads[0], slews[0])
debug.check(feasible_delay1>0,"Negative delay may not be possible")
debug.check(feasible_delay0>0,"Negative delay may not be possible")
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
# 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, loads[0], slews[0], 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
def obtain_cycle_times(self, slow_period, fast_period):
def obtain_cycle_times(self, period):
"""Returns a list of key time-points [ns] of the waveform (each rising edge)
of the cycles to do a timing evaluation. The last time is the end of the simulation
and does not need a rising edge."""
# idle: half cycle, no operation
t_current = 0.5 * slow_period
# slow cycle1: W data 1 address 1111 to initialize cell to a value
self.cycle_times = [t_current]
self.init_cycle=1
t_current += slow_period
# slow cycle2: R data 1 address 1111 (to ensure cell was written to opposite data value)
# idle cycle, no operation
t_current = period
self.cycle_times = []
# cycle0: W data 1 address 1111 to initialize cell to a value
self.cycle_times.append(t_current)
self.verify_init_cycle=2
t_current += slow_period
t_current += period
# fast cycle3: W data 0 address 1111 (to ensure a write of opposite value works)
# cycle1: W data 0 address 1111 (to ensure a write of value works)
self.cycle_times.append(t_current)
self.write_cycle=3
t_current += fast_period
# fast cycle4: W data 1 address 0000 (to invert the bus cap from prev write)
self.write0_cycle=1
t_current += period
# cycle2: W data 1 address 0000 (to clear the data bus cap)
self.cycle_times.append(t_current)
self.clear_bus_cycle=4
t_current += fast_period
t_current += period
# fast cycle5: R data 0 address 1111 (to ensure that a read works and gets the value)
# cycle3: R data 0 address 1111 to check W0 works
self.cycle_times.append(t_current)
self.read_cycle=5
t_current += fast_period
self.read0_cycle=3
t_current += period
# slow cycle 6: wait a slow clock period to end the simulation
# cycle4: W data 1 address 1111 (to ensure a write of value works)
self.cycle_times.append(t_current)
self.wait_cycle=6
t_current += slow_period
self.write1_cycle=4
t_current += period
# end time of simulation
# cycle5: W data 0 address 0000 (to clear the data bus cap)
self.cycle_times.append(t_current)
t_current += period
# cycle6: R data 1 address 1111 to check W1 works
self.cycle_times.append(t_current)
self.read1_cycle=6
t_current += period
# cycle7: wait a clock period to end the simulation
self.cycle_times.append(t_current)
t_current += period

View File

@ -8,7 +8,8 @@ import math
import setup_hold
import delay
import charutils as ch
import tech
import numpy as np
OPTS = globals.get_opts()
@ -16,24 +17,53 @@ class lib:
""" lib file generation."""
def __init__(self, libname, sram, spfile, use_model=OPTS.analytical_delay):
self.sram = sram
self.spfile = spfile
self.use_model = use_model
self.name = sram.name
self.num_words = sram.num_words
self.word_size = sram.word_size
self.addr_size = sram.addr_size
self.sh = setup_hold.setup_hold()
self.d = delay.delay(sram, spfile)
# These are the parameters to determine the table sizes
#self.load_scales = np.array([0.1, 0.25, 0.5, 1, 2, 4, 8])
self.load_scales = np.array([0.25, 1, 8])
#self.load_scales = np.array([0.25, 1])
self.load = tech.spice["FF_in_cap"]
self.loads = self.load_scales*self.load
debug.info(1,"Loads: {0}".format(self.loads))
#self.slew_scales = np.array([0.1, 0.25, 0.5, 1, 2, 4, 8])
self.slew_scales = np.array([0.25, 1, 8])
#self.slew_scales = np.array([0.25, 1])
self.slew = tech.spice["rise_time"]
self.slews = self.slew_scales*self.slew
debug.info(1,"Slews: {0}".format(self.slews))
debug.info(1,"Writing to {0}".format(libname))
self.lib = open(libname, "w")
self.write_header()
self.write_data_bus()
self.write_addr_bus()
self.write_control_pins()
self.write_clk()
self.lib.close()
def write_header(self):
""" Write the header information """
self.lib.write("library ({0}_lib)".format(self.name))
self.lib.write("{\n")
self.lib.write(" delay_model : \"table_lookup\";\n")
self.write_units()
self.write_defaults()
self.write_LUT()
self.write_LUT_templates()
self.lib.write(" default_operating_conditions : TT; \n")
@ -50,34 +80,7 @@ class lib:
self.lib.write(" dont_use : true;\n")
self.lib.write(" map_only : true;\n")
self.lib.write(" dont_touch : true;\n")
self.lib.write(" area : {0};\n\n".format(sram.width * sram.height))
times = self.sh.analyze()
for i in times.keys():
times[i] = ch.round_time(times[i])
probe_address = "1" * self.addr_size
probe_data = self.word_size - 1
if use_model:
data = sram.analytical_model(slope=0.001)
else:
data = self.d.analyze(probe_address, probe_data)
for i in data.keys():
if i == "read_power" or i == "write_power":
continue
data[i] = ch.round_time(data[i])
self.write_data_bus(data, times)
self.write_addr_bus(times)
self.write_control_pins(times)
self.write_clk(data)
self.lib.close()
self.lib.write(" area : {0};\n\n".format(self.sram.width * self.sram.height))
def write_units(self):
@ -116,47 +119,75 @@ class lib:
self.lib.write(" default_fanout_load : 1.0 ;\n")
self.lib.write(" default_max_fanout : 4.0 ;\n")
self.lib.write(" default_connection_class : universal ;\n\n")
def create_list(self,values):
""" Helper function to create quoted, line wrapped list """
list_values = ", ".join(str(v) for v in values)
return "\"{0}\"".format(list_values)
def create_array(self,values, length):
""" Helper function to create quoted, line wrapped array with each row of given length """
# check that the length is a multiple or give an error!
debug.check(len(values)%length == 0,"Values are not a multiple of the length. Cannot make a full array.")
rounded_values = map(ch.round_time,values)
split_values = [rounded_values[i:i+length] for i in range(0, len(rounded_values), length)]
formatted_rows = map(self.create_list,split_values)
formatted_array = ",\\\n".join(formatted_rows)
return formatted_array
def write_index(self, number, values):
""" Write the index """
quoted_string = self.create_list(values)
self.lib.write(" index_{0}({1});\n".format(number,quoted_string))
def write_values(self, values, row_length, indent):
""" Write the index """
quoted_string = self.create_array(values, row_length)
# indent each newline plus extra spaces for word values
indented_string = quoted_string.replace('\n', '\n' + indent +" ")
self.lib.write("{0}values({1});\n".format(indent,indented_string))
def write_LUT(self):
def write_LUT_templates(self):
""" Adds lookup_table format (A 1x1 lookup_table)."""
Tran = ["CELL_UP_FOR_CLOCK" , "CELL_DN_FOR_CLOCK"]
Tran = ["CELL_TABLE"]
for i in Tran:
self.lib.write(" lu_table_template({0})".format(i))
self.lib.write("{\n")
self.lib.write(" variable_1 : input_net_transition;\n")
self.lib.write(" variable_2 : total_output_net_capacitance;\n")
self.lib.write(" index_1 (\"0.5\");\n")
self.lib.write(" index_2 (\"0.5\");\n")
self.write_index(1,self.slews)
self.write_index(2,self.loads)
self.lib.write(" }\n\n")
CONS = ["CONSTRAINT_HIGH_POS" , "CONSTRAINT_LOW_POS"]
CONS = ["CONSTRAINT_TABLE"]
for i in CONS:
self.lib.write(" lu_table_template({0})".format(i))
self.lib.write("{\n")
self.lib.write(" variable_1 : related_pin_transition;\n")
self.lib.write(" variable_2 : constrained_pin_transition;\n")
self.lib.write(" index_1 (\"0.5\");\n")
self.lib.write(" index_2 (\"0.5\");\n")
self.write_index(1,self.slews)
self.write_index(2,self.slews)
self.lib.write(" }\n\n")
self.lib.write(" lu_table_template(CLK_TRAN) {\n")
self.lib.write(" variable_1 : constrained_pin_transition;\n")
self.lib.write(" index_1 (\"0.5\");\n")
self.lib.write(" }\n\n")
# self.lib.write(" lu_table_template(CLK_TRAN) {\n")
# self.lib.write(" variable_1 : constrained_pin_transition;\n")
# self.write_index(1,self.slews)
# self.lib.write(" }\n\n")
self.lib.write(" lu_table_template(TRAN) {\n")
self.lib.write(" variable_1 : total_output_net_capacitance;\n")
self.lib.write(" index_1 (\"0.5\");\n")
self.lib.write(" }\n\n")
# self.lib.write(" lu_table_template(TRAN) {\n")
# self.lib.write(" variable_1 : total_output_net_capacitance;\n")
# self.write_index(1,self.slews)
# self.lib.write(" }\n\n")
CONS2 = ["INPUT_BY_TRANS_FOR_CLOCK" , "INPUT_BY_TRANS_FOR_SIGNAL"]
for i in CONS2:
self.lib.write(" power_lut_template({0})".format(i))
self.lib.write("{\n")
self.lib.write(" variable_1 : input_transition_time;\n")
self.lib.write(" index_1 (\"0.5\");\n")
self.lib.write(" }\n\n")
# CONS2 = ["INPUT_BY_TRANS_FOR_CLOCK" , "INPUT_BY_TRANS_FOR_SIGNAL"]
# for i in CONS2:
# self.lib.write(" power_lut_template({0})".format(i))
# self.lib.write("{\n")
# self.lib.write(" variable_1 : input_transition_time;\n")
# #self.write_index(1,self.slews)
# self.write_index(1,[self.slews[0]])
# self.lib.write(" }\n\n")
def write_bus(self):
""" Adds format of DATA and ADDR bus."""
@ -179,107 +210,122 @@ class lib:
self.lib.write(" }\n\n")
def write_timing(self, times):
def write_FF_setuphold(self):
""" Adds Setup and Hold timing results"""
self.compute_setup_hold()
self.lib.write(" timing(){ \n")
self.lib.write(" timing_type : setup_rising; \n")
self.lib.write(" related_pin : \"clk\"; \n")
self.lib.write(" rise_constraint(CONSTRAINT_HIGH_POS) {\n")
self.lib.write(" values(\"{0}\"); \n".format(times["setup_time_one"]))
self.lib.write(" rise_constraint(CONSTRAINT_TABLE) {\n")
rounded_values = map(ch.round_time,self.times["setup_times_LH"])
self.write_values(rounded_values,len(self.slews)," ")
self.lib.write(" }\n")
self.lib.write(" fall_constraint(CONSTRAINT_LOW_POS) {\n")
self.lib.write(" values(\"{0}\"); \n".format(times["setup_time_zero"]))
self.lib.write(" fall_constraint(CONSTRAINT_TABLE) {\n")
rounded_values = map(ch.round_time,self.times["setup_times_HL"])
self.write_values(rounded_values,len(self.slews)," ")
self.lib.write(" }\n")
self.lib.write(" }\n")
self.lib.write(" timing(){ \n")
self.lib.write(" timing_type : hold_rising; \n")
self.lib.write(" related_pin : \"clk\"; \n")
self.lib.write(" rise_constraint(CONSTRAINT_HIGH_POS) {\n")
self.lib.write(" values(\"{0}\"); \n".format(times["hold_time_one"]))
self.lib.write(" rise_constraint(CONSTRAINT_TABLE) {\n")
rounded_values = map(ch.round_time,self.times["hold_times_LH"])
self.write_values(rounded_values,len(self.slews)," ")
self.lib.write(" }\n")
self.lib.write(" fall_constraint(CONSTRAINT_LOW_POS) {\n")
self.lib.write(" values(\"{0}\"); \n".format(times["hold_time_zero"]))
self.lib.write(" fall_constraint(CONSTRAINT_TABLE) {\n")
rounded_values = map(ch.round_time,self.times["hold_times_HL"])
self.write_values(rounded_values,len(self.slews)," ")
self.lib.write(" }\n")
self.lib.write(" }\n")
def write_data_bus(self, data, times):
def write_data_bus(self):
""" Adds data bus timing results."""
self.compute_delay()
self.lib.write(" bus(DATA){\n")
self.lib.write(" bus_type : DATA; \n")
self.lib.write(" direction : inout; \n")
self.lib.write(" max_capacitance : {0}; \n".format(tech.spice["FF_in_cap"] + tech.spice["tri_gate_out_cap"] ))
self.lib.write(" pin(DATA[{0}:0])".format(self.word_size - 1))
self.lib.write("{\n")
self.lib.write(" }\n")
self.lib.write(" max_capacitance : {0}; \n".format(8*tech.spice["FF_in_cap"]))
self.lib.write(" three_state : \"!OEb & !clk\"; \n")
self.lib.write(" memory_write(){ \n")
self.lib.write(" address : ADDR; \n")
self.lib.write(" clocked_on : clk; \n")
self.lib.write(" }\n")
self.lib.write(" internal_power(){\n")
self.lib.write(" when : \"OEb & !clk\"; \n")
self.lib.write(" rise_power(INPUT_BY_TRANS_FOR_SIGNAL){\n")
self.lib.write(" values(\"{0}\");\n".format(data["write_power"]* 1e3))
self.lib.write(" }\n")
self.lib.write(" fall_power(INPUT_BY_TRANS_FOR_SIGNAL){\n")
self.lib.write(" values(\"{0}\");\n".format(data["write_power"]* 1e3))
self.lib.write(" }\n")
self.lib.write(" }\n")
self.write_timing(times)
self.lib.write(" memory_read(){ \n")
self.lib.write(" address : ADDR; \n")
self.lib.write(" }\n")
self.lib.write(" pin(DATA[{0}:0])".format(self.word_size - 1))
self.lib.write("{\n")
self.lib.write(" internal_power(){\n")
self.lib.write(" when : \"OEb & !clk\"; \n")
self.lib.write(" rise_power(scalar){\n")
self.lib.write(" values(\"{0}\");\n".format(self.delay["write1_power"]))
self.lib.write(" }\n")
self.lib.write(" fall_power(scalar){\n")
self.lib.write(" values(\"{0}\");\n".format(self.delay["write0_power"]))
self.lib.write(" }\n")
self.lib.write(" }\n")
self.write_FF_setuphold()
self.lib.write(" internal_power(){\n")
self.lib.write(" when : \"!OEb & !clk\"; \n")
self.lib.write(" rise_power(INPUT_BY_TRANS_FOR_SIGNAL){\n")
self.lib.write(" values(\"{0}\");\n".format(data["read_power"]* 1e3))
self.lib.write(" rise_power(scalar){\n")
self.lib.write(" values(\"{0}\");\n".format(self.delay["read1_power"]))
self.lib.write(" }\n")
self.lib.write(" fall_power(INPUT_BY_TRANS_FOR_SIGNAL){\n")
self.lib.write(" values(\"{0}\");\n".format(data["read_power"]* 1e3))
self.lib.write(" fall_power(scalar){\n")
self.lib.write(" values(\"{0}\");\n".format(self.delay["read0_power"]))
self.lib.write(" }\n")
self.lib.write(" }\n")
self.lib.write(" timing(){ \n")
self.lib.write(" timing_sense : non_unate; \n")
self.lib.write(" related_pin : \"clk\"; \n")
self.lib.write(" timing_type : rising_edge; \n")
self.lib.write(" cell_rise(CELL_UP_FOR_CLOCK) {\n")
self.lib.write(" values(\"{0}\"); \n".format(data["delay1"]))
self.lib.write(" timing_type : falling_edge; \n")
self.lib.write(" cell_rise(CELL_TABLE) {\n")
rounded_values = map(ch.round_time,self.delay["delay1"])
self.write_values(rounded_values,len(self.loads)," ")
self.lib.write(" }\n")
self.lib.write(" cell_fall(CELL_DN_FOR_CLOCK) {\n")
self.lib.write(" values(\"{0}\"); \n".format(data["delay0"]))
self.lib.write(" cell_fall(CELL_TABLE) {\n")
rounded_values = map(ch.round_time,self.delay["delay0"])
self.write_values(rounded_values,len(self.loads)," ")
self.lib.write(" }\n")
self.lib.write(" rise_transition(TRAN) {\n")
self.lib.write(" values(\"{0}\"); \n".format(data["delay1"]))
self.lib.write(" rise_transition(CELL_TABLE) {\n")
rounded_values = map(ch.round_time,self.delay["slew1"])
self.write_values(rounded_values,len(self.loads)," ")
self.lib.write(" }\n")
self.lib.write(" fall_transition(TRAN) {\n")
self.lib.write(" values(\"{0}\"); \n".format(data["delay0"]))
self.lib.write(" fall_transition(CELL_TABLE) {\n")
rounded_values = map(ch.round_time,self.delay["slew0"])
self.write_values(rounded_values,len(self.loads)," ")
self.lib.write(" }\n")
self.lib.write(" }\n")
self.lib.write(" }\n")
self.lib.write(" }\n\n")
def write_addr_bus(self, times):
def write_addr_bus(self):
""" Adds addr bus timing results."""
self.lib.write(" bus(ADDR){\n")
self.lib.write(" bus_type : ADDR; \n")
self.lib.write(" direction : input; \n")
self.lib.write(" capacitance : {0}; \n".format(tech.spice["FF_in_cap"]))
self.lib.write(" max_transition : 0.5;\n")
self.lib.write(" max_transition : {0};\n".format(self.slews[-1]))
self.lib.write(" fanout_load : 1.000000;\n")
self.lib.write(" pin(ADDR[{0}:0])".format(self.addr_size - 1))
self.lib.write("{\n")
self.lib.write(" }\n")
self.write_timing(times)
self.write_FF_setuphold()
self.lib.write(" }\n")
self.lib.write(" }\n\n")
def write_control_pins(self, times):
def write_control_pins(self):
""" Adds control pins timing results."""
ctrl_pin_names = ["CSb", "OEb", "WEb"]
@ -288,39 +334,68 @@ class lib:
self.lib.write("{\n")
self.lib.write(" direction : input; \n")
self.lib.write(" capacitance : {0}; \n".format(tech.spice["FF_in_cap"]))
self.write_timing(times)
self.write_FF_setuphold()
self.lib.write(" }\n\n")
def write_clk(self, data):
def write_clk(self):
""" Adds clk pin timing results."""
self.compute_delay()
self.lib.write(" pin(clk){\n")
self.lib.write(" clock : true;\n")
self.lib.write(" direction : input; \n")
self.lib.write(" capacitance : {0}; \n".format(tech.spice["FF_in_cap"]))
min_pulse_width = (ch.round_time(data["min_period1"]) + ch.round_time(data["min_period0"]))/2.0
min_period = ch.round_time(data["min_period1"]) + ch.round_time(data["min_period0"])
min_pulse_width = ch.round_time(self.delay["min_period"])/2.0
min_period = ch.round_time(self.delay["min_period"])
self.lib.write(" timing(){ \n")
self.lib.write(" timing_type :\"min_pulse_width\"; \n")
self.lib.write(" related_pin : clk; \n")
self.lib.write(" rise_constraint(CLK_TRAN) {\n")
self.lib.write(" rise_constraint(scalar) {\n")
self.lib.write(" values(\"{0}\"); \n".format(min_pulse_width))
self.lib.write(" }\n")
self.lib.write(" fall_constraint(CLK_TRAN) {\n")
self.lib.write(" fall_constraint(scalar) {\n")
self.lib.write(" values(\"{0}\"); \n".format(min_pulse_width))
self.lib.write(" }\n")
self.lib.write(" }\n")
self.lib.write(" timing(){ \n")
self.lib.write(" timing_type :\"minimum_period\"; \n")
self.lib.write(" related_pin : clk; \n")
self.lib.write(" rise_constraint(CLK_TRAN) {\n")
self.lib.write(" rise_constraint(scalar) {\n")
self.lib.write(" values(\"{0}\"); \n".format(min_period))
self.lib.write(" }\n")
self.lib.write(" fall_constraint(CLK_TRAN) {\n")
self.lib.write(" fall_constraint(scalar) {\n")
self.lib.write(" values(\"{0}\"); \n".format(min_period))
self.lib.write(" }\n")
self.lib.write(" }\n")
self.lib.write(" }\n")
self.lib.write(" }\n")
self.lib.write("}\n")
def compute_delay(self):
""" Do the analysis if we haven't characterized the SRAM yet """
try:
self.d
except AttributeError:
self.d = delay.delay(self.sram, self.spfile)
probe_address = "1" * self.addr_size
probe_data = self.word_size - 1
if self.use_model:
self.d = True
self.delay = self.sram.analytical_model(self.slews,self.loads)
else:
self.delay = self.d.analyze(probe_address, probe_data, self.slews, self.loads)
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
try:
self.sh
except AttributeError:
self.sh = setup_hold.setup_hold()
if self.use_model:
self.times = self.sh.analytical_model(self.slews,self.loads)
else:
self.times = self.sh.analyze(self.slews,self.slews)

View File

@ -8,9 +8,6 @@ import ms_flop
OPTS = globals.get_opts()
vdd = tech.spice["supply_voltage"]
gnd = tech.spice["gnd_voltage"]
class setup_hold():
"""
@ -20,311 +17,308 @@ class setup_hold():
def __init__(self):
# This must match the spice model order
self.pins = ["data_buf", "dout", "dout_bar", "clk_buf", "vdd", "gnd"]
self.output_name = "dout"
self.pins = ["data", "dout", "dout_bar", "clk", "vdd", "gnd"]
self.model_name = "ms_flop"
self.model_location = OPTS.openram_tech + "sp_lib/ms_flop.sp"
self.period = tech.spice["feasible_period"]
self.vdd = tech.spice["supply_voltage"]
self.gnd = tech.spice["gnd_voltage"]
debug.info(2,"Feasible period from technology file: {0} ".format(self.period))
def check_arguments(self, correct_value, period):
"""Checks if given arguments for write_stimulus() meets requirements"""
if not isinstance(correct_value, float):
if not isinstance(correct_value, int):
debug.error("Given correct_value is not a valid number",1)
if not isinstance(period, float):
if not isinstance(period, int):
debug.error("Given period is not a valid number",1)
def write_stimulus(self, mode, target_time, correct_value, period, noise_margin):
def write_stimulus(self, mode, target_time, correct_value):
"""Creates a stimulus file for SRAM setup/hold time calculation"""
self.check_arguments(correct_value,period)
# creates and opens the stimulus file for writing
temp_stim = OPTS.openram_temp + "stim.sp"
self.sf = open(temp_stim, "w")
self.write_header(correct_value, period)
self.write_header(correct_value)
# instantiate the master-slave d-flip-flop
self.sf.write("* Instantiation of the Master-Slave D-flip-flop\n")
stimuli.inst_model(stim_file=self.sf,
pins=self.pins,
model_name=self.model_name)
self.sf.write("\n")
# create a buffer for the inputs
self.sf.write("* Buffer subckt\n")
stimuli.create_buffer(stim_file=self.sf,
buffer_name="buffer",
size=[1, 1])
self.sf.write("\n")
self.write_data(mode=mode,
target_time=target_time,
period=period,
correct_value=correct_value)
self.write_clock(period)
self.write_clock()
self.write_measures(mode=mode,
correct_value=correct_value,
noise_margin=noise_margin,
period=period)
correct_value=correct_value)
self.write_control(period=period)
stimuli.write_control(self.sf,4*self.period)
self.sf.close()
def write_header(self, correct_value, period):
def write_header(self, correct_value):
""" Write the header file with all the models and the power supplies. """
self.sf.write("* Stimulus for setup/hold: data {0} period {1}n\n".format(correct_value, period))
self.sf.write("\n")
self.sf.write("* Stimulus for setup/hold: data {0} period {1}n\n".format(correct_value, self.period))
# include files in stimulus file
self.model_list = tech.spice["fet_models"] + [self.model_location]
stimuli.write_include(stim_file=self.sf,
models=self.model_list)
self.sf.write("\n")
# add vdd/gnd statements
self.sf.write("* Global Power Supplies\n")
stimuli.write_supply(stim_file=self.sf,
vdd_name=tech.spice["vdd_name"],
gnd_name=tech.spice["gnd_name"],
vdd_voltage=vdd,
gnd_voltage=gnd)
self.sf.write("\n")
stimuli.write_supply(self.sf)
def write_data(self, mode, period, target_time, correct_value):
""" Create the buffered data signals for setup/hold analysis """
self.sf.write("* Buffer for the DATA signal\n")
stimuli.add_buffer(stim_file=self.sf,
buffer_name="buffer",
signal_list=["DATA"])
def write_data(self, mode, target_time, correct_value):
"""Create the data signals for setup/hold analysis. First period is to
initialize it to the opposite polarity. Second period is used for
characterization.
"""
self.sf.write("* Generation of the data and clk signals\n")
incorrect_value = stimuli.get_inverse_value(correct_value)
if mode=="HOLD":
init_value = incorrect_value
start_value = correct_value
end_value = incorrect_value
else:
init_value = incorrect_value
start_value = incorrect_value
end_value = correct_value
stimuli.gen_pulse(stim_file=self.sf,
sig_name="DATA",
v1=start_value,
v2=end_value,
offset=target_time,
period=2*period,
t_rise=tech.spice["rise_time"],
t_fall=tech.spice["fall_time"])
self.sf.write("\n")
stimuli.gen_pwl(stim_file=self.sf,
sig_name="data",
clk_times=[self.period, target_time],
data_values=[init_value, start_value, end_value],
period=target_time,
slew=self.constrained_input_slew,
setup=0)
def write_clock(self,period):
""" Create the buffered clock signal for setup/hold analysis """
self.sf.write("* Buffer for the clk signal\n")
stimuli.add_buffer(stim_file=self.sf,
buffer_name="buffer",
signal_list=["clk"])
self.sf.write("\n")
stimuli.gen_pulse(stim_file=self.sf,
sig_name="clk",
offset=period,
period=period,
t_rise=tech.spice["rise_time"],
t_fall=tech.spice["fall_time"])
self.sf.write("\n")
def write_clock(self):
""" Create the clock signal for setup/hold analysis. First period initializes the FF
while the second is used for characterization."""
stimuli.gen_pwl(stim_file=self.sf,
sig_name="clk",
# initial clk edge is right after the 0 time to initialize a flop
# without using .IC on an internal node.
# Return input to value after one period.
# The second pulse is the characterization one at 2*period
clk_times=[0.1*self.period,self.period,2*self.period],
data_values=[0, 1, 0, 1],
period=2*self.period,
slew=self.constrained_input_slew,
setup=0)
def write_measures(self, mode, correct_value, noise_margin, period):
def write_measures(self, mode, correct_value):
""" Measure statements for setup/hold with right phases. """
if correct_value == vdd:
max_or_min = "MAX"
rise_or_fall = "RISE"
if correct_value == 1:
dout_rise_or_fall = "RISE"
else:
max_or_min = "MIN"
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"
incorrect_value = stimuli.get_inverse_value(correct_value)
self.sf.write("* Measure statements for pass/fail verification\n")
self.sf.write(".IC v({0})={1}\n".format(self.output_name, incorrect_value))
#self.sf.write(".MEASURE TRAN {0}VOUT {0} v({1}) GOAL={2}\n".format(max_or_min, output_name, noise_margin))
# above is the old cmd for hspice, below is the one work for both
self.sf.write(".MEASURE TRAN {0}VOUT {0} v({1}) from ={2}n to ={3}n\n".format(max_or_min,
self.output_name,
1.5*period,
2*period))
self.sf.write("\n")
trig_name = "clk"
targ_name = "dout"
trig_val = targ_val = 0.5 * self.vdd
# Start triggers right before the clock edge at 2*period
stimuli.gen_meas_delay(stim_file=self.sf,
meas_name="clk2q_delay",
trig_name=trig_name,
targ_name=targ_name,
trig_val=trig_val,
targ_val=targ_val,
trig_dir="RISE",
targ_dir=dout_rise_or_fall,
td=1.9*self.period)
targ_name = "data"
# Start triggers right after initialize value is returned to normal
# at one period
stimuli.gen_meas_delay(stim_file=self.sf,
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,
td=1.2*self.period)
def write_control(self, period):
# transient window
end_time = 2 * period
self.sf.write(".TRAN 5p {0}n\n".format(end_time))
self.sf.write(".OPTIONS POST=1 PROBE\n")
# create plots for all signals
self.sf.write(".probe V(*)\n")
# end the stimulus file
self.sf.write(".end\n")
def bidir_search(self, correct_value, noise_margin, measure_name, mode):
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.
"""
period = tech.spice["feasible_period"]
debug.info(2,"Feasible period from technology file: {0} ".format(period))
# The clock will start being offset by a period, so we want to look before and after
# this time by half a period.
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
# 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=target_time,
correct_value=correct_value,
period=period,
noise_margin=noise_margin)
target_time=feasible_bound,
correct_value=correct_value)
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(2,"Checked initial {0} time {1}, data at {2}, clock at {3} ".format(mode,setuphold_time,
target_time,period))
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)
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))
# We already found it feasible, so advance one step first thing.
debug.info(2,"Performing bidir search on {3} time: {2} LB: {0} UB: {1} ".format(lower_bound,
upper_bound,
setuphold_time,
mode))
if mode == "HOLD":
target_time -= 0.5 * (upper_bound - lower_bound)
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:
target_time += 0.5 * (upper_bound - lower_bound)
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,
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))
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()
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)
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:
lower_bound = target_time
target_time += 0.5 * (upper_bound - lower_bound)
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(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)
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...")
# 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
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}, data at {2}, clock at {3}.".format(mode,setuphold_time,target_time,period))
return setuphold_time
debug.info(2,"Converged on {0} time {1}.".format(mode,passing_setuphold_time))
return passing_setuphold_time
def setup_time(self):
"""Calculates the setup time for low-to-high and high-to-low
transition for a D-flip-flop"""
one_found = self.bidir_search(vdd, 0.9*vdd, "maxvout", "SETUP")
zero_found = self.bidir_search(gnd, 0.1*vdd, "minvout", "SETUP")
return [one_found, zero_found]
def hold_time(self):
"""Calculates the hold time for low-to-high and high-to-low
transition for a D-flip-flop"""
one_found = self.bidir_search(vdd, 0.9*vdd, "maxvout", "HOLD")
zero_found = self.bidir_search(gnd, 0.1*vdd, "minvout", "HOLD")
return [one_found, zero_found]
def pass_fail_test(self,value,correct_value,noise_margin):
"""Function to Test if the output value reached the
noise_margin to determine if it passed or failed"""
if correct_value == vdd:
return True if value >= noise_margin else False
else:
return True if value <= noise_margin else False
def analyze(self):
"""main function to calculate both setup and hold time for the
d-flip-flop returns a dictionary that contains 4 times for both
setup/hold times for high_to_low and low_to_high transition
dictionary keys: setup_time_one (low_to_high), setup_time_zero
(high_to_low), hold_time_one (low_to_high), hold_time_zero
(high_to_low)
def setup_LH_time(self):
"""Calculates the setup time for low-to-high transition for a DFF
"""
return self.bidir_search(1, "SETUP")
[one_setup_time, zero_setup_time] = self.setup_time()
[one_hold_time, zero_hold_time] = self.hold_time()
debug.info(1, "Setup Time for low_to_high transistion: {0}".format(one_setup_time))
debug.info(1, "Setup Time for high_to_low transistion: {0}".format(zero_setup_time))
debug.info(1, "Hold Time for low_to_high transistion: {0}".format(one_hold_time))
debug.info(1, "Hold Time for high_to_low transistion: {0}".format(zero_hold_time))
times = {"setup_time_one": one_setup_time,
"setup_time_zero": zero_setup_time,
"hold_time_one": one_hold_time,
"hold_time_zero": zero_hold_time
def setup_HL_time(self):
"""Calculates the setup time for high-to-low transition for a DFF
"""
return self.bidir_search(0, "SETUP")
def hold_LH_time(self):
"""Calculates the hold time for low-to-high transition for a DFF
"""
return self.bidir_search(1, "HOLD")
def hold_HL_time(self):
"""Calculates the hold time for high-to-low transition for a DFF
"""
return self.bidir_search(0, "HOLD")
def analyze(self, related_slews, constrained_slews):
"""main function to calculate both setup and hold time for the
DFF and returns a dictionary that contains 4 lists for both
setup/hold times for high_to_low and low_to_high transitions
for all the slew combinations of the data and clock.
"""
LH_setup = []
HL_setup = []
LH_hold = []
HL_hold = []
for self.related_input_slew in related_slews:
for self.constrained_input_slew in constrained_slews:
debug.info(1, "Clock slew: {0} Data slew: {1}".format(self.related_input_slew,self.constrained_input_slew))
LH_setup_time = self.setup_LH_time()
debug.info(1, " Setup Time for low_to_high transistion: {0}".format(LH_setup_time))
HL_setup_time = self.setup_HL_time()
debug.info(1, " Setup Time for high_to_low transistion: {0}".format(HL_setup_time))
LH_hold_time = self.hold_LH_time()
debug.info(1, " Hold Time for low_to_high transistion: {0}".format(LH_hold_time))
HL_hold_time = self.hold_HL_time()
debug.info(1, " Hold Time for high_to_low transistion: {0}".format(HL_hold_time))
LH_setup.append(LH_setup_time)
HL_setup.append(HL_setup_time)
LH_hold.append(LH_hold_time)
HL_hold.append(HL_hold_time)
times = {"setup_times_LH": LH_setup,
"setup_times_HL": HL_setup,
"hold_times_LH": LH_hold,
"hold_times_HL": HL_hold
}
return times
def analytical_model(self,related_slews, constrained_slews):
""" Just return the fixed setup/hold times from the technology.
"""
LH_setup = []
HL_setup = []
LH_hold = []
HL_hold = []
for self.related_input_slew in related_slews:
for self.constrained_input_slew in constrained_slews:
# convert from ps to ns
LH_setup.append(tech.spice["msflop_setup"]/1e3)
HL_setup.append(tech.spice["msflop_setup"]/1e3)
LH_hold.append(tech.spice["msflop_hold"]/1e3)
HL_hold.append(tech.spice["msflop_hold"]/1e3)
times = {"setup_times_LH": LH_setup,
"setup_times_HL": HL_setup,
"hold_times_LH": LH_hold,
"hold_times_HL": HL_hold
}
return times

View File

@ -10,11 +10,12 @@ import debug
import subprocess
import os
import sys
import numpy as np
OPTS = globals.get_opts()
vdd = tech.spice["supply_voltage"]
gnd = tech.spice["gnd_voltage"]
vdd_voltage = tech.spice["supply_voltage"]
gnd_voltage = tech.spice["gnd_voltage"]
vdd_name = tech.spice["vdd_name"]
gnd_name = tech.spice["gnd_name"]
pmos_name = tech.spice["pmos_name"]
@ -26,14 +27,14 @@ def inst_sram(stim_file, abits, dbits, sram_name):
"""function to instatiate the sram subckt"""
stim_file.write("Xsram ")
for i in range(dbits):
stim_file.write("DATA[{0}] ".format(i))
stim_file.write("D[{0}] ".format(i))
for i in range(abits):
stim_file.write("A[{0}]_buf ".format(i))
stim_file.write("A[{0}] ".format(i))
for i in tech.spice["control_signals"]:
stim_file.write("{0}_buf ".format(i))
stim_file.write("{0}_buf_buf ".format(tech.spice["clk"]))
stim_file.write("{0} ".format(i))
stim_file.write("{0} ".format(tech.spice["clk"]))
stim_file.write("{0} {1} ".format(vdd_name, gnd_name))
stim_file.write("{0}\n".format(sram_name))
stim_file.write("{0}\n\n".format(sram_name))
def inst_model(stim_file, pins, model_name):
@ -82,10 +83,10 @@ def create_buffer(stim_file, buffer_name, size=[1,3], beta=2.5):
nmos_name,
size[1] * tx_width,
tx_length))
stim_file.write(".ENDS test_{0}\n".format(buffer_name))
stim_file.write(".ENDS test_{0}\n\n".format(buffer_name))
def add_buffer(stim_file, buffer_name, signal_list):
def inst_buffer(stim_file, buffer_name, signal_list):
"""Adds buffers to each top level signal that is in signal_list (only for sim purposes)"""
for signal in signal_list:
stim_file.write("X{0}_buffer {0} {0}_buf {1} {2} test_{3}\n".format(signal,
@ -94,7 +95,7 @@ def add_buffer(stim_file, buffer_name, signal_list):
buffer_name))
def add_inverter(stim_file, signal_list):
def inst_inverter(stim_file, signal_list):
"""Adds inv for each signal that needs its inverted version (only for sim purposes)"""
for signal in signal_list:
stim_file.write("X{0}_inv {0} {0}_inv {1} {2} test_inv\n".format(signal,
@ -102,24 +103,24 @@ def add_inverter(stim_file, signal_list):
"test"+gnd_name))
def add_accesstx(stim_file, dbits):
def inst_accesstx(stim_file, dbits):
"""Adds transmission gate for inputs to data-bus (only for sim purposes)"""
stim_file.write("* Tx Pin-list: Drain Gate Source Body\n")
for i in range(dbits):
pmos_access_string="mp{0} DATA[{0}] WEb_trans_buf D[{0}]_buf {1} {2} w={3}u l={4}u\n"
pmos_access_string="mp{0} DATA[{0}] acc_en D[{0}] {1} {2} w={3}u l={4}u\n"
stim_file.write(pmos_access_string.format(i,
"test"+vdd_name,
pmos_name,
2 * tx_width,
tx_length))
nmos_access_string="mn{0} DATA[{0}] WEb_trans_inv D[{0}]_buf {1} {2} w={3}u l={4}u\n"
nmos_access_string="mn{0} DATA[{0}] acc_en_inv D[{0}] {1} {2} w={3}u l={4}u\n"
stim_file.write(nmos_access_string.format(i,
"test"+gnd_name,
nmos_name,
2 * tx_width,
tx_length))
def gen_pulse(stim_file, sig_name, v1=gnd, v2=vdd, offset=0, period=1, t_rise=0, t_fall=0):
def gen_pulse(stim_file, sig_name, v1=gnd_voltage, v2=vdd_voltage, offset=0, period=1, t_rise=0, t_fall=0):
"""Generates a periodic signal with 50% duty cycle and slew rates. Period is measured
from 50% to 50%."""
pulse_string="V{0} {0} 0 PULSE ({1} {2} {3}n {4}n {5}n {6}n {7}n)\n"
@ -133,276 +134,95 @@ def gen_pulse(stim_file, sig_name, v1=gnd, v2=vdd, offset=0, period=1, t_rise=0,
period))
def gen_pwl(stim_file, sig_name, clk_times, data_values, period, slew, setup):
# the initial value is not a clock time
debug.check(len(clk_times)+1==len(data_values),"Clock and data value lengths don't match.")
# shift signal times earlier for setup time
times = np.array(clk_times) - setup*period
values = np.array(data_values) * vdd_voltage
half_slew = 0.5 * slew
stim_file.write("V{0} {0} 0 PWL (0n {1}v ".format(sig_name, values[0]))
for i in range(len(times)):
stim_file.write("{0}n {1}v {2}n {3}v ".format(times[i]-half_slew,
values[i],
times[i]+half_slew,
values[i+1]))
stim_file.write(")\n")
def gen_clk_pwl(stim_file, cycle_times, t_fall, t_rise):
"""Generates a clk signal using pwl. The cycle times are the times of the
clock rising edge. It is assumed to start at time 0 with clock 0. Duty
cycle is assumed to be 50%. Rise/fall times are 0-100%."""
stim_file.write("V{0} {0} 0 PWL (0n 0v ".format(tech.spice["clk"]))
for i in range(len(cycle_times)-1):
period = cycle_times[i+1] - cycle_times[i]
t_current = cycle_times[i] - 0.5*t_rise # 50% point is at cycle time
t_current2 = t_current + t_rise
# rising edge
stim_file.write("{0}n {1}v {2}n {3}v ".format(t_current, gnd, t_current2, vdd))
t_current = t_current + 0.5*period - 0.5*t_fall # 50% point is at cycle time
t_current2 = t_current + t_fall
# falling edge
stim_file.write("{0}n {1}v {2}n {3}v ".format(t_current, vdd, t_current2, gnd))
# end time doesn't need a rising edge
stim_file.write("{0}n {1}v)\n".format(cycle_times[-1], gnd))
def gen_data_pwl(stim_file, key_times, sig_name, data_value, feasible_period, target_period, t_rise, t_fall):
def gen_data(stim_file, clk_times, sig_name, period, slew):
"""Generates the PWL data inputs for a simulation timing test."""
data_value_invert = gnd if data_value == vdd else vdd
t_current = 0.0
stim_file.write("V{0} {0} 0 PWL ({1}n {2}v ".format(sig_name, t_current, data_value_invert))
t_current = key_times[2] - 0.25 * target_period
t_current += (0.5 * target_period) # uses falling edge for ZBT mode
slew_time = t_rise if data_value_invert == gnd else t_fall
t_current2 = t_current + slew_time
stim_file.write("{0}n {1}v {2}n {3}v ".format(t_current, data_value_invert, t_current2, data_value))
t_current = key_times[2] + 0.25 * target_period
t_current += (0.5 * target_period) # uses falling edge for ZBT mode
slew_time = t_rise if data_value == gnd else t_fall
t_current2 = t_current + slew_time
stim_file.write("{0}n {1}v {2}n {3}v ".format(t_current, data_value, t_current2, data_value_invert))
t_current = key_times[5] + 0.25 * feasible_period
stim_file.write("{0}n {1}v)\n".format(t_current, data_value_invert))
# values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP
# we are asserting the opposite value on the other side of the tx gate during
# the read to be "worst case". Otherwise, it can actually assist the read.
values = [0, 1, 0, 1, 1, 1, 0, 0, 0 ]
gen_pwl(stim_file, sig_name, clk_times, values, period, slew, 0.05)
def gen_addr_pwl(stim_file, key_times, addr, feasible_period, target_period, t_rise, t_fall):
"""Generates the PWL for address inputs for a simulation timing test"""
# reverse string
reversed_addr = addr[::-1]
# inverts all bits in address using intermediate value of 2
invert_addr = reversed_addr.replace('1', '2').replace('0', '1').replace('2', '0')
def gen_addr(stim_file, clk_times, addr, period, slew):
"""Generates the address inputs for a simulation timing test.
One cycle is different to clear the bus
"""
zero_values = [0, 0, 0, 1, 0, 0, 1, 0, 0 ]
ones_values = [1, 1, 1, 0, 1, 1, 0, 1, 1 ]
for i in range(len(addr)):
sig_name = "A[{0}]".format(i)
if addr[i]==1:
gen_pwl(stim_file, sig_name, clk_times, ones_values, period, slew, 0.05)
else:
gen_pwl(stim_file, sig_name, clk_times, zero_values, period, slew, 0.05)
for i in range(len(reversed_addr)):
v_val = gnd if reversed_addr[i] == '0' else vdd
v_val_invert = gnd if invert_addr[i] == '0' else vdd
t_current = 0.0
stim_file.write("V{0} {0} 0 PWL ({1}n {2}v ".format("A[{0}]".format(i), t_current, v_val))
t_current = key_times[3] - 0.25 * target_period
slew_time = t_rise if v_val == gnd else t_fall
t_current2 = t_current + slew_time
stim_file.write("{0}n {1}v {2}n {3}v ".format(t_current, v_val, t_current2, v_val_invert))
t_current = key_times[4] - 0.25 * target_period
slew_time = t_rise if v_val_invert == gnd else t_fall
t_current2 = t_current + slew_time
stim_file.write("{0}n {1}v {2}n {3}v ".format(t_current, v_val_invert, t_current2, v_val))
t_current = key_times[5] + 0.25 * feasible_period
stim_file.write("{0}n {1}v)\n".format(t_current, v_val))
def gen_constant(stim_file, sig_name, v_ref, v_val):
def gen_constant(stim_file, sig_name, v_val):
"""Generates a constant signal with reference voltage and the voltage value"""
stim_file.write("V{0} {0} {1} DC {2}\n".format(sig_name, v_ref, v_val))
stim_file.write("V{0} {0} 0 DC {1}\n".format(sig_name, v_val))
def gen_csb_pwl(key_times, feasible_period, target_period, t_rise, t_fall):
"""Returns two lists for x,y coordinates for the generation of CSb pwl"""
t_current = 0.0
x_list = [t_current]
y_list = [vdd]
def gen_csb(stim_file, clk_times, period, slew):
""" Generates the PWL CSb signal"""
# values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP
values = [1, 0, 0, 0, 0, 0, 0, 0, 1]
gen_pwl(stim_file, "CSb", clk_times, values, period, slew, 0.05)
for key_time in key_times[:2]:
t_current = key_time - 0.25 * feasible_period
x_list.append(t_current)
y_list.append(vdd)
x_list.append(t_current + t_fall)
y_list.append(gnd)
t_current = key_time + 0.25 * feasible_period
x_list.append(t_current)
y_list.append(gnd)
x_list.append(t_current + t_rise)
y_list.append(vdd)
for key_time in key_times[2:-1]:
t_current = key_time - 0.25 * target_period
x_list.append(t_current)
y_list.append(vdd)
x_list.append(t_current + t_fall)
y_list.append(gnd)
t_current = key_time + 0.25 * target_period
x_list.append(t_current)
y_list.append(gnd)
x_list.append(t_current + t_rise)
y_list.append(vdd)
return (x_list, y_list)
def gen_web(stim_file, clk_times, period, slew):
""" Generates the PWL WEb signal"""
# values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP
values = [1, 0, 0, 0, 1, 0, 0, 1, 1]
gen_pwl(stim_file, "WEb", clk_times, values, period, slew, 0.05)
values = [1, 0, 0, 0, 1, 0, 0, 1, 1]
gen_pwl(stim_file, "acc_en", clk_times, values, period, slew, 0)
values = [0, 1, 1, 1, 0, 1, 1, 0, 0]
gen_pwl(stim_file, "acc_en_inv", clk_times, values, period, slew, 0)
def gen_oeb(stim_file, clk_times, period, slew):
""" Generates the PWL WEb signal"""
# values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP
values = [1, 1, 1, 1, 0, 1, 1, 0, 1]
gen_pwl(stim_file, "OEb", clk_times, values, period, slew, 0.05)
def gen_web_pwl(key_times, feasible_period, target_period, t_rise, t_fall):
"""Returns two lists for x,y coordinates for the generation of WEb pwl"""
t_current = 0.0
x_list = [t_current]
y_list = [vdd]
t_current = key_times[0] - 0.25 * feasible_period
x_list.append(t_current)
y_list.append(vdd)
x_list.append(t_current + t_fall)
y_list.append(gnd)
t_current = key_times[0] + 0.25 * feasible_period
x_list.append(t_current)
y_list.append(gnd)
x_list.append(t_current + t_rise)
y_list.append(vdd)
t_current = key_times[2] - 0.25 * target_period
x_list.append(t_current)
y_list.append(vdd)
x_list.append(t_current + t_fall)
y_list.append(gnd)
t_current = key_times[2] + 0.25 * target_period
x_list.append(t_current)
y_list.append(gnd)
x_list.append(t_current + t_rise)
y_list.append(vdd)
t_current = key_times[3] - 0.25 * target_period
x_list.append(t_current)
y_list.append(vdd)
x_list.append(t_current + t_fall)
y_list.append(gnd)
t_current = key_times[3] + 0.25 * target_period
x_list.append(t_current)
y_list.append(gnd)
x_list.append(t_current + t_rise)
y_list.append(vdd)
return (x_list, y_list)
def gen_oeb_pwl(key_times, feasible_period, target_period, t_rise, t_fall):
"""Returns two lists for x,y coordinates for the generation of OEb pwl"""
t_current = 0.0
x_list = [t_current]
y_list = [vdd]
t_current = key_times[1] - 0.25 * feasible_period
x_list.append(t_current)
y_list.append(vdd)
x_list.append(t_current + t_fall)
y_list.append(gnd)
t_current = key_times[1] + 0.25 * feasible_period
x_list.append(t_current)
y_list.append(gnd)
x_list.append(t_current + t_rise)
y_list.append(vdd)
t_current = key_times[4] - 0.25 * target_period
x_list.append(t_current)
y_list.append(vdd)
x_list.append(t_current + t_fall)
y_list.append(gnd)
t_current = key_times[4] + 0.25 * target_period
x_list.append(t_current)
y_list.append(gnd)
x_list.append(t_current + t_rise)
y_list.append(vdd)
return (x_list, y_list)
def gen_web_trans_pwl(key_times, feasible_period, target_period, t_rise, t_fall):
"""Returns two lists for x,y coordinates for the generation of WEb_transmission_gate pwl"""
t_current = 0.0
x_list = [t_current]
y_list = [vdd]
t_current = key_times[0] + 0.5 * feasible_period
t_current -= 0.25 * feasible_period
x_list.append(t_current)
y_list.append(vdd)
x_list.append(t_current + t_fall)
y_list.append(gnd)
t_current += 0.5 * feasible_period
x_list.append(t_current)
y_list.append(gnd)
x_list.append(t_current + t_rise)
y_list.append(vdd)
t_current = key_times[2] + 0.5 * target_period
t_current -= 0.25 * target_period
x_list.append(t_current)
y_list.append(vdd)
x_list.append(t_current + t_fall)
y_list.append(gnd)
t_current += 0.5 * target_period
x_list.append(t_current)
y_list.append(gnd)
x_list.append(t_current + t_rise)
y_list.append(vdd)
t_current = key_times[3] + 0.5 * target_period
t_current -= 0.25 * target_period
x_list.append(t_current)
y_list.append(vdd)
x_list.append(t_current + t_fall)
y_list.append(gnd)
t_current += 0.5 * target_period
x_list.append(t_current)
y_list.append(gnd)
x_list.append(t_current + t_rise)
y_list.append(vdd)
return (x_list, y_list)
def get_inverse_value(value):
if value > 0.5*vdd:
return gnd
elif value <= 0.5*vdd:
return vdd
def get_inverse_voltage(value):
if value > 0.5*vdd_voltage:
return gnd_voltage
elif value <= 0.5*vdd_voltage:
return vdd_voltage
else:
debug.error("Invalid value to get an inverse of: {0}".format(value))
def gen_pwl(stim_file, sig_name, x_list, y_list):
"""Generates an arbitrary pwl for a signal where xlist is times in
ns and ylist is voltage. """
t_current = 0.0
stim_file.write("V{0} {0} 0 PWL (".format(sig_name))
for p in zip(x_list,y_list):
stim_file.write("{0}n {1}v ".format(p[0],p[1]))
stim_file.write(")\n")
def gen_trap_pwl(stim_file, sig_name, x_list, y_list, t_rise, t_fall):
"""Generates a trapezoidal pwl for a signal where xlist is times in ns and ylist is voltage.
Transitions are assumed to ignore slew and the slew rates are generated automatically
using the provided 0-100% slew times and centering times at the 50% point.."""
stim_file.write("V{0} {0} 0 PWL (".format(sig_name))
for p in zip(x_list,y_list):
slew = t_rise if p[1]>0.5*vdd else t_fall
start = max(p[0]-0.5*slew,0)
end = p[0]+0.5*slew
stim_file.write("{0}n {1}v ".format(start, get_inverse_value(p[1])))
stim_file.write("{0}n {1}v ".format(end, p[1]))
stim_file.write(")\n")
def get_inverse_value(value):
if value > 0.5:
return 0
elif value <= 0.5:
return 1
else:
debug.error("Invalid value to get an inverse of: {0}".format(value))
def gen_meas_delay(stim_file, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, td):
"""Creates the .meas statement for the measurement of delay"""
measure_string=".meas tran {0} TRIG v({1}) VAL={2} RISE={3} TARG v({4}) VAL={5} TD={7}n {6}=1\n"
measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={7}n TARG v({4}) VAL={5} {6}=1 TD={7}n\n\n"
stim_file.write(measure_string.format(meas_name,
trig_name,
trig_val,
@ -411,7 +231,7 @@ def gen_meas_delay(stim_file, meas_name, trig_name, targ_name, trig_val, targ_va
targ_val,
targ_dir,
td))
def gen_meas_power(stim_file, meas_name, t_initial, t_final):
"""Creates the .meas statement for the measurement of avg power"""
# power mea cmd is different in different spice:
@ -419,27 +239,38 @@ def gen_meas_power(stim_file, meas_name, t_initial, t_final):
power_exp = "power"
else:
power_exp = "par('(-1*v(" + str(vdd_name) + ")*I(v" + str(vdd_name) + "))')"
stim_file.write(".meas tran {0} avg {1} from={2}n to={3}n\n".format(meas_name,
stim_file.write(".meas tran {0} avg {1} from={2}n to={3}n\n\n".format(meas_name,
power_exp,
t_initial,
t_final))
stim_file.write("\n")
def write_control(stim_file, end_time):
# UIC is needed for ngspice to converge
stim_file.write(".TRAN 5p {0}n UIC\n".format(end_time))
stim_file.write(".OPTIONS POST=1 RUNLVL=4 PROBE\n")
# create plots for all signals
stim_file.write("* probe is used for hspice\n")
stim_file.write("*.probe V(*)\n")
stim_file.write("* plot is used for ngspice interactive mode \n")
stim_file.write("*.plot V(*)\n")
# end the stimulus file
stim_file.write(".end\n\n")
def write_include(stim_file, models):
"""Writes include statements, inputs are lists of model files"""
for item in list(models):
stim_file.write(".include \"{0}\"\n".format(item))
stim_file.write(".include \"{0}\"\n\n".format(item))
def write_supply(stim_file, vdd_name, gnd_name, vdd_voltage, gnd_voltage):
def write_supply(stim_file):
"""Writes supply voltage statements"""
stim_file.write("V{0} {0} 0.0 {1}\n".format(vdd_name, vdd_voltage))
stim_file.write("V{0} {0} 0.0 {1}\n".format(gnd_name, gnd_voltage))
# This is for the test power supply
stim_file.write("V{0} {0} 0.0 {1}\n".format("test"+vdd_name, vdd_voltage))
stim_file.write("V{0} {0} 0.0 {1}\n".format("test"+gnd_name, gnd_voltage))
stim_file.write("V{0} {0} 0.0 {1}\n\n".format("test"+gnd_name, gnd_voltage))
def run_sim():

View File

@ -34,6 +34,6 @@ def info(lev, str):
if (OPTS.debug_level >= lev):
frm = inspect.stack()[1]
mod = inspect.getmodule(frm[0])
print("\n[{0}]: {1}".format(frm[0].f_code.co_name,str))
print("[{0}]: {1}".format(frm[0].f_code.co_name,str))
# This sometimes gets a NoneType mod...
# print "[" , mod.__name__ , "]: ", str

View File

@ -141,6 +141,17 @@ def read_config(config_file):
if not OPTS.output_path.endswith('/'):
OPTS.output_path += "/"
debug.info(1, "Output saved in " + OPTS.output_path)
# Don't delete the output dir, it may have other files!
# make the directory if it doesn't exist
try:
os.makedirs(OPTS.output_path, 0o750)
except OSError as e:
if e.errno == 17: # errno.EEXIST
os.chmod(OPTS.output_path, 0o750)
except:
debug.error("Unable to make output directory.",-1)
def set_calibre():
@ -219,13 +230,7 @@ def setup_paths():
if e.errno == 17: # errno.EEXIST
os.chmod(OPTS.openram_temp, 0o750)
# Don't delete the output dir, it may have other files!
# make the directory if it doesn't exist
try:
os.makedirs(OPTS.output_path, 0o750)
except OSError as e:
if e.errno == 17: # errno.EEXIST
os.chmod(OPTS.output_path, 0o750)

View File

@ -597,7 +597,7 @@ class hierarchical_decoder(design.design):
yoffset - self.via_shift],
rotate=90)
def delay(self, slope, load = 0.0):
def delay(self, slew, load = 0.0):
# A -> out
if self.determine_predecodes(self.num_inputs)[1]==0:
pre = self.pre2_4
@ -605,15 +605,15 @@ class hierarchical_decoder(design.design):
else:
pre = self.pre3_8
nand = self.nand3
a_t_out_delay = pre.delay(slope=slope,load = nand.input_load())
a_t_out_delay = pre.delay(slew=slew,load = nand.input_load())
# out -> z
out_t_z_delay = nand.delay(slope= a_t_out_delay.slope,
out_t_z_delay = nand.delay(slew= a_t_out_delay.slew,
load = self.inv.input_load())
result = a_t_out_delay + out_t_z_delay
# Z -> decode_out
z_t_decodeout_delay = self.inv.delay(slope = out_t_z_delay.slope , load = load)
z_t_decodeout_delay = self.inv.delay(slew = out_t_z_delay.slew , load = load)
result = result + z_t_decodeout_delay
return result

View File

@ -108,16 +108,16 @@ class hierarchical_predecode2x4(hierarchical_predecode):
def get_via_y(self):
return self.rail_height
def delay(self, slope, load = 0.0 ):
def delay(self, slew, load = 0.0 ):
# A -> B
a_t_b_delay = self.inv.delay(slope=slope,load = self.nand.input_load())
a_t_b_delay = self.inv.delay(slew=slew,load = self.nand.input_load())
# out -> z
b_t_z_delay = self.nand.delay(slope=a_t_b_delay.slope,load = self.inv.input_load())
b_t_z_delay = self.nand.delay(slew=a_t_b_delay.slew,load = self.inv.input_load())
result = a_t_b_delay + b_t_z_delay
# Z -> out
a_t_out_delay = self.inv.delay(slope=b_t_z_delay.slope,load = load)
a_t_out_delay = self.inv.delay(slew=b_t_z_delay.slew,load = load)
result = result + a_t_out_delay
return result

View File

@ -90,13 +90,13 @@ class hierarchical_predecode3x8(hierarchical_predecode):
- 0.5 * drc["minwidth_metal1"])
return yoffset
def delay(self, slope, load = 0.0 ):
def delay(self, slew, load = 0.0 ):
# A -> z
b_t_z_delay = self.nand.delay(slope=slope,
b_t_z_delay = self.nand.delay(slew=slew,
load = self.input_load())
# Z -> out
a_t_out_delay = self.inv.delay(slope=b_t_z_delay.slope,
a_t_out_delay = self.inv.delay(slew=b_t_z_delay.slew,
load = load)
result = b_t_z_delay + a_t_out_delay
return result

View File

@ -148,7 +148,7 @@ class spice:
del usedMODS
spfile.close()
def delay(self, slope, load=0.0):
def delay(self, slew, load=0.0):
"""Inform users undefined delay module while building new modules"""
debug.warning("Design Class {0} delay function needs to be defined"
.format(self.__class__.__name__))
@ -158,7 +158,7 @@ class spice:
# return 0 to keep code running while building
return delay_data(0.0, 0.0)
def cal_delay_with_rc(self, r, c ,slope, swing = 0.5):
def cal_delay_with_rc(self, r, c ,slew, swing = 0.5):
"""
Calculate the delay of a mosfet by
modeling it as a resistance driving a capacitance
@ -167,19 +167,19 @@ class spice:
delay = swing_factor * r * c #c is in ff and delay is in fs
delay = delay * 0.001 #make the unit to ps
# Output slope should be linear to input slope which is described
# as 0.005* slope.
# Output slew should be linear to input slew which is described
# as 0.005* slew.
# The slope will be also influenced by the delay.
# If no input slope(or too small to make impact)
# The mimum slope should be the time to charge RC.
# The slew will be also influenced by the delay.
# If no input slew(or too small to make impact)
# The mimum slew should be the time to charge RC.
# Delay * 2 is from 0 to 100% swing. 0.6*2*delay is from 20%-80%.
slope = delay * 0.6 * 2 + 0.005 * slope
return delay_data(delay = delay, slope = slope)
slew = delay * 0.6 * 2 + 0.005 * slew
return delay_data(delay = delay, slew = slew)
def return_delay(self, delay, slope):
return delay_data(delay, slope)
def return_delay(self, delay, slew):
return delay_data(delay, slew)
def generate_rc_net(self,lump_num, wire_length, wire_width):
return wire_spice_model(lump_num, wire_length, wire_width)
@ -188,17 +188,17 @@ class delay_data:
"""
This is the delay class to represent the delay information
Time is 50% of the signal to 50% of reference signal delay.
Slope is the 20% of the signal to 80% of signal
Slew is the 10% of the signal to 90% of signal
"""
def __init__(self, delay=0.0, slope=0.0):
def __init__(self, delay=0.0, slew=0.0):
""" init function support two init method"""
# will take single input as a coordinate
self.delay = delay
self.slope = slope
self.slew = slew
def __str__(self):
""" override print function output """
return "Delay Data: Delay "+str(self.delay)+", Slope "+str(self.slope)+""
return "Delay Data: Delay "+str(self.delay)+", Slew "+str(self.slew)+""
def __add__(self, other):
"""
@ -206,7 +206,7 @@ class delay_data:
"""
assert isinstance(other,delay_data)
return delay_data(other.delay + self.delay,
other.slope)
other.slew)
def __radd__(self, other):
"""
@ -214,7 +214,7 @@ class delay_data:
"""
assert isinstance(other,delay_data)
return delay_data(other.delay + self.delay,
self.slope)
self.slew)
class wire_spice_model:
@ -241,14 +241,14 @@ class wire_spice_model:
def return_input_cap(self):
return 0.5 * self.wire_c * self.lump_num
def return_delay_over_wire(self, slope, swing = 0.5):
def return_delay_over_wire(self, slew, swing = 0.5):
# delay will be sum of arithmetic sequence start from
# rc to self.lump_num*rc with step of rc
swing_factor = abs(math.log(1-swing)) # time constant based on swing
sum_factor = (1+self.lump_num) * self.lump_num * 0.5 # sum of the arithmetic sequence
delay = sum_factor * swing_factor * self.wire_r * self.wire_c
slope = delay * 2 + slope
result= delay_data(delay, slope)
slew = delay * 2 + slew
result= delay_data(delay, slew)
return result

View File

@ -24,19 +24,19 @@ class ms_flop(design.design):
self.dout_offset = ms_flop.chars["dout"]
self.dout_bar_offset = ms_flop.chars["dout_bar"]
def delay(self, slope, load = 0.0):
def delay(self, slew, load = 0.0):
#import pinv
# use inv to mimic the delay
# din -> mout
#ref = pinv.pinv("reference_inv")
#mid_load = ref.input_load()
#din_t_mout_delay = ref.delay(slope = slope, load = mid_load)
#din_t_mout_delay = ref.delay(slew = slew, load = mid_load)
# mout -> out
#mout_t_out_delay = ref.delay(slope = slope, load = load)
#mout_t_out_delay = ref.delay(slew = slew, load = load)
#result = din_t_mout_delay + mout_t_out_delay
# dont k how to calculate this now, use constant in tech file
from tech import spice
result = self.return_delay(spice["msflop_delay"], spice["msflop_slope"])
result = self.return_delay(spice["msflop_delay"], spice["msflop_slew"])
return result

View File

@ -150,7 +150,7 @@ class ms_flop_array(design.design):
self.vdd_positions.append(vector(self.ms_flop_chars["vdd"]).scale(0, 1))
def delay(self, slope, load=0.0):
result = self.ms_flop.delay(slope = slope,
def delay(self, slew, load=0.0):
result = self.ms_flop.delay(slew = slew,
load = load)
return result

View File

@ -26,7 +26,7 @@ class nand_2(design.design):
name = "nand2_{0}".format(nand_2.unique_id)
nand_2.unique_id += 1
design.design.__init__(self, name)
debug.info(2, "create nand_2 strcuture {0} with size of {1}".format(
debug.info(2, "create nand_2 structure {0} with size of {1}".format(
name, nmos_width))
self.nmos_width = nmos_width
@ -447,7 +447,7 @@ class nand_2(design.design):
from tech import spice
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
def delay(self, slope, load=0.0):
def delay(self, slew, load=0.0):
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
c_para = spice["min_tx_c_para"]*(self.nmos_size/parameter["min_tx_size"])#ff
return self.cal_delay_with_rc(r = r, c = c_para+load, slope =slope)
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
return self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)

View File

@ -26,7 +26,7 @@ class nand_3(design.design):
name = "nand3_{0}".format(nand_3.unique_id)
nand_3.unique_id += 1
design.design.__init__(self, name)
debug.info(2, "create nand_3 strcuture {0} with size of {1}".format(name, nmos_width))
debug.info(2, "create nand_3 structure {0} with size of {1}".format(name, nmos_width))
self.nmos_width = nmos_width
self.height = height
@ -532,7 +532,7 @@ class nand_3(design.design):
def input_load(self):
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
def delay(self, slope, load=0.0):
def delay(self, slew, load=0.0):
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
c_para = spice["min_tx_c_para"]*(self.nmos_size/parameter["min_tx_size"])#ff
return self.cal_delay_with_rc(r = r, c = c_para+load, slope =slope)
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
return self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)

View File

@ -25,7 +25,7 @@ class nor_2(design.design):
name = "nor2_{0}".format(nor_2.unique_id)
nor_2.unique_id += 1
design.design.__init__(self, name)
debug.info(2, "create nand_2 strcuture {0} with size of {1}".format(name, nmos_width))
debug.info(2, "create nor_2 structure {0} with size of {1}".format(name, nmos_width))
self.nmos_width = nmos_width
self.height = height

View File

@ -23,7 +23,7 @@ class pinv(design.design):
name = "pinv{0}".format(pinv.unique_id)
pinv.unique_id += 1
design.design.__init__(self, name)
debug.info(2, "create pinv strcuture {0} with size of {1}".format(name, nmos_width))
debug.info(2, "create pinv structure {0} with size of {1}".format(name, nmos_width))
self.nmos_width = nmos_width
self.beta = beta
@ -410,8 +410,8 @@ class pinv(design.design):
def input_load(self):
return ((self.nmos_size+self.pmos_size)/parameter["min_tx_size"])*spice["min_tx_gate_c"]
def delay(self, slope, load=0.0):
def delay(self, slew, load=0.0):
from tech import spice
r = spice["min_tx_r"]/(self.nmos_size/parameter["min_tx_size"])
c_para = spice["min_tx_c_para"]*(self.nmos_size/parameter["min_tx_size"])#ff
return self.cal_delay_with_rc(r = r, c = c_para+load, slope =slope)
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
return self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)

View File

@ -21,10 +21,10 @@ class sense_amp(design.design):
self.width = sense_amp.chars["width"]
self.height = sense_amp.chars["height"]
def delay(self, slope, load=0.0):
def delay(self, slew, load=0.0):
from tech import spice
r = spice["min_tx_r"]/(10)
c_para = spice["min_tx_c_para"]#ff
result = self.cal_delay_with_rc(r = r, c = c_para+load, slope =slope)
return self.return_delay(result.delay , result.slope)
c_para = spice["min_tx_drain_c"]
result = self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)
return self.return_delay(result.delay, result.slew)

View File

@ -132,6 +132,6 @@ class sense_amp_array(design.design):
height=drc["minwidth_metal1"])
self.SCLK_positions.append(sclk_offset)
def delay(self, slope, load =0.0):
result = self.amp.delay(slope=slope, load =load)
def delay(self, slew, load=0.0):
result = self.amp.delay(slew=slew, load=load)
return result

View File

@ -11,7 +11,6 @@ import getpass
from vector import vector
from globals import OPTS
class sram(design.design):
"""
Dynamically generated SRAM by connecting banks to control logic. The
@ -1174,12 +1173,28 @@ class sram(design.design):
del usedMODS
sp.close()
def analytical_model(self,slope):
#control_delay = self.control.delay(slope=slope)
bank_delay = self.bank.delay(slope = slope)
data ={'delay1': bank_delay.delay, 'delay0': bank_delay.delay,
'min_period1': 0,
'min_period0': 0,
'read_power': 0,
'write_power': 0}
def analytical_model(self,slews,loads):
LH_delay = []
HL_delay = []
LH_slew = []
HL_slew = []
for slew in slews:
for load in loads:
bank_delay = self.bank.delay(slew,load)
# Convert from ps to ns
LH_delay.append(bank_delay.delay/1e3)
HL_delay.append(bank_delay.delay/1e3)
LH_slew.append(bank_delay.slew/1e3)
HL_slew.append(bank_delay.slew/1e3)
data = {"min_period": 0,
"delay1": LH_delay,
"delay0": HL_delay,
"slew1": LH_slew,
"slew0": HL_slew,
"read0_power": 0,
"read1_power": 0,
"write0_power": 0,
"write1_power": 0
}
return data

View File

@ -46,21 +46,40 @@ class timing_sram_test(unittest.TestCase):
debug.info(1, "Probe address {0} probe data {1}".format(probe_address, probe_data))
d = delay.delay(s,tempspice)
data = d.analyze(probe_address, probe_data)
import tech
loads = [tech.spice["FF_in_cap"]*4]
slews = [tech.spice["rise_time"]*2]
data = d.analyze(probe_address, probe_data,slews,loads)
if OPTS.tech_name == "freepdk45":
self.assertTrue(isclose(data['delay1'],0.013649))
self.assertTrue(isclose(data['delay0'],0.22893))
self.assertTrue(isclose(data['min_period1'],0.078582763671875))
self.assertTrue(isclose(data['min_period0'],0.25543212890625))
self.assertTrue(isclose(data['delay1'][0],0.0262)) # diff than hspice
self.assertTrue(isclose(data['delay0'][0],0.1099)) # diff than hspice
self.assertTrue(isclose(data['slew1'][0],0.0210)) # diff than hspice
self.assertTrue(isclose(data['slew0'][0],0.0270)) # diff than hspice
self.assertTrue(isclose(data['min_period'],0.068)) # diff than hspice
self.assertTrue(isclose(data['read0_power'],0.01782)) # diff than hspice
self.assertTrue(isclose(data['read1_power'],0.01778)) # diff than hspice
self.assertTrue(isclose(data['write0_power'],0.01663)) # diff than hspice
self.assertTrue(isclose(data['write1_power'],0.01592)) # diff than hspice
elif OPTS.tech_name == "scn3me_subm":
self.assertTrue(isclose(data['delay1'],1.5335))
self.assertTrue(isclose(data['delay0'],2.2635000000000005))
self.assertTrue(isclose(data['min_period1'],1.53564453125))
self.assertTrue(isclose(data['min_period0'],2.998046875))
self.assertTrue(isclose(data['delay1'][0],0.5985)) # diff than hspice
self.assertTrue(isclose(data['delay0'][0],1.3726)) # diff than hspice
self.assertTrue(isclose(data['slew1'][0],1.0046)) # diff than hspice
self.assertTrue(isclose(data['slew0'][0],1.3013)) # diff than hspice
self.assertTrue(isclose(data['min_period'],1.953)) # diff than hspice
self.assertTrue(isclose(data['read0_power'],4.5491)) # diff than hspice
self.assertTrue(isclose(data['read1_power'],4.5202)) # diff than hspice
self.assertTrue(isclose(data['write0_power'],3.8564)) # diff than hspice
self.assertTrue(isclose(data['write1_power'],3.7287)) # diff than hspice
else:
self.assertTrue(False) # other techs fail
# reset these options
OPTS.check_lvsdrc = True
OPTS.spice_version="hspice"
OPTS.force_spice = False
globals.set_spice()
os.remove(tempspice)
globals.end_openram()

View File

@ -1,53 +0,0 @@
#!/usr/bin/env python2.7
"""
Run a regresion test on various srams
"""
import unittest
from testutils import header,isclose
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.get_opts()
#@unittest.skip("SKIPPING 21_timing_sram_test")
class timing_setup_test(unittest.TestCase):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.spice_version="hspice"
OPTS.force_spice = True
globals.set_spice()
import sram
import setup_hold
sh = setup_hold.setup_hold()
[one_setup_time, zero_setup_time] = sh.hold_time()
OPTS.check_lvsdrc = True
if OPTS.tech_name == "freepdk45":
self.assertTrue(isclose(one_setup_time,-0.0048828125))
self.assertTrue(isclose(zero_setup_time,-0.010986328125))
elif OPTS.tech_name == "scn3me_subm":
self.assertTrue(isclose(one_setup_time,0.04638671875))
self.assertTrue(isclose(zero_setup_time,-0.0830078125))
else:
self.assertTrue(False) # other techs fail
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -28,18 +28,31 @@ class timing_setup_test(unittest.TestCase):
globals.set_spice()
import sram
import tech
slews = [tech.spice["rise_time"]*2]
import setup_hold
sh = setup_hold.setup_hold()
[one_setup_time, zero_setup_time] = sh.setup_time()
data = sh.analyze(slews,slews)
OPTS.check_lvsdrc = True
one_setup_time = data['setup_times_LH'][0]
zero_setup_time = data['setup_times_HL'][0]
one_hold_time = data['hold_times_LH'][0]
zero_hold_time = data['hold_times_HL'][0]
if OPTS.tech_name == "freepdk45":
self.assertTrue(isclose(one_setup_time,0.0146484375))
self.assertTrue(isclose(zero_setup_time,0.008544921875))
self.assertTrue(isclose(one_setup_time,0.0146))
self.assertTrue(isclose(zero_setup_time,0.0085))
self.assertTrue(isclose(one_hold_time,0.00244))
self.assertTrue(isclose(zero_hold_time,-0.00366))
elif OPTS.tech_name == "scn3me_subm":
self.assertTrue(isclose(one_setup_time,0.0927734375))
self.assertTrue(isclose(zero_setup_time,-0.0244140625))
self.assertTrue(isclose(one_setup_time,0.1001))
self.assertTrue(isclose(zero_setup_time,0.02075))
self.assertTrue(isclose(one_hold_time,0.02075))
self.assertTrue(isclose(zero_hold_time,-0.0830))
else:
self.assertTrue(False) # other techs fail

View File

@ -32,12 +32,6 @@ class timing_sram_test(unittest.TestCase):
num_banks=OPTS.config.num_banks,
name="test_sram1")
# reset these options
OPTS.check_lvsdrc = True
OPTS.spice_version="hspice"
OPTS.force_spice = False
globals.set_spice()
import delay
tempspice = OPTS.openram_temp + "temp.sp"
@ -48,23 +42,44 @@ class timing_sram_test(unittest.TestCase):
debug.info(1, "Probe address {0} probe data {1}".format(probe_address, probe_data))
d = delay.delay(s,tempspice)
data = d.analyze(probe_address, probe_data)
import tech
loads = [tech.spice["FF_in_cap"]*4]
slews = [tech.spice["rise_time"]*2]
data = d.analyze(probe_address, probe_data,slews,loads)
if OPTS.tech_name == "freepdk45":
self.assertTrue(isclose(data['delay1'],0.013649)) # diff than hspice
self.assertTrue(isclose(data['delay0'],0.22893)) # diff than hspice
self.assertTrue(isclose(data['min_period1'],0.078582763671875)) # diff than hspice
self.assertTrue(isclose(data['min_period0'],0.25543212890625)) # diff than hspice
self.assertTrue(isclose(data['delay1'][0],0.0268)) # diff than hspice
self.assertTrue(isclose(data['delay0'][0],0.1127)) # diff than hspice
self.assertTrue(isclose(data['slew1'][0],0.0231)) # diff than hspice
self.assertTrue(isclose(data['slew0'][0],0.0276)) # diff than hspice
self.assertTrue(isclose(data['min_period'],0.071)) # diff than hspice
self.assertTrue(isclose(data['read0_power'],0.0227)) # diff than hspice
self.assertTrue(isclose(data['read1_power'],0.0223)) # diff than hspice
self.assertTrue(isclose(data['write0_power'],0.02001)) # diff than hspice
self.assertTrue(isclose(data['write1_power'],0.0193)) # diff than hspice
elif OPTS.tech_name == "scn3me_subm":
self.assertTrue(isclose(data['delay1'],1.5342000000000002)) # diff than hspice
self.assertTrue(isclose(data['delay0'],2.2698)) # diff than hspice
self.assertTrue(isclose(data['min_period1'],1.534423828125)) # diff than hspice
self.assertTrue(isclose(data['min_period0'],2.99560546875)) # diff than hspice
self.assertTrue(isclose(data['delay1'][0],0.6228)) # diff than hspice
self.assertTrue(isclose(data['delay0'][0],1.4147)) # diff than hspice
self.assertTrue(isclose(data['slew1'][0],1.0567)) # diff than hspice
self.assertTrue(isclose(data['slew0'][0],1.3454)) # diff than hspice
self.assertTrue(isclose(data['min_period'],1.719)) # diff than hspice
self.assertTrue(isclose(data['read0_power'],4.7812)) # diff than hspice
self.assertTrue(isclose(data['read1_power'],5.5500)) # diff than hspice
self.assertTrue(isclose(data['write0_power'],3.9314)) # diff than hspice
self.assertTrue(isclose(data['write1_power'],3.4097)) # diff than hspice
else:
self.assertTrue(False) # other techs fail
# reset these options
OPTS.check_lvsdrc = True
OPTS.spice_version="hspice"
OPTS.force_spice = False
globals.set_spice()
os.remove(tempspice)
globals.end_openram()
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -1,55 +0,0 @@
#!/usr/bin/env python2.7
"""
Run a regresion test on various srams
"""
import unittest
from testutils import header,isclose
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.get_opts()
#@unittest.skip("SKIPPING 21_timing_sram_test")
class timing_setup_test(unittest.TestCase):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.spice_version="ngspice"
OPTS.force_spice = True
globals.set_spice()
import sram
import setup_hold
sh = setup_hold.setup_hold()
[one_setup_time, zero_setup_time] = sh.setup_time()
# reset these options
OPTS.check_lvsdrc = True
OPTS.spice_version="hspice"
OPTS.force_spice = False
globals.set_spice()
if OPTS.tech_name == "freepdk45":
self.assertTrue(isclose(one_setup_time,0.0146484375))
self.assertTrue(isclose(zero_setup_time,0.008544921875))
elif OPTS.tech_name == "scn3me_subm":
self.assertTrue(isclose(one_setup_time,0.09521484375)) #diff than hspice
self.assertTrue(isclose(zero_setup_time,-0.0244140625))
else:
self.assertTrue(False) # other techs fail
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -27,10 +27,13 @@ class timing_setup_test(unittest.TestCase):
globals.set_spice()
import sram
import tech
slews = [tech.spice["rise_time"]*2]
import setup_hold
sh = setup_hold.setup_hold()
[one_setup_time, zero_setup_time] = sh.hold_time()
data = sh.analyze(slews,slews)
# reset these options
OPTS.check_lvsdrc = True
@ -38,12 +41,21 @@ class timing_setup_test(unittest.TestCase):
OPTS.force_spice = False
globals.set_spice()
one_setup_time = data['setup_times_LH'][0]
zero_setup_time = data['setup_times_HL'][0]
one_hold_time = data['hold_times_LH'][0]
zero_hold_time = data['hold_times_HL'][0]
if OPTS.tech_name == "freepdk45":
self.assertTrue(isclose(one_setup_time,-0.0048828125))
self.assertTrue(isclose(zero_setup_time,-0.010986328125))
self.assertTrue(isclose(one_setup_time,0.0146))
self.assertTrue(isclose(zero_setup_time,0.0085))
self.assertTrue(isclose(one_hold_time,0.00244))
self.assertTrue(isclose(zero_hold_time,-0.00366))
elif OPTS.tech_name == "scn3me_subm":
self.assertTrue(isclose(one_setup_time,0.45654296875)) # diff than hspice
self.assertTrue(isclose(zero_setup_time,-0.0830078125))
self.assertTrue(isclose(one_setup_time,0.1001))
self.assertTrue(isclose(zero_setup_time,0.0208))
self.assertTrue(isclose(one_hold_time,0.02075))
self.assertTrue(isclose(zero_hold_time,-0.08301))
else:
self.assertTrue(False) # other techs fail

View File

@ -46,7 +46,10 @@ class sram_func_test(unittest.TestCase):
d.set_probe(probe_address,probe_data)
# This will exit if it doesn't find a feasible period
feasible_period = d.find_feasible_period(2.0)
import tech
load = tech.spice["FF_in_cap"]*4
slew = tech.spice["rise_time"]*2
feasible_period = d.find_feasible_period(load,slew)
os.remove(tempspice)

View File

@ -31,52 +31,18 @@ library (sram_2_16_1_freepdk45_lib){
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_UP_FOR_CLOCK){
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1 ("0.5");
index_2 ("0.5");
index_1("0.00125, 0.005, 0.04");
index_2("0.052275, 0.2091, 1.6728");
}
lu_table_template(CELL_DN_FOR_CLOCK){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CONSTRAINT_HIGH_POS){
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CONSTRAINT_LOW_POS){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CLK_TRAN) {
variable_1 : constrained_pin_transition;
index_1 ("0.5");
}
lu_table_template(TRAN) {
variable_1 : total_output_net_capacitance;
index_1 ("0.5");
}
power_lut_template(INPUT_BY_TRANS_FOR_CLOCK){
variable_1 : input_transition_time;
index_1 ("0.5");
}
power_lut_template(INPUT_BY_TRANS_FOR_SIGNAL){
variable_1 : input_transition_time;
index_1 ("0.5");
index_1("0.00125, 0.005, 0.04");
index_2("0.00125, 0.005, 0.04");
}
default_operating_conditions : TT;
@ -113,102 +79,126 @@ cell (sram_2_16_1_freepdk45){
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 0.62166;
pin(DATA[1:0]){
}
max_capacitance : 1.6728;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[1:0]){
internal_power(){
when : "OEb & !clk";
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.67729");
rise_power(scalar){
values("0.020845");
}
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.67729");
fall_power(scalar){
values("0.021849");
}
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
memory_read(){
address : ADDR;
}
internal_power(){
when : "!OEb & !clk";
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.028881");
rise_power(scalar){
values("0.023616");
}
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.028881");
fall_power(scalar){
values("0.023883");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : rising_edge;
cell_rise(CELL_UP_FOR_CLOCK) {
values("0.019");
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.025, 0.026, 0.032",\
"0.026, 0.026, 0.033",\
"0.03, 0.031, 0.037");
}
cell_fall(CELL_DN_FOR_CLOCK) {
values("0.239");
cell_fall(CELL_TABLE) {
values("0.11, 0.11, 0.118",\
"0.11, 0.111, 0.119",\
"0.114, 0.114, 0.122");
}
rise_transition(TRAN) {
values("0.019");
rise_transition(CELL_TABLE) {
values("0.016, 0.017, 0.028",\
"0.016, 0.017, 0.028",\
"0.016, 0.018, 0.028");
}
fall_transition(TRAN) {
values("0.239");
fall_transition(CELL_TABLE) {
values("0.02, 0.022, 0.037",\
"0.02, 0.022, 0.037",\
"0.021, 0.023, 0.037");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 0.2091;
max_transition : 0.5;
max_transition : 0.04;
fanout_load : 1.000000;
pin(ADDR[3:0]){
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
}
pin(CSb){
@ -217,21 +207,29 @@ cell (sram_2_16_1_freepdk45){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
@ -242,21 +240,29 @@ cell (sram_2_16_1_freepdk45){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
@ -267,21 +273,29 @@ cell (sram_2_16_1_freepdk45){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027",\
"0.009, 0.015, 0.027");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015",\
"0.009, 0.009, 0.015");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
rise_constraint(CONSTRAINT_TABLE) {
values("0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004",\
"0.002, 0.002, -0.004");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
fall_constraint(CONSTRAINT_TABLE) {
values("-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016",\
"-0.004, -0.004, -0.016");
}
}
}
@ -293,21 +307,21 @@ cell (sram_2_16_1_freepdk45){
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(CLK_TRAN) {
values("0.175");
rise_constraint(scalar) {
values("0.0405");
}
fall_constraint(CLK_TRAN) {
values("0.175");
fall_constraint(scalar) {
values("0.0405");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(CLK_TRAN) {
values("0.35");
rise_constraint(scalar) {
values("0.081");
}
fall_constraint(CLK_TRAN) {
values("0.35");
fall_constraint(scalar) {
values("0.081");
}
}
}

View File

@ -31,52 +31,18 @@ library (sram_2_16_1_freepdk45_lib){
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_UP_FOR_CLOCK){
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1 ("0.5");
index_2 ("0.5");
index_1("0.00125, 0.005, 0.04");
index_2("0.052275, 0.2091, 1.6728");
}
lu_table_template(CELL_DN_FOR_CLOCK){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CONSTRAINT_HIGH_POS){
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CONSTRAINT_LOW_POS){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CLK_TRAN) {
variable_1 : constrained_pin_transition;
index_1 ("0.5");
}
lu_table_template(TRAN) {
variable_1 : total_output_net_capacitance;
index_1 ("0.5");
}
power_lut_template(INPUT_BY_TRANS_FOR_CLOCK){
variable_1 : input_transition_time;
index_1 ("0.5");
}
power_lut_template(INPUT_BY_TRANS_FOR_SIGNAL){
variable_1 : input_transition_time;
index_1 ("0.5");
index_1("0.00125, 0.005, 0.04");
index_2("0.00125, 0.005, 0.04");
}
default_operating_conditions : TT;
@ -113,102 +79,126 @@ cell (sram_2_16_1_freepdk45){
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 0.62166;
pin(DATA[1:0]){
}
max_capacitance : 1.6728;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[1:0]){
internal_power(){
when : "OEb & !clk";
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
rise_power(scalar){
values("0");
}
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
fall_power(scalar){
values("0");
}
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
memory_read(){
address : ADDR;
}
internal_power(){
when : "!OEb & !clk";
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
rise_power(scalar){
values("0");
}
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
fall_power(scalar){
values("0");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : rising_edge;
cell_rise(CELL_UP_FOR_CLOCK) {
values("120.044");
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.12, 0.121, 0.131",\
"0.12, 0.121, 0.131",\
"0.12, 0.121, 0.131");
}
cell_fall(CELL_DN_FOR_CLOCK) {
values("120.044");
cell_fall(CELL_TABLE) {
values("0.12, 0.121, 0.131",\
"0.12, 0.121, 0.131",\
"0.12, 0.121, 0.131");
}
rise_transition(TRAN) {
values("120.044");
rise_transition(CELL_TABLE) {
values("0.006, 0.007, 0.018",\
"0.006, 0.007, 0.018",\
"0.006, 0.007, 0.018");
}
fall_transition(TRAN) {
values("120.044");
fall_transition(CELL_TABLE) {
values("0.006, 0.007, 0.018",\
"0.006, 0.007, 0.018",\
"0.006, 0.007, 0.018");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 0.2091;
max_transition : 0.5;
max_transition : 0.04;
fanout_load : 1.000000;
pin(ADDR[3:0]){
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
}
}
pin(CSb){
@ -217,21 +207,29 @@ cell (sram_2_16_1_freepdk45){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
}
@ -242,21 +240,29 @@ cell (sram_2_16_1_freepdk45){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
}
@ -267,21 +273,29 @@ cell (sram_2_16_1_freepdk45){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.015");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("0.009");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("-0.005");
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.011");
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
}
@ -293,20 +307,20 @@ cell (sram_2_16_1_freepdk45){
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(CLK_TRAN) {
rise_constraint(scalar) {
values("0.0");
}
fall_constraint(CLK_TRAN) {
fall_constraint(scalar) {
values("0.0");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(CLK_TRAN) {
rise_constraint(scalar) {
values("0.0");
}
fall_constraint(CLK_TRAN) {
fall_constraint(scalar) {
values("0.0");
}
}

View File

@ -31,52 +31,18 @@ library (sram_2_16_1_scn3me_subm_lib){
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_UP_FOR_CLOCK){
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1 ("0.5");
index_2 ("0.5");
index_1("0.0125, 0.05, 0.4");
index_2("2.45605, 9.8242, 78.5936");
}
lu_table_template(CELL_DN_FOR_CLOCK){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CONSTRAINT_HIGH_POS){
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CONSTRAINT_LOW_POS){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CLK_TRAN) {
variable_1 : constrained_pin_transition;
index_1 ("0.5");
}
lu_table_template(TRAN) {
variable_1 : total_output_net_capacitance;
index_1 ("0.5");
}
power_lut_template(INPUT_BY_TRANS_FOR_CLOCK){
variable_1 : input_transition_time;
index_1 ("0.5");
}
power_lut_template(INPUT_BY_TRANS_FOR_SIGNAL){
variable_1 : input_transition_time;
index_1 ("0.5");
index_1("0.0125, 0.05, 0.4");
index_2("0.0125, 0.05, 0.4");
}
default_operating_conditions : TT;
@ -113,102 +79,126 @@ cell (sram_2_16_1_scn3me_subm){
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 11.3222;
pin(DATA[1:0]){
}
max_capacitance : 78.5936;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[1:0]){
internal_power(){
when : "OEb & !clk";
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("15.6576");
rise_power(scalar){
values("4.5249");
}
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("15.6576");
fall_power(scalar){
values("5.117");
}
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
rise_constraint(CONSTRAINT_TABLE) {
values("0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
fall_constraint(CONSTRAINT_TABLE) {
values("0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
fall_constraint(CONSTRAINT_TABLE) {
values("-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175");
}
}
memory_read(){
address : ADDR;
}
internal_power(){
when : "!OEb & !clk";
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("6.2822");
rise_power(scalar){
values("5.8331");
}
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("6.2822");
fall_power(scalar){
values("5.8513");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : rising_edge;
cell_rise(CELL_UP_FOR_CLOCK) {
values("1.658");
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.262, 0.343, 1.014",\
"0.264, 0.345, 1.018",\
"0.311, 0.389, 1.063");
}
cell_fall(CELL_DN_FOR_CLOCK) {
values("2.364");
cell_fall(CELL_TABLE) {
values("0.836, 0.944, 1.92",\
"0.84, 0.948, 1.924",\
"0.877, 0.985, 1.959");
}
rise_transition(TRAN) {
values("1.658");
rise_transition(CELL_TABLE) {
values("0.209, 0.354, 1.883",\
"0.213, 0.356, 1.882",\
"0.314, 0.361, 1.884");
}
fall_transition(TRAN) {
values("2.364");
fall_transition(CELL_TABLE) {
values("0.236, 0.444, 6.753",\
"0.236, 0.444, 6.724",\
"0.236, 0.444, 6.53");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 9.8242;
max_transition : 0.5;
max_transition : 0.4;
fanout_load : 1.000000;
pin(ADDR[3:0]){
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
rise_constraint(CONSTRAINT_TABLE) {
values("0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
fall_constraint(CONSTRAINT_TABLE) {
values("0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
fall_constraint(CONSTRAINT_TABLE) {
values("-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175");
}
}
}
}
pin(CSb){
@ -217,21 +207,29 @@ cell (sram_2_16_1_scn3me_subm){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
rise_constraint(CONSTRAINT_TABLE) {
values("0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
fall_constraint(CONSTRAINT_TABLE) {
values("0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
fall_constraint(CONSTRAINT_TABLE) {
values("-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175");
}
}
}
@ -242,21 +240,29 @@ cell (sram_2_16_1_scn3me_subm){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
rise_constraint(CONSTRAINT_TABLE) {
values("0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
fall_constraint(CONSTRAINT_TABLE) {
values("0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
fall_constraint(CONSTRAINT_TABLE) {
values("-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175");
}
}
}
@ -267,21 +273,29 @@ cell (sram_2_16_1_scn3me_subm){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
rise_constraint(CONSTRAINT_TABLE) {
values("0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186",\
"0.082, 0.088, 0.186");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
fall_constraint(CONSTRAINT_TABLE) {
values("0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027",\
"0.021, 0.021, 0.027");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021",\
"0.009, 0.015, 0.021");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
fall_constraint(CONSTRAINT_TABLE) {
values("-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175",\
"-0.065, -0.071, -0.175");
}
}
}
@ -293,21 +307,21 @@ cell (sram_2_16_1_scn3me_subm){
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(CLK_TRAN) {
values("2.543");
rise_constraint(scalar) {
values("1.328");
}
fall_constraint(CLK_TRAN) {
values("2.543");
fall_constraint(scalar) {
values("1.328");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(CLK_TRAN) {
values("5.086");
rise_constraint(scalar) {
values("2.656");
}
fall_constraint(CLK_TRAN) {
values("5.086");
fall_constraint(scalar) {
values("2.656");
}
}
}

View File

@ -31,52 +31,18 @@ library (sram_2_16_1_scn3me_subm_lib){
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_UP_FOR_CLOCK){
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1 ("0.5");
index_2 ("0.5");
index_1("0.0125, 0.05, 0.4");
index_2("2.45605, 9.8242, 78.5936");
}
lu_table_template(CELL_DN_FOR_CLOCK){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CONSTRAINT_HIGH_POS){
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CONSTRAINT_LOW_POS){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1 ("0.5");
index_2 ("0.5");
}
lu_table_template(CLK_TRAN) {
variable_1 : constrained_pin_transition;
index_1 ("0.5");
}
lu_table_template(TRAN) {
variable_1 : total_output_net_capacitance;
index_1 ("0.5");
}
power_lut_template(INPUT_BY_TRANS_FOR_CLOCK){
variable_1 : input_transition_time;
index_1 ("0.5");
}
power_lut_template(INPUT_BY_TRANS_FOR_SIGNAL){
variable_1 : input_transition_time;
index_1 ("0.5");
index_1("0.0125, 0.05, 0.4");
index_2("0.0125, 0.05, 0.4");
}
default_operating_conditions : TT;
@ -113,102 +79,126 @@ cell (sram_2_16_1_scn3me_subm){
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 11.3222;
pin(DATA[1:0]){
}
max_capacitance : 78.5936;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[1:0]){
internal_power(){
when : "OEb & !clk";
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
rise_power(scalar){
values("0");
}
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
fall_power(scalar){
values("0");
}
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
memory_read(){
address : ADDR;
}
internal_power(){
when : "!OEb & !clk";
rise_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
rise_power(scalar){
values("0");
}
fall_power(INPUT_BY_TRANS_FOR_SIGNAL){
values("0.0");
fall_power(scalar){
values("0");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : rising_edge;
cell_rise(CELL_UP_FOR_CLOCK) {
values("553.907");
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.57, 0.617, 1.058",\
"0.57, 0.617, 1.058",\
"0.57, 0.617, 1.058");
}
cell_fall(CELL_DN_FOR_CLOCK) {
values("553.907");
cell_fall(CELL_TABLE) {
values("0.57, 0.617, 1.058",\
"0.57, 0.617, 1.058",\
"0.57, 0.617, 1.058");
}
rise_transition(TRAN) {
values("553.907");
rise_transition(CELL_TABLE) {
values("0.024, 0.081, 0.61",\
"0.024, 0.081, 0.61",\
"0.024, 0.081, 0.61");
}
fall_transition(TRAN) {
values("553.907");
fall_transition(CELL_TABLE) {
values("0.024, 0.081, 0.61",\
"0.024, 0.081, 0.61",\
"0.024, 0.081, 0.61");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 9.8242;
max_transition : 0.5;
max_transition : 0.4;
fanout_load : 1.000000;
pin(ADDR[3:0]){
}
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
}
}
pin(CSb){
@ -217,21 +207,29 @@ cell (sram_2_16_1_scn3me_subm){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
}
@ -242,21 +240,29 @@ cell (sram_2_16_1_scn3me_subm){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
}
@ -267,21 +273,29 @@ cell (sram_2_16_1_scn3me_subm){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.093");
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.024");
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_HIGH_POS) {
values("0.046");
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_LOW_POS) {
values("-0.083");
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
}
@ -293,20 +307,20 @@ cell (sram_2_16_1_scn3me_subm){
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(CLK_TRAN) {
rise_constraint(scalar) {
values("0.0");
}
fall_constraint(CLK_TRAN) {
fall_constraint(scalar) {
values("0.0");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(CLK_TRAN) {
rise_constraint(scalar) {
values("0.0");
}
fall_constraint(CLK_TRAN) {
fall_constraint(scalar) {
values("0.0");
}
}

View File

@ -59,24 +59,24 @@ def isapproxdiff(f1, f2, error_tolerance=0.001):
# 2. Remove the floats from the string
for f in b1_floats:
b1=b1.replace(str(f),"")
b1=b1.replace(str(f),"",1)
for f in b2_floats:
b2=b2.replace(str(f),"")
b2=b2.replace(str(f),"",1)
#print "b1:",b1,
#print "b2:",b2,
# 3. Check if remaining string matches
if b1 != b2:
debug.info(2,"Line: {0}\n!=\nLine: {1}".format(b1,b2))
debug.info(1,"Line: {0}\n!=\nLine: {1}".format(b1,b2))
return False
# 4. Now compare that the floats match
if len(b1_floats)!=len(b2_floats):
debug.info(2,"Len {0} != {1}".format(len(b1_floats),len(b2_floats)))
debug.info(1,"Len {0} != {1}".format(len(b1_floats),len(b2_floats)))
return False
for (f1,f2) in zip(b1_floats,b2_floats):
if not relative_compare(float(f1),float(f2),error_tolerance):
debug.info(2, "Float {0} != {1}".format(f1,f2))
debug.info(1, "Float {0} != {1}".format(f1,f2))
return False
if not b1:

View File

@ -21,11 +21,11 @@ class tri_gate(design.design):
self.width = tri_gate.chars["width"]
self.height = tri_gate.chars["height"]
def delay(self, slope, load=0.0):
def delay(self, slew, load=0.0):
from tech import spice
r = spice["min_tx_r"]
c_para = spice["min_tx_c_para"]#ff
return self.cal_delay_with_rc(r = r, c = c_para+load, slope =slope)
c_para = spice["min_tx_drain_c"]
return self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew)
def input_load(self):

View File

@ -35,9 +35,9 @@ class tri_gate_array(design.design):
def add_pins(self):
"""create the name of pins depend on the word size"""
for i in range(self.word_size):
self.add_pin("tri_in[{0}]".format(i))
self.add_pin("IN[{0}]".format(i))
for i in range(self.word_size):
self.add_pin("DATA[{0}]".format(i))
self.add_pin("OUT[{0}]".format(i))
for pin in ["en", "en_bar", "vdd", "gnd"]:
self.add_pin(pin)
@ -49,8 +49,8 @@ class tri_gate_array(design.design):
self.tri_gate_positions = []
self.vdd_positions = []
self.gnd_positions = []
self.tri_in_positions = []
self.DATA_positions = []
self.in_positions = []
self.out_positions = []
def add_modules(self):
"""instantiation of a tri gate"""
@ -75,8 +75,8 @@ class tri_gate_array(design.design):
mod=self.tri,
offset=[x_off, 0],
mirror = mirror)
self.connect_inst(["tri_in[{0}]".format(i),
"DATA[{0}]".format(i),
self.connect_inst(["in[{0}]".format(i),
"out[{0}]".format(i),
"en", "en_bar", "vdd", "gnd"])
def add_metal_rails(self):
@ -118,20 +118,18 @@ class tri_gate_array(design.design):
self.add_label(text="gnd",
layer="metal2",
offset=pin_offset["gnd"])
self.add_label(text="tri_in[{0}]".format(i),
self.add_label(text="in[{0}]".format(i),
layer="metal2",
offset=pin_offset["in"])
self.add_label(text="DATA[{0}]".format(i),
self.add_label(text="out[{0}]".format(i),
layer="metal2",
offset=pin_offset["out"])
self.vdd_positions.append(pin_offset["vdd"])
self.gnd_positions.append(pin_offset["gnd"])
self.tri_in_positions.append(pin_offset["in"])
self.DATA_positions.append(pin_offset["out"])
self.in_positions.append(pin_offset["in"])
self.out_positions.append(pin_offset["out"])
def delay(self, slope, load=0.0):
result = self.tri.delay(slope = slope,
load = load)
def delay(self, slew, load=0.0):
result = self.tri.delay(slew = slew, load = load)
return result

View File

@ -210,12 +210,12 @@ class wordline_driver(design.design):
self.vdd_positions.append(vdd_offset)
self.gnd_positions.append(gnd_offset)
def delay(self, slope, load=0):
def delay(self, slew, load=0):
# decode_out -> net
decode_t_net = self.NAND2.delay(slope = slope, load = self.inv.input_load())
decode_t_net = self.NAND2.delay(slew, self.inv.input_load())
# net -> wl
net_t_wl = self.inv.delay(slope = decode_t_net.slope, load = load)
net_t_wl = self.inv.delay(decode_t_net.slew, load)
result = decode_t_net + net_t_wl
return result

View File

@ -260,11 +260,11 @@ spice["fet_models"] = [SPICE_MODEL_DIR+"/NMOS_VTG.inc",
SPICE_MODEL_DIR+"/PMOS_VTG.inc"]
#spice stimulus related variables
spice["clock_period"] = 2.0
spice["feasible_period"] = 5 # estimated feasible period in ns
spice["supply_voltage"] = 1.0 #vdd in [Volts]
spice["gnd_voltage"] = 0.0 #gnd in [Volts]
spice["rise_time"] = 0.001 #rise time in [Nano-seconds]
spice["fall_time"] = 0.001 #fall time in [Nano-seconds]
spice["rise_time"] = 0.005 #rise time in [Nano-seconds]
spice["fall_time"] = 0.005 #fall time in [Nano-seconds]
spice["temp"] = 25 #temperature in [Celsius]
#parasitics of metal for bit/word lines
@ -272,8 +272,8 @@ spice["bitline_res"] = 0.1 #bitline resistance in [Ohms/micro-meter]
spice["bitline_cap"] = 0.2 #bitline capacitance in [Femto-farad/micro-meter]
spice["wordline_res"] = 0.1 #wordline resistance in [Ohms/micro-meter]
spice["wordline_cap"] = 0.2 #wordline capacitance in [Femto-farad/micro-meter]
spice["FF_in_cap"] = 0.2091 #Input capacitance of ms_flop (Din) [Femto-farad]
spice["tri_gate_out_cap"] = 0.41256 #Output capacitance of tri_gate (tri_out) [Femto-farad]
spice["FF_in_cap"] = 0.2091 #Input capacitance of ms_flop (Din) [Femto-farad]
spice["tri_gate_out_cap"] = 0.41256 #Output capacitance of tri_gate (tri_out) [Femto-farad]
#sram signal names
@ -288,14 +288,13 @@ spice["minwidth_tx"] = drc["minwidth_tx"]
spice["channel"] = drc["minlength_channel"]
spice["clk"] = "clk"
# estimated feasible period in ns
spice["feasible_period"] = 5
# analytical delay parameter
spice["wire_unit_r"] = 0.075 #ohm
spice["wire_unit_c"] = 0.64 #ff/um^2
spice["min_tx_r"] = 9250.0
spice["min_tx_c_para"] = 0.7 #ff
spice["min_tx_gate_c"] = 0.2
spice["msflop_delay"] = 20.5171565446#ps
spice["msflop_slope"] = 13.0801872972#ps
# analytical delay parameters
spice["wire_unit_r"] = 0.075 # Unit wire resistance in ohms/square
spice["wire_unit_c"] = 0.64 # Unit wire capacitance ff/um^2
spice["min_tx_r"] = 9250.0 # Minimum transistor on resistance in ohms
spice["min_tx_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff
spice["min_tx_gate_c"] = 0.2 # Minimum transistor gate capacitance in ff
spice["msflop_setup"] = 9 # DFF setup time in ps
spice["msflop_hold"] = 1 # DFF hold time in ps
spice["msflop_delay"] = 20.5 # DFF Clk-to-q delay in ps
spice["msflop_slew"] = 13.1 # DFF output slew in ps w/ no load

View File

@ -178,11 +178,11 @@ spice["pmos"]="p"
spice["fet_models"] = [os.environ.get("SPICE_MODEL_DIR")+"/on_c5n.sp"]
#spice stimulus related variables
spice["clock_period"] = 10.0
spice["feasible_period"] = 5 # estimated feasible period in ns
spice["supply_voltage"] = 5.0 #vdd in [Volts]
spice["gnd_voltage"] = 0.0 #gnd in [Volts]
spice["rise_time"] = 0.001 #rise time in [Nano-seconds]
spice["fall_time"] = 0.001 #fall time in [Nano-seconds]
spice["rise_time"] = 0.05 #rise time in [Nano-seconds]
spice["fall_time"] = 0.05 #fall time in [Nano-seconds]
spice["temp"] = 25 #temperature in [Celsius]
#parasitics of metal for bit/word lines
@ -190,8 +190,8 @@ spice["bitline_res"] = 0.1 #bitline resistance in [Ohms/micro-meter]
spice["bitline_cap"] = 0.2 #bitline capacitance in [Femto-farad/micro-meter]
spice["wordline_res"] = 0.1 #wordline resistance in [Ohms/micro-meter]
spice["wordline_cap"] = 0.2 #wordline capacitance in [Femto-farad/micro-meter]
spice["FF_in_cap"] = 9.8242 #Input capacitance of ms_flop (Din) [Femto-farad]
spice["tri_gate_out_cap"] = 1.4980 #Output capacitance of tri_gate (tri_out) [Femto-farad]
spice["FF_in_cap"] = 9.8242 #Input capacitance of ms_flop (Din) [Femto-farad]
spice["tri_gate_out_cap"] = 1.4980 #Output capacitance of tri_gate (tri_out) [Femto-farad]
#sram signal names
@ -206,16 +206,15 @@ spice["minwidth_tx"] = drc["minwidth_tx"]
spice["channel"] = drc["minlength_channel"]
spice["clk"] = "clk"
# estimated feasible period in ns
spice["feasible_period"] = 5
# analytical delay parameters
# FIXME: These need to be updated for SCMOS, they are copied from FreePDK45.
spice["wire_unit_r"] = 0.075 # Unit wire resistance in ohms/square
spice["wire_unit_c"] = 0.64 # Unit wire capacitance ff/um^2
spice["min_tx_r"] = 9250.0 # Minimum transistor on resistance in ohms
spice["min_tx_drain_c"] = 0.7 # Minimum transistor drain capacitance in ff
spice["min_tx_gate_c"] = 0.1 # Minimum transistor gate capacitance in ff
spice["msflop_setup"] = 9 # DFF setup time in ps
spice["msflop_hold"] = 1 # DFF hold time in ps
spice["msflop_delay"] = 20.5 # DFF Clk-to-q delay in ps
spice["msflop_slew"] = 13.1 # DFF output slew in ps w/ no load
# analytical delay parameter
# these numbers are copied from freepdk
# need to measure them in scn cmos
spice["wire_unit_r"] = 0.075 #ohm
spice["wire_unit_c"] = 0.64 #ff/um^2
spice["min_tx_r"] = 9250.0
spice["min_tx_c_para"] = 0.7 #ff
spice["min_tx_gate_c"] = 0.1
spice["msflop_delay"] = 20.5171565446#ps
spice["msflop_slope"] = 13.0801872972#ps