mirror of https://github.com/VLSIDA/OpenRAM.git
Improved characterizer.
This commit is contained in:
parent
e92cb9ecef
commit
20d8c0bc45
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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():
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue