mirror of https://github.com/VLSIDA/OpenRAM.git
Mostly formatting. Added write measurements.
This commit is contained in:
parent
3df8abd38c
commit
9cb96bda7d
|
|
@ -52,7 +52,7 @@ class delay(simulation):
|
||||||
self.add_graph_exclusions()
|
self.add_graph_exclusions()
|
||||||
|
|
||||||
def create_measurement_names(self):
|
def create_measurement_names(self):
|
||||||
"""Create measurement names. The names themselves currently define the type of measurement"""
|
""" Create measurement names. The names themselves currently define the type of measurement """
|
||||||
|
|
||||||
self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"]
|
self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"]
|
||||||
self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"]
|
self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"]
|
||||||
|
|
@ -60,14 +60,17 @@ class delay(simulation):
|
||||||
# self.bitline_delay_names = ["delay_bl", "delay_br"]
|
# self.bitline_delay_names = ["delay_bl", "delay_br"]
|
||||||
|
|
||||||
def create_measurement_objects(self):
|
def create_measurement_objects(self):
|
||||||
"""Create the measurements used for read and write ports"""
|
""" Create the measurements used for read and write ports """
|
||||||
|
|
||||||
self.read_meas_lists = self.create_read_port_measurement_objects()
|
self.read_meas_lists = self.create_read_port_measurement_objects()
|
||||||
self.write_meas_lists = self.create_write_port_measurement_objects()
|
self.write_meas_lists = self.create_write_port_measurement_objects()
|
||||||
self.check_meas_names(self.read_meas_lists+self.write_meas_lists)
|
self.check_meas_names(self.read_meas_lists+self.write_meas_lists)
|
||||||
|
|
||||||
def check_meas_names(self, measures_lists):
|
def check_meas_names(self, measures_lists):
|
||||||
"""Given measurements (in 2d list), checks that their names are unique.
|
"""
|
||||||
Spice sim will fail otherwise."""
|
Given measurements (in 2d list), checks that their names are unique.
|
||||||
|
Spice sim will fail otherwise.
|
||||||
|
"""
|
||||||
name_set = set()
|
name_set = set()
|
||||||
for meas_list in measures_lists:
|
for meas_list in measures_lists:
|
||||||
for meas in meas_list:
|
for meas in meas_list:
|
||||||
|
|
@ -121,6 +124,7 @@ class delay(simulation):
|
||||||
unique error checking, these are separated from other measurements.
|
unique error checking, these are separated from other measurements.
|
||||||
These measurements are only associated with read values.
|
These measurements are only associated with read values.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.bitline_volt_meas = []
|
self.bitline_volt_meas = []
|
||||||
|
|
||||||
self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ZERO",
|
self.bitline_volt_meas.append(voltage_at_measure("v_bl_READ_ZERO",
|
||||||
|
|
@ -140,6 +144,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def create_write_port_measurement_objects(self):
|
def create_write_port_measurement_objects(self):
|
||||||
"""Create the measurements used for read ports: delays, slews, powers"""
|
"""Create the measurements used for read ports: delays, slews, powers"""
|
||||||
|
|
||||||
self.write_lib_meas = []
|
self.write_lib_meas = []
|
||||||
|
|
||||||
self.write_lib_meas.append(power_measure("write1_power", "RISE", measure_scale=1e3))
|
self.write_lib_meas.append(power_measure("write1_power", "RISE", measure_scale=1e3))
|
||||||
|
|
@ -149,10 +154,12 @@ class delay(simulation):
|
||||||
|
|
||||||
write_measures = []
|
write_measures = []
|
||||||
write_measures.append(self.write_lib_meas)
|
write_measures.append(self.write_lib_meas)
|
||||||
|
write_measures.append(self.create_write_bit_measures())
|
||||||
return write_measures
|
return write_measures
|
||||||
|
|
||||||
def create_debug_measurement_objects(self):
|
def create_debug_measurement_objects(self):
|
||||||
"""Create debug measurement to help identify failures."""
|
"""Create debug measurement to help identify failures."""
|
||||||
|
|
||||||
self.debug_volt_meas = []
|
self.debug_volt_meas = []
|
||||||
for meas in self.delay_meas:
|
for meas in self.delay_meas:
|
||||||
# Output voltage measures
|
# Output voltage measures
|
||||||
|
|
@ -167,7 +174,8 @@ class delay(simulation):
|
||||||
return self.debug_volt_meas+[self.sen_meas]
|
return self.debug_volt_meas+[self.sen_meas]
|
||||||
|
|
||||||
def create_read_bit_measures(self):
|
def create_read_bit_measures(self):
|
||||||
"""Adds bit measurements for read0 and read1 cycles"""
|
""" Adds bit measurements for read0 and read1 cycles """
|
||||||
|
|
||||||
self.bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]}
|
self.bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]}
|
||||||
meas_cycles = (sram_op.READ_ZERO, sram_op.READ_ONE)
|
meas_cycles = (sram_op.READ_ZERO, sram_op.READ_ONE)
|
||||||
for cycle in meas_cycles:
|
for cycle in meas_cycles:
|
||||||
|
|
@ -178,10 +186,27 @@ class delay(simulation):
|
||||||
self.bit_meas[polarity].append(meas)
|
self.bit_meas[polarity].append(meas)
|
||||||
# Dictionary values are lists, reduce to a single list of measurements
|
# Dictionary values are lists, reduce to a single list of measurements
|
||||||
return [meas for meas_list in self.bit_meas.values() for meas in meas_list]
|
return [meas for meas_list in self.bit_meas.values() for meas in meas_list]
|
||||||
|
|
||||||
|
def create_write_bit_measures(self):
|
||||||
|
""" Adds bit measurements for write0 and write1 cycles """
|
||||||
|
|
||||||
|
self.bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]}
|
||||||
|
meas_cycles = (sram_op.WRITE_ZERO, sram_op.WRITE_ONE)
|
||||||
|
for cycle in meas_cycles:
|
||||||
|
meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name)
|
||||||
|
single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data)
|
||||||
|
for polarity,meas in single_bit_meas.items():
|
||||||
|
meas.meta_str = cycle
|
||||||
|
self.bit_meas[polarity].append(meas)
|
||||||
|
# Dictionary values are lists, reduce to a single list of measurements
|
||||||
|
return [meas for meas_list in self.bit_meas.values() for meas in meas_list]
|
||||||
|
|
||||||
def get_bit_measures(self, meas_tag, probe_address, probe_data):
|
def get_bit_measures(self, meas_tag, probe_address, probe_data):
|
||||||
"""Creates measurements for the q/qbar of input bit position.
|
"""
|
||||||
meas_tag is a unique identifier for the measurement."""
|
Creates measurements for the q/qbar of input bit position.
|
||||||
|
meas_tag is a unique identifier for the measurement.
|
||||||
|
"""
|
||||||
|
|
||||||
bit_col = self.get_data_bit_column_number(probe_address, probe_data)
|
bit_col = self.get_data_bit_column_number(probe_address, probe_data)
|
||||||
bit_row = self.get_address_row_number(probe_address)
|
bit_row = self.get_address_row_number(probe_address)
|
||||||
(cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, bit_row, bit_col)
|
(cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, bit_row, bit_col)
|
||||||
|
|
@ -190,6 +215,7 @@ class delay(simulation):
|
||||||
"supported for characterization. Storage nets={}").format(storage_names))
|
"supported for characterization. Storage nets={}").format(storage_names))
|
||||||
q_name = cell_name+'.'+str(storage_names[0])
|
q_name = cell_name+'.'+str(storage_names[0])
|
||||||
qbar_name = cell_name+'.'+str(storage_names[1])
|
qbar_name = cell_name+'.'+str(storage_names[1])
|
||||||
|
|
||||||
# Bit measures, measurements times to be defined later. The measurement names must be unique
|
# Bit measures, measurements times to be defined later. The measurement names must be unique
|
||||||
# but they is enforced externally
|
# but they is enforced externally
|
||||||
q_meas = voltage_at_measure("v_q_{}".format(meas_tag), q_name, has_port=False)
|
q_meas = voltage_at_measure("v_q_{}".format(meas_tag), q_name, has_port=False)
|
||||||
|
|
@ -199,11 +225,13 @@ class delay(simulation):
|
||||||
|
|
||||||
def set_load_slew(self,load,slew):
|
def set_load_slew(self,load,slew):
|
||||||
""" Set the load and slew """
|
""" Set the load and slew """
|
||||||
|
|
||||||
self.load = load
|
self.load = load
|
||||||
self.slew = slew
|
self.slew = slew
|
||||||
|
|
||||||
def add_graph_exclusions(self):
|
def add_graph_exclusions(self):
|
||||||
"""Exclude portions of SRAM from timing graph which are not relevant"""
|
"""Exclude portions of SRAM from timing graph which are not relevant"""
|
||||||
|
|
||||||
# other initializations can only be done during analysis when a bit has been selected
|
# other initializations can only be done during analysis when a bit has been selected
|
||||||
# for testing.
|
# for testing.
|
||||||
self.sram.bank.graph_exclude_precharge()
|
self.sram.bank.graph_exclude_precharge()
|
||||||
|
|
@ -214,6 +242,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def create_graph(self):
|
def create_graph(self):
|
||||||
"""Creates timing graph to generate the timing paths for the SRAM output."""
|
"""Creates timing graph to generate the timing paths for the SRAM output."""
|
||||||
|
|
||||||
self.sram.bank.bitcell_array.init_graph_params() # Removes previous bit exclusions
|
self.sram.bank.bitcell_array.init_graph_params() # Removes previous bit exclusions
|
||||||
self.sram.bank.bitcell_array.graph_exclude_bits(self.wordline_row, self.bitline_column)
|
self.sram.bank.bitcell_array.graph_exclude_bits(self.wordline_row, self.bitline_column)
|
||||||
|
|
||||||
|
|
@ -224,6 +253,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def set_internal_spice_names(self):
|
def set_internal_spice_names(self):
|
||||||
"""Sets important names for characterization such as Sense amp enable and internal bit nets."""
|
"""Sets important names for characterization such as Sense amp enable and internal bit nets."""
|
||||||
|
|
||||||
port = 0
|
port = 0
|
||||||
self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port), \
|
self.graph.get_all_paths('{}{}'.format(tech.spice["clk"], port), \
|
||||||
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
|
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
|
||||||
|
|
@ -233,10 +263,13 @@ class delay(simulation):
|
||||||
|
|
||||||
self.bl_name,self.br_name = self.get_bl_name(self.graph.all_paths)
|
self.bl_name,self.br_name = self.get_bl_name(self.graph.all_paths)
|
||||||
debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name))
|
debug.info(2,"bl name={}, br name={}".format(self.bl_name,self.br_name))
|
||||||
|
|
||||||
def get_sen_name(self, paths):
|
def get_sen_name(self, paths):
|
||||||
"""Gets the signal name associated with the sense amp enable from input paths.
|
"""
|
||||||
Only expects a single path to contain the sen signal name."""
|
Gets the signal name associated with the sense amp enable from input paths.
|
||||||
|
Only expects a single path to contain the sen signal name.
|
||||||
|
"""
|
||||||
|
|
||||||
sa_mods = factory.get_mods(OPTS.sense_amp)
|
sa_mods = factory.get_mods(OPTS.sense_amp)
|
||||||
# Any sense amp instantiated should be identical, any change to that
|
# Any sense amp instantiated should be identical, any change to that
|
||||||
# will require some identification to determine the mod desired.
|
# will require some identification to determine the mod desired.
|
||||||
|
|
@ -247,6 +280,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def get_bl_name(self, paths):
|
def get_bl_name(self, paths):
|
||||||
"""Gets the signal name associated with the bitlines in the bank."""
|
"""Gets the signal name associated with the bitlines in the bank."""
|
||||||
|
|
||||||
cell_mods = factory.get_mods(OPTS.bitcell)
|
cell_mods = factory.get_mods(OPTS.bitcell)
|
||||||
if len(cell_mods)>=1:
|
if len(cell_mods)>=1:
|
||||||
cell_mod = self.get_primary_cell_mod(cell_mods)
|
cell_mod = self.get_primary_cell_mod(cell_mods)
|
||||||
|
|
@ -264,16 +298,20 @@ class delay(simulation):
|
||||||
bl_names.append(self.get_alias_in_path(paths, int_net, cell_mod, exclude_set))
|
bl_names.append(self.get_alias_in_path(paths, int_net, cell_mod, exclude_set))
|
||||||
|
|
||||||
return bl_names[0], bl_names[1]
|
return bl_names[0], bl_names[1]
|
||||||
|
|
||||||
|
|
||||||
def get_bl_name_search_exclusions(self):
|
def get_bl_name_search_exclusions(self):
|
||||||
"""Gets the mods as a set which should be excluded while searching for name."""
|
"""Gets the mods as a set which should be excluded while searching for name."""
|
||||||
|
|
||||||
# Exclude the RBL as it contains bitcells which are not in the main bitcell array
|
# Exclude the RBL as it contains bitcells which are not in the main bitcell array
|
||||||
# so it makes the search awkward
|
# so it makes the search awkward
|
||||||
return set(factory.get_mods(OPTS.replica_bitline))
|
return set(factory.get_mods(OPTS.replica_bitline))
|
||||||
|
|
||||||
def get_primary_cell_mod(self, cell_mods):
|
def get_primary_cell_mod(self, cell_mods):
|
||||||
"""Distinguish bitcell array mod from replica bitline array.
|
"""
|
||||||
Assume there are no replica bitcells in the primary array."""
|
Distinguish bitcell array mod from replica bitline array.
|
||||||
|
Assume there are no replica bitcells in the primary array.
|
||||||
|
"""
|
||||||
if len(cell_mods) == 1:
|
if len(cell_mods) == 1:
|
||||||
return cell_mods[0]
|
return cell_mods[0]
|
||||||
rbc_mods = factory.get_mods(OPTS.replica_bitcell)
|
rbc_mods = factory.get_mods(OPTS.replica_bitcell)
|
||||||
|
|
@ -290,6 +328,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def are_mod_pins_equal(self, mods):
|
def are_mod_pins_equal(self, mods):
|
||||||
"""Determines if there are pins differences in the input mods"""
|
"""Determines if there are pins differences in the input mods"""
|
||||||
|
|
||||||
if len(mods) == 0:
|
if len(mods) == 0:
|
||||||
return True
|
return True
|
||||||
pins = mods[0].pins
|
pins = mods[0].pins
|
||||||
|
|
@ -299,8 +338,11 @@ class delay(simulation):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_alias_in_path(self, paths, int_net, mod, exclusion_set=None):
|
def get_alias_in_path(self, paths, int_net, mod, exclusion_set=None):
|
||||||
"""Finds a single alias for the int_net in given paths.
|
"""
|
||||||
More or less hits cause an error"""
|
Finds a single alias for the int_net in given paths.
|
||||||
|
More or less hits cause an error
|
||||||
|
"""
|
||||||
|
|
||||||
net_found = False
|
net_found = False
|
||||||
for path in paths:
|
for path in paths:
|
||||||
aliases = self.sram.find_aliases(self.sram_spc_name, self.pins, path, int_net, mod, exclusion_set)
|
aliases = self.sram.find_aliases(self.sram_spc_name, self.pins, path, int_net, mod, exclusion_set)
|
||||||
|
|
@ -318,6 +360,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def check_arguments(self):
|
def check_arguments(self):
|
||||||
"""Checks if arguments given for write_stimulus() meets requirements"""
|
"""Checks if arguments given for write_stimulus() meets requirements"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
int(self.probe_address, 2)
|
int(self.probe_address, 2)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|
@ -353,10 +396,12 @@ class delay(simulation):
|
||||||
|
|
||||||
|
|
||||||
def write_delay_stimulus(self):
|
def write_delay_stimulus(self):
|
||||||
""" Creates a stimulus file for simulations to probe a bitcell at a given clock period.
|
"""
|
||||||
|
Creates a stimulus file for simulations to probe a bitcell at a given clock period.
|
||||||
Address and bit were previously set with set_probe().
|
Address and bit were previously set with set_probe().
|
||||||
Input slew (in ns) and output capacitive load (in fF) are required for charaterization.
|
Input slew (in ns) and output capacitive load (in fF) are required for charaterization.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.check_arguments()
|
self.check_arguments()
|
||||||
|
|
||||||
# obtains list of time-points for each rising clk edge
|
# obtains list of time-points for each rising clk edge
|
||||||
|
|
@ -452,7 +497,11 @@ class delay(simulation):
|
||||||
self.sf.close()
|
self.sf.close()
|
||||||
|
|
||||||
def get_read_measure_variants(self, port, measure_obj):
|
def get_read_measure_variants(self, port, measure_obj):
|
||||||
"""Checks the measurement object and calls respective function for related measurement inputs."""
|
"""
|
||||||
|
Checks the measurement object and calls respective function for
|
||||||
|
related measurement inputs.
|
||||||
|
"""
|
||||||
|
|
||||||
meas_type = type(measure_obj)
|
meas_type = type(measure_obj)
|
||||||
if meas_type is delay_measure or meas_type is slew_measure:
|
if meas_type is delay_measure or meas_type is slew_measure:
|
||||||
variant_tuple = self.get_delay_measure_variants(port, measure_obj)
|
variant_tuple = self.get_delay_measure_variants(port, measure_obj)
|
||||||
|
|
@ -472,7 +521,11 @@ class delay(simulation):
|
||||||
return variant_tuple
|
return variant_tuple
|
||||||
|
|
||||||
def get_delay_measure_variants(self, port, delay_obj):
|
def get_delay_measure_variants(self, port, delay_obj):
|
||||||
"""Get the measurement values that can either vary from simulation to simulation (vdd, address) or port to port (time delays)"""
|
"""
|
||||||
|
Get the measurement values that can either vary from simulation to
|
||||||
|
simulation (vdd, address) or port to port (time delays)
|
||||||
|
"""
|
||||||
|
|
||||||
# Return value is intended to match the delay measure format: trig_td, targ_td, vdd, port
|
# Return value is intended to match the delay measure format: trig_td, targ_td, vdd, port
|
||||||
# vdd is arguably constant as that is true for a single lib file.
|
# vdd is arguably constant as that is true for a single lib file.
|
||||||
if delay_obj.meta_str == sram_op.READ_ZERO:
|
if delay_obj.meta_str == sram_op.READ_ZERO:
|
||||||
|
|
@ -491,6 +544,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def get_power_measure_variants(self, port, power_obj, operation):
|
def get_power_measure_variants(self, port, power_obj, operation):
|
||||||
"""Get the measurement values that can either vary port to port (time delays)"""
|
"""Get the measurement values that can either vary port to port (time delays)"""
|
||||||
|
|
||||||
# Return value is intended to match the power measure format: t_initial, t_final, port
|
# Return value is intended to match the power measure format: t_initial, t_final, port
|
||||||
t_initial = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]]
|
t_initial = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]]
|
||||||
t_final = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]+1]
|
t_final = self.cycle_times[self.measure_cycles[port][power_obj.meta_str]+1]
|
||||||
|
|
@ -498,21 +552,21 @@ class delay(simulation):
|
||||||
return (t_initial, t_final, port)
|
return (t_initial, t_final, port)
|
||||||
|
|
||||||
def get_volt_at_measure_variants(self, port, volt_meas):
|
def get_volt_at_measure_variants(self, port, volt_meas):
|
||||||
"""Get the measurement values that can either vary port to port (time delays)"""
|
"""
|
||||||
# Only checking 0 value reads for now.
|
Get the measurement values that can either vary port to port (time delays)
|
||||||
if volt_meas.meta_str == sram_op.READ_ZERO:
|
"""
|
||||||
# Falling delay are measured starting from neg. clk edge. Delay adjusted to that.
|
|
||||||
meas_cycle = self.cycle_times[self.measure_cycles[port][volt_meas.meta_str]]
|
meas_cycle = self.cycle_times[self.measure_cycles[port][volt_meas.meta_str]]
|
||||||
elif volt_meas.meta_str == sram_op.READ_ONE:
|
|
||||||
meas_cycle = self.cycle_times[self.measure_cycles[port][volt_meas.meta_str]]
|
|
||||||
else:
|
|
||||||
debug.error("Unrecognised delay Index={}".format(volt_meas.meta_str),1)
|
|
||||||
# Measurement occurs at the end of the period -> current period start + period
|
# Measurement occurs at the end of the period -> current period start + period
|
||||||
at_time = meas_cycle+self.period
|
at_time = meas_cycle+self.period
|
||||||
return (at_time, port)
|
return (at_time, port)
|
||||||
|
|
||||||
def get_volt_when_measure_variants(self, port, volt_meas):
|
def get_volt_when_measure_variants(self, port, volt_meas):
|
||||||
"""Get the measurement values that can either vary port to port (time delays)"""
|
"""
|
||||||
|
Get the measurement values that can either vary port to port (time delays)
|
||||||
|
"""
|
||||||
|
|
||||||
# Only checking 0 value reads for now.
|
# Only checking 0 value reads for now.
|
||||||
t_trig = meas_cycle_delay = self.cycle_times[self.measure_cycles[port][sram_op.READ_ZERO]]
|
t_trig = meas_cycle_delay = self.cycle_times[self.measure_cycles[port][sram_op.READ_ZERO]]
|
||||||
|
|
||||||
|
|
@ -522,6 +576,7 @@ class delay(simulation):
|
||||||
"""
|
"""
|
||||||
Write the measure statements to quantify the delay and power results for a read port.
|
Write the measure statements to quantify the delay and power results for a read port.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# add measure statements for delays/slews
|
# add measure statements for delays/slews
|
||||||
for meas_list in self.read_meas_lists:
|
for meas_list in self.read_meas_lists:
|
||||||
for measure in meas_list:
|
for measure in meas_list:
|
||||||
|
|
@ -529,17 +584,31 @@ class delay(simulation):
|
||||||
measure.write_measure(self.stim, measure_variant_inp_tuple)
|
measure.write_measure(self.stim, measure_variant_inp_tuple)
|
||||||
|
|
||||||
def get_write_measure_variants(self, port, measure_obj):
|
def get_write_measure_variants(self, port, measure_obj):
|
||||||
"""Checks the measurement object and calls respective function for related measurement inputs."""
|
"""
|
||||||
|
Checks the measurement object and calls respective function for related measurement inputs.
|
||||||
|
"""
|
||||||
|
|
||||||
meas_type = type(measure_obj)
|
meas_type = type(measure_obj)
|
||||||
if meas_type is power_measure:
|
if meas_type is power_measure:
|
||||||
return self.get_power_measure_variants(port, measure_obj, "write")
|
return self.get_power_measure_variants(port, measure_obj, "write")
|
||||||
|
elif meas_type is voltage_at_measure:
|
||||||
|
variant_tuple = self.get_volt_at_measure_variants(port, measure_obj)
|
||||||
else:
|
else:
|
||||||
debug.error("Input function not defined for measurement type={}".format(meas_type))
|
debug.error("Input function not defined for measurement type={}".format(meas_type))
|
||||||
|
|
||||||
|
# Removes port input from any object which does not use it. This shorthand only works if
|
||||||
|
# the measurement has port as the last input. Could be implemented by measurement type or
|
||||||
|
# remove entirely from measurement classes.
|
||||||
|
if not measure_obj.has_port:
|
||||||
|
variant_tuple = variant_tuple[:-1]
|
||||||
|
return variant_tuple
|
||||||
|
|
||||||
|
|
||||||
def write_delay_measures_write_port(self, port):
|
def write_delay_measures_write_port(self, port):
|
||||||
"""
|
"""
|
||||||
Write the measure statements to quantify the power results for a write port.
|
Write the measure statements to quantify the power results for a write port.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# add measure statements for power
|
# add measure statements for power
|
||||||
for meas_list in self.write_meas_lists:
|
for meas_list in self.write_meas_lists:
|
||||||
for measure in meas_list:
|
for measure in meas_list:
|
||||||
|
|
@ -550,17 +619,22 @@ class delay(simulation):
|
||||||
"""
|
"""
|
||||||
Write the measure statements to quantify the delay and power results for all targeted ports.
|
Write the measure statements to quantify the delay and power results for all targeted ports.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.sf.write("\n* Measure statements for delay and power\n")
|
self.sf.write("\n* Measure statements for delay and power\n")
|
||||||
|
|
||||||
# Output some comments to aid where cycles start and
|
# Output some comments to aid where cycles start and
|
||||||
# what is happening
|
# what is happening
|
||||||
for comment in self.cycle_comments:
|
for comment in self.cycle_comments:
|
||||||
self.sf.write("* {}\n".format(comment))
|
self.sf.write("* {}\n".format(comment))
|
||||||
|
|
||||||
|
self.sf.write("\n")
|
||||||
for read_port in self.targ_read_ports:
|
for read_port in self.targ_read_ports:
|
||||||
self.write_delay_measures_read_port(read_port)
|
self.sf.write("* Read ports {}\n".format(read_port))
|
||||||
|
self.write_delay_measures_read_port(read_port)
|
||||||
|
|
||||||
for write_port in self.targ_write_ports:
|
for write_port in self.targ_write_ports:
|
||||||
self.write_delay_measures_write_port(write_port)
|
self.sf.write("* Write ports {}\n".format(write_port))
|
||||||
|
self.write_delay_measures_write_port(write_port)
|
||||||
|
|
||||||
|
|
||||||
def write_power_measures(self):
|
def write_power_measures(self):
|
||||||
|
|
@ -595,14 +669,16 @@ class delay(simulation):
|
||||||
debug.error("Timed out, could not find a feasible period.",2)
|
debug.error("Timed out, could not find a feasible period.",2)
|
||||||
|
|
||||||
# Clear any write target ports and set read port
|
# Clear any write target ports and set read port
|
||||||
self.targ_write_ports = []
|
self.targ_write_ports = [port]
|
||||||
self.targ_read_ports = [port]
|
self.targ_read_ports = [port]
|
||||||
success = False
|
success = False
|
||||||
|
|
||||||
debug.info(1, "Trying feasible period: {0}ns on Port {1}".format(feasible_period, port))
|
debug.info(1, "Trying feasible period: {0}ns on Port {1}".format(feasible_period, port))
|
||||||
self.period = feasible_period
|
self.period = feasible_period
|
||||||
(success, results)=self.run_delay_simulation()
|
(success, results)=self.run_delay_simulation()
|
||||||
|
|
||||||
# Clear these target ports after simulation
|
# Clear these target ports after simulation
|
||||||
|
self.targ_write_ports = []
|
||||||
self.targ_read_ports = []
|
self.targ_read_ports = []
|
||||||
|
|
||||||
if not success:
|
if not success:
|
||||||
|
|
@ -615,9 +691,9 @@ class delay(simulation):
|
||||||
delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(*feasible_delays)
|
delay_str = "feasible_delay {0:.4f}ns/{1:.4f}ns".format(*feasible_delays)
|
||||||
slew_str = "slew {0:.4f}ns/{1:.4f}ns".format(*feasible_slews)
|
slew_str = "slew {0:.4f}ns/{1:.4f}ns".format(*feasible_slews)
|
||||||
debug.info(2, "feasible_period passed for Port {3}: {0}ns {1} {2} ".format(feasible_period,
|
debug.info(2, "feasible_period passed for Port {3}: {0}ns {1} {2} ".format(feasible_period,
|
||||||
delay_str,
|
delay_str,
|
||||||
slew_str,
|
slew_str,
|
||||||
port))
|
port))
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
debug.info(2, "Found feasible_period for port {0}: {1}ns".format(port, feasible_period))
|
debug.info(2, "Found feasible_period for port {0}: {1}ns".format(port, feasible_period))
|
||||||
|
|
@ -660,39 +736,23 @@ class delay(simulation):
|
||||||
works on the trimmed netlist by default, so powers do not
|
works on the trimmed netlist by default, so powers do not
|
||||||
include leakage of all cells.
|
include leakage of all cells.
|
||||||
"""
|
"""
|
||||||
# Sanity Check
|
|
||||||
debug.check(self.period > 0, "Target simulation period non-positive")
|
debug.check(self.period > 0, "Target simulation period non-positive")
|
||||||
|
|
||||||
sim_passed = True
|
|
||||||
result = [{} for i in self.all_ports]
|
|
||||||
# Checking from not data_value to data_value
|
|
||||||
self.write_delay_stimulus()
|
self.write_delay_stimulus()
|
||||||
|
|
||||||
self.stim.run_sim()
|
self.stim.run_sim()
|
||||||
|
|
||||||
|
self.check_measurements()
|
||||||
|
|
||||||
|
def check_measurements(self):
|
||||||
|
""" Check the write and read measurements """
|
||||||
|
|
||||||
# Loop through all targeted ports and collect delays and powers.
|
# Loop through all targeted ports and collect delays and powers.
|
||||||
# Too much duplicate code here. Try reducing
|
result = [{} for i in self.all_ports]
|
||||||
for port in self.targ_read_ports:
|
|
||||||
debug.info(2, "Checking delay values for port {}".format(port))
|
|
||||||
read_port_dict = {}
|
|
||||||
# Get measurements from output file
|
|
||||||
for measure in self.read_lib_meas:
|
|
||||||
read_port_dict[measure.name] = measure.retrieve_measure(port=port)
|
|
||||||
|
|
||||||
# Check sen timing, then bitlines, then general measurements.
|
|
||||||
if not self.check_sen_measure(port):
|
|
||||||
return (False,{})
|
|
||||||
success = self.check_debug_measures(port)
|
|
||||||
success = success and self.check_bit_measures()
|
|
||||||
# Check timing for read ports. Power is only checked if it was read correctly
|
|
||||||
if not self.check_valid_delays(read_port_dict) or not success:
|
|
||||||
return (False,{})
|
|
||||||
if not check_dict_values_is_float(read_port_dict):
|
|
||||||
debug.error("Failed to Measure Read Port Values:\n\t\t{0}".format(read_port_dict),1) # Printing the entire dict looks bad.
|
|
||||||
|
|
||||||
result[port].update(read_port_dict)
|
|
||||||
|
|
||||||
for port in self.targ_write_ports:
|
for port in self.targ_write_ports:
|
||||||
|
debug.info(2, "Checking write values for port {}".format(port))
|
||||||
write_port_dict = {}
|
write_port_dict = {}
|
||||||
for measure in self.write_lib_meas:
|
for measure in self.write_lib_meas:
|
||||||
write_port_dict[measure.name] = measure.retrieve_measure(port=port)
|
write_port_dict[measure.name] = measure.retrieve_measure(port=port)
|
||||||
|
|
@ -701,21 +761,45 @@ class delay(simulation):
|
||||||
debug.error("Failed to Measure Write Port Values:\n\t\t{0}".format(write_port_dict),1) # Printing the entire dict looks bad.
|
debug.error("Failed to Measure Write Port Values:\n\t\t{0}".format(write_port_dict),1) # Printing the entire dict looks bad.
|
||||||
result[port].update(write_port_dict)
|
result[port].update(write_port_dict)
|
||||||
|
|
||||||
# The delay is from the negative edge for our SRAM
|
|
||||||
return (sim_passed,result)
|
for port in self.targ_read_ports:
|
||||||
|
debug.info(2, "Checking read delay values for port {}".format(port))
|
||||||
|
read_port_dict = {}
|
||||||
|
# Get measurements from output file
|
||||||
|
for measure in self.read_lib_meas:
|
||||||
|
read_port_dict[measure.name] = measure.retrieve_measure(port=port)
|
||||||
|
|
||||||
|
# Check sen timing, then bitlines, then general measurements.
|
||||||
|
if not self.check_sen_measure(port):
|
||||||
|
return (False,{})
|
||||||
|
success = self.check_read_debug_measures(port)
|
||||||
|
success = success and self.check_bit_measures()
|
||||||
|
|
||||||
|
# Check timing for read ports. Power is only checked if it was read correctly
|
||||||
|
if not self.check_valid_delays(read_port_dict) or not success:
|
||||||
|
return (False,{})
|
||||||
|
if not check_dict_values_is_float(read_port_dict):
|
||||||
|
debug.error("Failed to Measure Read Port Values:\n\t\t{0}".format(read_port_dict),1) # Printing the entire dict looks bad.
|
||||||
|
|
||||||
|
result[port].update(read_port_dict)
|
||||||
|
|
||||||
|
return (True,result)
|
||||||
|
|
||||||
def check_sen_measure(self, port):
|
def check_sen_measure(self, port):
|
||||||
"""Checks that the sen occurred within a half-period"""
|
"""Checks that the sen occurred within a half-period"""
|
||||||
|
|
||||||
sen_val = self.sen_meas.retrieve_measure(port=port)
|
sen_val = self.sen_meas.retrieve_measure(port=port)
|
||||||
debug.info(2,"S_EN delay={} ns".format(sen_val))
|
debug.info(2,"s_en delay={}ns".format(sen_val))
|
||||||
if self.sen_meas.meta_add_delay:
|
if self.sen_meas.meta_add_delay:
|
||||||
max_delay = self.period/2
|
max_delay = self.period/2
|
||||||
else:
|
else:
|
||||||
max_delay = self.period
|
max_delay = self.period
|
||||||
return not (type(sen_val) != float or sen_val > max_delay)
|
return not (type(sen_val) != float or sen_val > max_delay)
|
||||||
|
|
||||||
def check_debug_measures(self, port):
|
|
||||||
|
def check_read_debug_measures(self, port):
|
||||||
"""Debug measures that indicate special conditions."""
|
"""Debug measures that indicate special conditions."""
|
||||||
|
|
||||||
# Currently, only check if the opposite than intended value was read during
|
# Currently, only check if the opposite than intended value was read during
|
||||||
# the read cycles i.e. neither of these measurements should pass.
|
# the read cycles i.e. neither of these measurements should pass.
|
||||||
success = True
|
success = True
|
||||||
|
|
@ -756,8 +840,10 @@ class delay(simulation):
|
||||||
|
|
||||||
|
|
||||||
def check_bit_measures(self):
|
def check_bit_measures(self):
|
||||||
"""Checks the measurements which represent the internal storage voltages
|
"""
|
||||||
at the end of the read cycle."""
|
Checks the measurements which represent the internal storage voltages
|
||||||
|
at the end of the read cycle.
|
||||||
|
"""
|
||||||
success = True
|
success = True
|
||||||
for polarity, meas_list in self.bit_meas.items():
|
for polarity, meas_list in self.bit_meas.items():
|
||||||
for meas in meas_list:
|
for meas in meas_list:
|
||||||
|
|
@ -780,8 +866,10 @@ class delay(simulation):
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def check_bitline_meas(self, v_discharged_bl, v_charged_bl):
|
def check_bitline_meas(self, v_discharged_bl, v_charged_bl):
|
||||||
"""Checks the value of the discharging bitline. Confirms s_en timing errors.
|
"""
|
||||||
Returns true if the bitlines are at there expected value."""
|
Checks the value of the discharging bitline. Confirms s_en timing errors.
|
||||||
|
Returns true if the bitlines are at there expected value.
|
||||||
|
"""
|
||||||
# The inputs looks at discharge/charged bitline rather than left or right (bl/br)
|
# The inputs looks at discharge/charged bitline rather than left or right (bl/br)
|
||||||
# Performs two checks, discharging bitline is at least 10% away from vdd and there is a
|
# Performs two checks, discharging bitline is at least 10% away from vdd and there is a
|
||||||
# 10% vdd difference between the bitlines. Both need to fail to be considered a s_en error.
|
# 10% vdd difference between the bitlines. Both need to fail to be considered a s_en error.
|
||||||
|
|
@ -794,8 +882,8 @@ class delay(simulation):
|
||||||
def run_power_simulation(self):
|
def run_power_simulation(self):
|
||||||
"""
|
"""
|
||||||
This simulates a disabled SRAM to get the leakage power when it is off.
|
This simulates a disabled SRAM to get the leakage power when it is off.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
debug.info(1, "Performing leakage power simulations.")
|
debug.info(1, "Performing leakage power simulations.")
|
||||||
self.write_power_stimulus(trim=False)
|
self.write_power_stimulus(trim=False)
|
||||||
self.stim.run_sim()
|
self.stim.run_sim()
|
||||||
|
|
@ -817,6 +905,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def check_valid_delays(self, result_dict):
|
def check_valid_delays(self, result_dict):
|
||||||
""" Check if the measurements are defined and if they are valid. """
|
""" Check if the measurements are defined and if they are valid. """
|
||||||
|
|
||||||
# Hard coded names currently
|
# Hard coded names currently
|
||||||
delay_hl = result_dict["delay_hl"]
|
delay_hl = result_dict["delay_hl"]
|
||||||
delay_lh = result_dict["delay_lh"]
|
delay_lh = result_dict["delay_lh"]
|
||||||
|
|
@ -884,6 +973,7 @@ class delay(simulation):
|
||||||
|
|
||||||
# Binary search algorithm to find the min period (max frequency) of input port
|
# Binary search algorithm to find the min period (max frequency) of input port
|
||||||
time_out = 25
|
time_out = 25
|
||||||
|
self.targ_write_ports = [port]
|
||||||
self.targ_read_ports = [port]
|
self.targ_read_ports = [port]
|
||||||
while True:
|
while True:
|
||||||
time_out -= 1
|
time_out -= 1
|
||||||
|
|
@ -892,9 +982,9 @@ class delay(simulation):
|
||||||
|
|
||||||
self.period = target_period
|
self.period = target_period
|
||||||
debug.info(1, "MinPeriod Search Port {3}: {0}ns (ub: {1} lb: {2})".format(target_period,
|
debug.info(1, "MinPeriod Search Port {3}: {0}ns (ub: {1} lb: {2})".format(target_period,
|
||||||
ub_period,
|
ub_period,
|
||||||
lb_period,
|
lb_period,
|
||||||
port))
|
port))
|
||||||
|
|
||||||
if self.try_period(feasible_delays):
|
if self.try_period(feasible_delays):
|
||||||
ub_period = target_period
|
ub_period = target_period
|
||||||
|
|
@ -915,14 +1005,16 @@ class delay(simulation):
|
||||||
This tries to simulate a period and checks if the result
|
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.
|
works. If it does and the delay is within 5% still, it returns True.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Run Delay simulation but Power results not used.
|
# Run Delay simulation but Power results not used.
|
||||||
(success, results) = self.run_delay_simulation()
|
(success, results) = self.run_delay_simulation()
|
||||||
if not success:
|
if not success:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Check the values of target readwrite and read ports. Write ports do not produce delays in this current version
|
# Check the values of target readwrite and read ports. Write ports do not produce delays in this current version
|
||||||
for port in self.targ_read_ports:
|
for port in self.targ_read_ports:
|
||||||
for dname in self.delay_meas_names: # check that the delays and slews do not degrade with tested period.
|
# check that the delays and slews do not degrade with tested period.
|
||||||
|
for dname in self.delay_meas_names:
|
||||||
|
|
||||||
# FIXME: This is a hack solution to fix the min period search. The slew will always be based on the period when there
|
# FIXME: This is a hack solution to fix the min period search. The slew will always be based on the period when there
|
||||||
# is a column mux. Therefore, the checks are skipped for this condition. This is hard to solve without changing the netlist.
|
# is a column mux. Therefore, the checks are skipped for this condition. This is hard to solve without changing the netlist.
|
||||||
|
|
@ -936,7 +1028,6 @@ class delay(simulation):
|
||||||
|
|
||||||
# key=raw_input("press return to continue")
|
# key=raw_input("press return to continue")
|
||||||
|
|
||||||
# Dynamic way to build string. A bit messy though.
|
|
||||||
delay_str = ', '.join("{0}={1}ns".format(mname, results[port][mname]) for mname in self.delay_meas_names)
|
delay_str = ', '.join("{0}={1}ns".format(mname, results[port][mname]) for mname in self.delay_meas_names)
|
||||||
debug.info(2,"Successful period {0}, Port {2}, {1}".format(self.period,
|
debug.info(2,"Successful period {0}, Port {2}, {1}".format(self.period,
|
||||||
delay_str,
|
delay_str,
|
||||||
|
|
@ -944,8 +1035,11 @@ class delay(simulation):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def set_probe(self,probe_address, probe_data):
|
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."""
|
Probe address and data can be set separately to utilize other
|
||||||
|
functions in this characterizer besides analyze.
|
||||||
|
"""
|
||||||
|
|
||||||
self.probe_address = probe_address
|
self.probe_address = probe_address
|
||||||
self.probe_data = probe_data
|
self.probe_data = probe_data
|
||||||
self.bitline_column = self.get_data_bit_column_number(probe_address, probe_data)
|
self.bitline_column = self.get_data_bit_column_number(probe_address, probe_data)
|
||||||
|
|
@ -954,6 +1048,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def get_data_bit_column_number(self, probe_address, probe_data):
|
def get_data_bit_column_number(self, probe_address, probe_data):
|
||||||
"""Calculates bitline column number of data bit under test using bit position and mux size"""
|
"""Calculates bitline column number of data bit under test using bit position and mux size"""
|
||||||
|
|
||||||
if self.sram.col_addr_size>0:
|
if self.sram.col_addr_size>0:
|
||||||
col_address = int(probe_address[0:self.sram.col_addr_size],2)
|
col_address = int(probe_address[0:self.sram.col_addr_size],2)
|
||||||
else:
|
else:
|
||||||
|
|
@ -963,6 +1058,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def get_address_row_number(self, probe_address):
|
def get_address_row_number(self, probe_address):
|
||||||
"""Calculates wordline row number of data bit under test using address and column mux size"""
|
"""Calculates wordline row number of data bit under test using address and column mux size"""
|
||||||
|
|
||||||
return int(probe_address[self.sram.col_addr_size:],2)
|
return int(probe_address[self.sram.col_addr_size:],2)
|
||||||
|
|
||||||
def prepare_netlist(self):
|
def prepare_netlist(self):
|
||||||
|
|
@ -988,6 +1084,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def analysis_init(self, probe_address, probe_data):
|
def analysis_init(self, probe_address, probe_data):
|
||||||
"""Sets values which are dependent on the data address/bit being tested."""
|
"""Sets values which are dependent on the data address/bit being tested."""
|
||||||
|
|
||||||
self.set_probe(probe_address, probe_data)
|
self.set_probe(probe_address, probe_data)
|
||||||
self.create_graph()
|
self.create_graph()
|
||||||
self.set_internal_spice_names()
|
self.set_internal_spice_names()
|
||||||
|
|
@ -998,6 +1095,7 @@ class delay(simulation):
|
||||||
"""
|
"""
|
||||||
Main function to characterize an SRAM for a table. Computes both delay and power characterization.
|
Main function to characterize an SRAM for a table. Computes both delay and power characterization.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Dict to hold all characterization values
|
# Dict to hold all characterization values
|
||||||
char_sram_data = {}
|
char_sram_data = {}
|
||||||
self.analysis_init(probe_address, probe_data)
|
self.analysis_init(probe_address, probe_data)
|
||||||
|
|
@ -1030,6 +1128,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def alter_lh_char_data(self, char_port_data):
|
def alter_lh_char_data(self, char_port_data):
|
||||||
"""Copies high-to-low data to low-to-high data to make them consistent on the same clock edge."""
|
"""Copies high-to-low data to low-to-high data to make them consistent on the same clock edge."""
|
||||||
|
|
||||||
# This is basically a hack solution which should be removed/fixed later.
|
# This is basically a hack solution which should be removed/fixed later.
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
char_port_data[port]['delay_lh'] = char_port_data[port]['delay_hl']
|
char_port_data[port]['delay_lh'] = char_port_data[port]['delay_hl']
|
||||||
|
|
@ -1037,6 +1136,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def simulate_loads_and_slews(self, slews, loads, leakage_offset):
|
def simulate_loads_and_slews(self, slews, loads, leakage_offset):
|
||||||
"""Simulate all specified output loads and input slews pairs of all ports"""
|
"""Simulate all specified output loads and input slews pairs of all ports"""
|
||||||
|
|
||||||
measure_data = self.get_empty_measure_data_dict()
|
measure_data = self.get_empty_measure_data_dict()
|
||||||
# Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways.
|
# Set the target simulation ports to all available ports. This make sims slower but failed sims exit anyways.
|
||||||
self.targ_read_ports = self.read_ports
|
self.targ_read_ports = self.read_ports
|
||||||
|
|
@ -1060,6 +1160,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def calculate_inverse_address(self):
|
def calculate_inverse_address(self):
|
||||||
"""Determine dummy test address based on probe address and column mux size."""
|
"""Determine dummy test address based on probe address and column mux size."""
|
||||||
|
|
||||||
# The inverse address needs to share the same bitlines as the probe address as the trimming will remove all other bitlines
|
# The inverse address needs to share the same bitlines as the probe address as the trimming will remove all other bitlines
|
||||||
# This is only an issue when there is a column mux and the address maps to different bitlines.
|
# This is only an issue when there is a column mux and the address maps to different bitlines.
|
||||||
column_addr = self.probe_address[:self.sram.col_addr_size] # do not invert this part
|
column_addr = self.probe_address[:self.sram.col_addr_size] # do not invert this part
|
||||||
|
|
@ -1125,6 +1226,7 @@ class delay(simulation):
|
||||||
self.probe_address,data_zeros)
|
self.probe_address,data_zeros)
|
||||||
|
|
||||||
def get_available_port(self,get_read_port):
|
def get_available_port(self,get_read_port):
|
||||||
|
|
||||||
"""Returns the first accessible read or write port. """
|
"""Returns the first accessible read or write port. """
|
||||||
if get_read_port and len(self.read_ports) > 0:
|
if get_read_port and len(self.read_ports) > 0:
|
||||||
return self.read_ports[0]
|
return self.read_ports[0]
|
||||||
|
|
@ -1142,6 +1244,7 @@ class delay(simulation):
|
||||||
of the cycles to do a timing evaluation. The last time is the end of the simulation
|
of the cycles to do a timing evaluation. The last time is the end of the simulation
|
||||||
and does not need a rising edge.
|
and does not need a rising edge.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Using this requires setting at least one port to target for simulation.
|
# Using this requires setting at least one port to target for simulation.
|
||||||
if len(self.targ_write_ports) == 0 and len(self.targ_read_ports) == 0:
|
if len(self.targ_write_ports) == 0 and len(self.targ_read_ports) == 0:
|
||||||
debug.error("No port selected for characterization.",1)
|
debug.error("No port selected for characterization.",1)
|
||||||
|
|
@ -1173,7 +1276,8 @@ class delay(simulation):
|
||||||
self.gen_test_cycles_one_port(cur_read_port, cur_write_port)
|
self.gen_test_cycles_one_port(cur_read_port, cur_write_port)
|
||||||
|
|
||||||
def analytical_delay(self, slews, loads):
|
def analytical_delay(self, slews, loads):
|
||||||
""" Return the analytical model results for the SRAM.
|
"""
|
||||||
|
Return the analytical model results for the SRAM.
|
||||||
"""
|
"""
|
||||||
if OPTS.num_rw_ports > 1 or OPTS.num_w_ports > 0 and OPTS.num_r_ports > 0:
|
if OPTS.num_rw_ports > 1 or OPTS.num_w_ports > 0 and OPTS.num_r_ports > 0:
|
||||||
debug.warning("Analytical characterization results are not supported for multiport.")
|
debug.warning("Analytical characterization results are not supported for multiport.")
|
||||||
|
|
@ -1206,6 +1310,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def analytical_power(self, slews, loads):
|
def analytical_power(self, slews, loads):
|
||||||
"""Get the dynamic and leakage power from the SRAM"""
|
"""Get the dynamic and leakage power from the SRAM"""
|
||||||
|
|
||||||
# slews unused, only last load is used
|
# slews unused, only last load is used
|
||||||
load = loads[-1]
|
load = loads[-1]
|
||||||
power = self.sram.analytical_power(self.corner, load)
|
power = self.sram.analytical_power(self.corner, load)
|
||||||
|
|
@ -1218,6 +1323,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def gen_data(self):
|
def gen_data(self):
|
||||||
""" Generates the PWL data inputs for a simulation timing test. """
|
""" Generates the PWL data inputs for a simulation timing test. """
|
||||||
|
|
||||||
for write_port in self.write_ports:
|
for write_port in self.write_ports:
|
||||||
for i in range(self.word_size):
|
for i in range(self.word_size):
|
||||||
sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i)
|
sig_name="{0}{1}_{2} ".format(self.din_name,write_port, i)
|
||||||
|
|
@ -1228,6 +1334,7 @@ class delay(simulation):
|
||||||
Generates the address inputs for a simulation timing test.
|
Generates the address inputs for a simulation timing test.
|
||||||
This alternates between all 1's and all 0's for the address.
|
This alternates between all 1's and all 0's for the address.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
for i in range(self.addr_size):
|
for i in range(self.addr_size):
|
||||||
sig_name = "{0}{1}_{2}".format(self.addr_name,port,i)
|
sig_name = "{0}{1}_{2}".format(self.addr_name,port,i)
|
||||||
|
|
@ -1235,6 +1342,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def gen_control(self):
|
def gen_control(self):
|
||||||
""" Generates the control signals """
|
""" Generates the control signals """
|
||||||
|
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
self.stim.gen_pwl("CSB{0}".format(port), self.cycle_times, self.csb_values[port], self.period, self.slew, 0.05)
|
self.stim.gen_pwl("CSB{0}".format(port), self.cycle_times, self.csb_values[port], self.period, self.slew, 0.05)
|
||||||
if port in self.readwrite_ports:
|
if port in self.readwrite_ports:
|
||||||
|
|
@ -1243,6 +1351,7 @@ class delay(simulation):
|
||||||
|
|
||||||
def get_empty_measure_data_dict(self):
|
def get_empty_measure_data_dict(self):
|
||||||
"""Make a dict of lists for each type of delay and power measurement to append results to"""
|
"""Make a dict of lists for each type of delay and power measurement to append results to"""
|
||||||
|
|
||||||
measure_names = self.delay_meas_names + self.power_meas_names
|
measure_names = self.delay_meas_names + self.power_meas_names
|
||||||
# Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists.
|
# Create list of dicts. List lengths is # of ports. Each dict maps the measurement names to lists.
|
||||||
measure_data = [{mname:[] for mname in measure_names} for i in self.all_ports]
|
measure_data = [{mname:[] for mname in measure_names} for i in self.all_ports]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue