Added bitcell check to storage nodes.

This commit is contained in:
Hunter Nichols 2019-05-20 18:35:52 -07:00
parent 412f9bb463
commit 099bc4e258
9 changed files with 181 additions and 45 deletions

View File

@ -182,6 +182,23 @@ class spice():
else: else:
self.spice = [] self.spice = []
def check_net_in_spice(self, net_name):
"""Checks if a net name exists in the current. Intended to be check nets in hand-made cells."""
#Remove spaces and lower case then add spaces. Nets are separated by spaces.
net_formatted = ' '+net_name.lstrip().rstrip().lower()+' '
for line in self.spice:
#Lowercase the line and remove any part of the line that is a comment.
line = line.lower().split('*')[0]
#Skip .subckt or .ENDS lines
if line.find('.') == 0:
continue
if net_formatted in line:
return True
return False
def contains(self, mod, modlist): def contains(self, mod, modlist):
for x in modlist: for x in modlist:
if x.name == mod.name: if x.name == mod.name:

View File

@ -20,6 +20,7 @@ class bitcell(design.design):
""" """
pin_names = ["bl", "br", "wl", "vdd", "gnd"] pin_names = ["bl", "br", "wl", "vdd", "gnd"]
internal_nets = ['Q', 'Qbar']
type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] type_list = ["OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
(width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"])
pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"]) pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"])
@ -33,6 +34,7 @@ class bitcell(design.design):
self.height = bitcell.height self.height = bitcell.height
self.pin_map = bitcell.pin_map self.pin_map = bitcell.pin_map
self.add_pin_types(self.type_list) self.add_pin_types(self.type_list)
self.nets_match = self.check_internal_nets()
def analytical_delay(self, corner, slew, load=0, swing = 0.5): def analytical_delay(self, corner, slew, load=0, swing = 0.5):
parasitic_delay = 1 parasitic_delay = 1
@ -77,6 +79,22 @@ class bitcell(design.design):
total_power = self.return_power(dynamic, leakage) total_power = self.return_power(dynamic, leakage)
return total_power return total_power
def check_internal_nets(self):
"""For handmade cell, checks sp file contains the storage nodes."""
nets_match = True
for net in self.internal_nets:
nets_match = nets_match and self.check_net_in_spice(net)
return nets_match
def get_storage_net_names(self):
"""Returns names of storage nodes in bitcell in [non-inverting, inverting] format."""
#Checks that they do exist
if self.nets_match:
return self.internal_nets
else:
debug.info(1,"Storage nodes={} not found in spice file.".format(self.internal_nets))
return None
def get_wl_cin(self): def get_wl_cin(self):
"""Return the relative capacitance of the access transistor gates""" """Return the relative capacitance of the access transistor gates"""
#This is a handmade cell so the value must be entered in the tech.py file or estimated. #This is a handmade cell so the value must be entered in the tech.py file or estimated.

View File

@ -15,7 +15,11 @@ class sram_op(Enum):
READ_ONE = 1 READ_ONE = 1
WRITE_ZERO = 2 WRITE_ZERO = 2
WRITE_ONE = 3 WRITE_ONE = 3
class bit_polarity(Enum):
NONINVERTING = 0
INVERTING = 1
def relative_compare(value1,value2,error_tolerance=0.001): def relative_compare(value1,value2,error_tolerance=0.001):
""" This is used to compare relative values for convergence. """ """ This is used to compare relative values for convergence. """
return (abs(value1 - value2) / abs(max(value1,value2)) <= error_tolerance) return (abs(value1 - value2) / abs(max(value1,value2)) <= error_tolerance)
@ -38,7 +42,6 @@ def parse_spice_list(filename, key):
f.close() f.close()
# val = re.search(r"{0}\s*=\s*(-?\d+.?\d*\S*)\s+.*".format(key), contents) # val = re.search(r"{0}\s*=\s*(-?\d+.?\d*\S*)\s+.*".format(key), contents)
val = re.search(r"{0}\s*=\s*(-?\d+.?\d*[e]?[-+]?[0-9]*\S*)\s+.*".format(key), contents) val = re.search(r"{0}\s*=\s*(-?\d+.?\d*[e]?[-+]?[0-9]*\S*)\s+.*".format(key), contents)
if val != None: if val != None:
debug.info(4, "Key = " + key + " Val = " + val.group(1)) debug.info(4, "Key = " + key + " Val = " + val.group(1))
return convert_to_float(val.group(1)) return convert_to_float(val.group(1))

View File

@ -60,7 +60,19 @@ class delay(simulation):
"""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)
def check_meas_names(self, measures_lists):
"""Given measurements (in 2d list), checks that their names are unique.
Spice sim will fail otherwise."""
name_set = set()
for meas_list in measures_lists:
for meas in meas_list:
name = meas.name.lower()
debug.check(name not in name_set,("SPICE measurements must have unique names. "
"Duplicate name={}").format(name))
name_set.add(name)
def create_read_port_measurement_objects(self): def create_read_port_measurement_objects(self):
"""Create the measurements used for read ports: delays, slews, powers""" """Create the measurements used for read ports: delays, slews, powers"""
@ -104,6 +116,7 @@ class delay(simulation):
#Other measurements associated with the read port not included in the liberty file #Other measurements associated with the read port not included in the liberty file
read_measures.append(self.create_bitline_measurement_objects()) read_measures.append(self.create_bitline_measurement_objects())
read_measures.append(self.create_debug_measurement_objects()) read_measures.append(self.create_debug_measurement_objects())
read_measures.append(self.create_read_bit_measures())
return read_measures return read_measures
@ -164,6 +177,37 @@ class delay(simulation):
self.debug_volt_meas[-1].meta_str = debug_meas.meta_str self.debug_volt_meas[-1].meta_str = debug_meas.meta_str
return self.debug_delay_meas+self.debug_volt_meas return self.debug_delay_meas+self.debug_volt_meas
def create_read_bit_measures(self):
"""Adds bit measurements for read0 and read1 cycles"""
self.bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]}
meas_cycles = (sram_op.READ_ZERO, sram_op.READ_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):
"""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_row = self.get_address_row_number(probe_address)
(cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, bit_row, bit_col)
storage_names = cell_inst.mod.get_storage_net_names()
debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes"
"supported for characterization. Storage nets={}").format(storage_names))
q_name = cell_name+'.'+str(storage_names[0])
qbar_name = cell_name+'.'+str(storage_names[1])
#Bit measures, measurements times to be defined later. The measurement names must be unique
# but they is enforced externally
q_meas = voltage_at_measure("v_q_{}".format(meas_tag), q_name, has_port=False)
qbar_meas = voltage_at_measure("v_qbar_{}".format(meas_tag), qbar_name, has_port=False)
return {bit_polarity.NONINVERTING:q_meas, bit_polarity.INVERTING:qbar_meas}
def set_load_slew(self,load,slew): def set_load_slew(self,load,slew):
""" Set the load and slew """ """ Set the load and slew """
@ -211,6 +255,11 @@ class delay(simulation):
self.br_name = [bl for bl in preconv_names if 'br' in bl][0] self.br_name = [bl for bl in preconv_names if 'br' in bl][0]
debug.info(1,"bl_name={}".format(self.bl_name)) debug.info(1,"bl_name={}".format(self.bl_name))
(cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, self.wordline_row, self.bitline_column)
debug.info(1, "cell_name={}".format(cell_name))
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:
@ -350,16 +399,22 @@ class delay(simulation):
"""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:
return self.get_delay_measure_variants(port, measure_obj) variant_tuple = self.get_delay_measure_variants(port, measure_obj)
elif meas_type is power_measure: elif meas_type is power_measure:
return self.get_power_measure_variants(port, measure_obj, "read") variant_tuple = self.get_power_measure_variants(port, measure_obj, "read")
elif meas_type is voltage_when_measure: elif meas_type is voltage_when_measure:
return self.get_volt_when_measure_variants(port, measure_obj) variant_tuple = self.get_volt_when_measure_variants(port, measure_obj)
elif meas_type is voltage_at_measure: elif meas_type is voltage_at_measure:
return self.get_volt_at_measure_variants(port, measure_obj) 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 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
@ -567,10 +622,10 @@ class delay(simulation):
#Get measurements from output file #Get measurements from output file
for measure in self.read_lib_meas: for measure in self.read_lib_meas:
read_port_dict[measure.name] = measure.retrieve_measure(port=port) read_port_dict[measure.name] = measure.retrieve_measure(port=port)
debug_passed = self.check_debug_measures(port, read_port_dict) success = self.check_debug_measures(port, read_port_dict)
success = success and self.check_bit_measures()
#Check timing for read ports. Power is only checked if it was read correctly #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 debug_passed: if not self.check_valid_delays(read_port_dict) or not success:
return (False,{}) return (False,{})
if not check_dict_values_is_float(read_port_dict): 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. debug.error("Failed to Measure Read Port Values:\n\t\t{0}".format(read_port_dict),1) #Printing the entire dict looks bad.
@ -648,7 +703,32 @@ class delay(simulation):
return success return success
def check_bit_measures(self):
"""Checks the measurements which represent the internal storage voltages
at the end of the read cycle."""
success = True
for polarity, meas_list in self.bit_meas.items():
for meas in meas_list:
val = meas.retrieve_measure()
debug.info(1,"{}={}".format(meas.name, val))
if type(val) != float:
continue
meas_cycle = meas.meta_str
if (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.NONINVERTING) or\
(meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.INVERTING):
success = val < self.vdd_voltage*.1
elif (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.INVERTING) or\
(meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.NONINVERTING):
success = val > self.vdd_voltage*.9
if not success:
debug.info(1,("Wrong value detected on probe bit during read cycle. "
"Check writes and control logic for bugs.\n measure={}, op={}, "
"bit_storage={}").format(meas.name, meas_cycle.name, polarity.name))
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. """Checks the value of the discharging bitline. Confirms s_en timing errors.
Returns true if the bitlines are at there expected value.""" Returns true if the bitlines are at there expected value."""

View File

@ -13,10 +13,11 @@ from .charutils import *
class spice_measurement(ABC): class spice_measurement(ABC):
"""Base class for spice stimulus measurements.""" """Base class for spice stimulus measurements."""
def __init__(self, measure_name, measure_scale=None): def __init__(self, measure_name, measure_scale=None, has_port=True):
#Names must be unique for correct spice simulation, but not enforced here. #Names must be unique for correct spice simulation, but not enforced here.
self.name = measure_name self.name = measure_name
self.measure_scale = measure_scale self.measure_scale = measure_scale
self.has_port = has_port #Needed for error checking
#Some meta values used externally. variables are added here for consistency accross the objects #Some meta values used externally. variables are added here for consistency accross the objects
self.meta_str = None self.meta_str = None
self.meta_add_delay = False self.meta_add_delay = False
@ -35,18 +36,29 @@ class spice_measurement(ABC):
measure_vals = self.get_measure_values(*input_tuple) measure_vals = self.get_measure_values(*input_tuple)
measure_func(stim_obj, *measure_vals) measure_func(stim_obj, *measure_vals)
def retrieve_measure(self, port=""): def retrieve_measure(self, port=None):
value = parse_spice_list("timing", "{0}{1}".format(self.name.lower(), port)) self.port_error_check(port)
if port != None:
value = parse_spice_list("timing", "{0}{1}".format(self.name.lower(), port))
else:
value = parse_spice_list("timing", "{0}".format(self.name.lower()))
if type(value)!=float or self.measure_scale == None: if type(value)!=float or self.measure_scale == None:
return value return value
else: else:
return value*self.measure_scale return value*self.measure_scale
def port_error_check(self, port):
if self.has_port and port == None:
debug.error("Cannot retrieve measurement, port input was expected.",1)
elif not self.has_port and port != None:
debug.error("Unexpected port input received during measure retrieval.",1)
class delay_measure(spice_measurement): class delay_measure(spice_measurement):
"""Generates a spice measurement for the delay of 50%-to-50% points of two signals.""" """Generates a spice measurement for the delay of 50%-to-50% points of two signals."""
def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd=0.5, targ_vdd=0.5, measure_scale=None): def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, targ_dir_str,\
spice_measurement.__init__(self, measure_name, measure_scale) trig_vdd=0.5, targ_vdd=0.5, measure_scale=None, has_port=True):
spice_measurement.__init__(self, measure_name, measure_scale, has_port)
self.set_meas_constants(trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd, targ_vdd) self.set_meas_constants(trig_name, targ_name, trig_dir_str, targ_dir_str, trig_vdd, targ_vdd)
def get_measure_function(self): def get_measure_function(self):
@ -56,10 +68,8 @@ class delay_measure(spice_measurement):
"""Set the constants for this measurement: signal names, directions, and trigger scales""" """Set the constants for this measurement: signal names, directions, and trigger scales"""
self.trig_dir_str = trig_dir_str self.trig_dir_str = trig_dir_str
self.targ_dir_str = targ_dir_str self.targ_dir_str = targ_dir_str
self.trig_val_of_vdd = trig_vdd self.trig_val_of_vdd = trig_vdd
self.targ_val_of_vdd = targ_vdd self.targ_val_of_vdd = targ_vdd
self.trig_name_no_port = trig_name self.trig_name_no_port = trig_name
self.targ_name_no_port = targ_name self.targ_name_no_port = targ_name
@ -67,9 +77,10 @@ class delay_measure(spice_measurement):
def get_measure_values(self, trig_td, targ_td, vdd_voltage, port=None): def get_measure_values(self, trig_td, targ_td, vdd_voltage, port=None):
"""Constructs inputs to stimulus measurement function. Variant values are inputs here.""" """Constructs inputs to stimulus measurement function. Variant values are inputs here."""
self.port_error_check(port)
trig_val = self.trig_val_of_vdd * vdd_voltage trig_val = self.trig_val_of_vdd * vdd_voltage
targ_val = self.targ_val_of_vdd * vdd_voltage targ_val = self.targ_val_of_vdd * vdd_voltage
if port != None: if port != None:
#For dictionary indexing reasons, the name is formatted differently than the signals #For dictionary indexing reasons, the name is formatted differently than the signals
meas_name = "{}{}".format(self.name, port) meas_name = "{}{}".format(self.name, port)
@ -79,13 +90,12 @@ class delay_measure(spice_measurement):
meas_name = self.name meas_name = self.name
trig_name = self.trig_name_no_port trig_name = self.trig_name_no_port
targ_name = self.targ_name_no_port targ_name = self.targ_name_no_port
return (meas_name,trig_name,targ_name,trig_val,targ_val,self.trig_dir_str,self.targ_dir_str,trig_td,targ_td) return (meas_name,trig_name,targ_name,trig_val,targ_val,self.trig_dir_str,self.targ_dir_str,trig_td,targ_td)
class slew_measure(delay_measure): class slew_measure(delay_measure):
def __init__(self, measure_name, signal_name, slew_dir_str, measure_scale=None): def __init__(self, measure_name, signal_name, slew_dir_str, measure_scale=None, has_port=True):
spice_measurement.__init__(self, measure_name, measure_scale) spice_measurement.__init__(self, measure_name, measure_scale, has_port)
self.set_meas_constants(signal_name, slew_dir_str) self.set_meas_constants(signal_name, slew_dir_str)
def set_meas_constants(self, signal_name, slew_dir_str): def set_meas_constants(self, signal_name, slew_dir_str):
@ -101,7 +111,6 @@ class slew_measure(delay_measure):
self.targ_val_of_vdd = 0.1 self.targ_val_of_vdd = 0.1
else: else:
debug.error("Unrecognised slew measurement direction={}".format(slew_dir_str),1) debug.error("Unrecognised slew measurement direction={}".format(slew_dir_str),1)
self.trig_name_no_port = signal_name self.trig_name_no_port = signal_name
self.targ_name_no_port = signal_name self.targ_name_no_port = signal_name
@ -110,8 +119,8 @@ class slew_measure(delay_measure):
class power_measure(spice_measurement): class power_measure(spice_measurement):
"""Generates a spice measurement for the average power between two time points.""" """Generates a spice measurement for the average power between two time points."""
def __init__(self, measure_name, power_type="", measure_scale=None): def __init__(self, measure_name, power_type="", measure_scale=None, has_port=True):
spice_measurement.__init__(self, measure_name, measure_scale) spice_measurement.__init__(self, measure_name, measure_scale, has_port)
self.set_meas_constants(power_type) self.set_meas_constants(power_type)
def get_measure_function(self): def get_measure_function(self):
@ -124,6 +133,7 @@ class power_measure(spice_measurement):
def get_measure_values(self, t_initial, t_final, port=None): def get_measure_values(self, t_initial, t_final, port=None):
"""Constructs inputs to stimulus measurement function. Variant values are inputs here.""" """Constructs inputs to stimulus measurement function. Variant values are inputs here."""
self.port_error_check(port)
if port != None: if port != None:
meas_name = "{}{}".format(self.name, port) meas_name = "{}{}".format(self.name, port)
else: else:
@ -133,8 +143,8 @@ class power_measure(spice_measurement):
class voltage_when_measure(spice_measurement): class voltage_when_measure(spice_measurement):
"""Generates a spice measurement to measure the voltage of a signal based on the voltage of another.""" """Generates a spice measurement to measure the voltage of a signal based on the voltage of another."""
def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, trig_vdd, measure_scale=None): def __init__(self, measure_name, trig_name, targ_name, trig_dir_str, trig_vdd, measure_scale=None, has_port=True):
spice_measurement.__init__(self, measure_name, measure_scale) spice_measurement.__init__(self, measure_name, measure_scale, has_port)
self.set_meas_constants(trig_name, targ_name, trig_dir_str, trig_vdd) self.set_meas_constants(trig_name, targ_name, trig_dir_str, trig_vdd)
def get_measure_function(self): def get_measure_function(self):
@ -144,13 +154,12 @@ class voltage_when_measure(spice_measurement):
"""Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)""" """Sets values useful for power simulations. This value is only meta related to the lib file (rise/fall)"""
self.trig_dir_str = trig_dir_str self.trig_dir_str = trig_dir_str
self.trig_val_of_vdd = trig_vdd self.trig_val_of_vdd = trig_vdd
self.trig_name_no_port = trig_name self.trig_name_no_port = trig_name
self.targ_name_no_port = targ_name self.targ_name_no_port = targ_name
def get_measure_values(self, trig_td, vdd_voltage, port=None): def get_measure_values(self, trig_td, vdd_voltage, port=None):
"""Constructs inputs to stimulus measurement function. Variant values are inputs here.""" """Constructs inputs to stimulus measurement function. Variant values are inputs here."""
self.port_error_check(port)
if port != None: if port != None:
#For dictionary indexing reasons, the name is formatted differently than the signals #For dictionary indexing reasons, the name is formatted differently than the signals
meas_name = "{}{}".format(self.name, port) meas_name = "{}{}".format(self.name, port)
@ -160,17 +169,15 @@ class voltage_when_measure(spice_measurement):
meas_name = self.name meas_name = self.name
trig_name = self.trig_name_no_port trig_name = self.trig_name_no_port
targ_name = self.targ_name_no_port targ_name = self.targ_name_no_port
trig_voltage = self.trig_val_of_vdd*vdd_voltage
trig_voltage = self.trig_val_of_vdd*vdd_voltage
return (meas_name,trig_name,targ_name,trig_voltage,self.trig_dir_str,trig_td) return (meas_name,trig_name,targ_name,trig_voltage,self.trig_dir_str,trig_td)
class voltage_at_measure(spice_measurement): class voltage_at_measure(spice_measurement):
"""Generates a spice measurement to measure the voltage at a specific time. """Generates a spice measurement to measure the voltage at a specific time.
The time is considered variant with different periods.""" The time is considered variant with different periods."""
def __init__(self, measure_name, targ_name, measure_scale=None): def __init__(self, measure_name, targ_name, measure_scale=None, has_port=True):
spice_measurement.__init__(self, measure_name, measure_scale) spice_measurement.__init__(self, measure_name, measure_scale, has_port)
self.set_meas_constants(targ_name) self.set_meas_constants(targ_name)
def get_measure_function(self): def get_measure_function(self):
@ -182,13 +189,13 @@ class voltage_at_measure(spice_measurement):
def get_measure_values(self, time_at, port=None): def get_measure_values(self, time_at, port=None):
"""Constructs inputs to stimulus measurement function. Variant values are inputs here.""" """Constructs inputs to stimulus measurement function. Variant values are inputs here."""
self.port_error_check(port)
if port != None: if port != None:
#For dictionary indexing reasons, the name is formatted differently than the signals #For dictionary indexing reasons, the name is formatted differently than the signals
meas_name = "{}{}".format(self.name, port) meas_name = "{}{}".format(self.name, port)
targ_name = self.targ_name_no_port.format(port) targ_name = self.targ_name_no_port.format(port)
else: else:
meas_name = self.name meas_name = self.name
targ_name = self.targ_name_no_port targ_name = self.targ_name_no_port
return (meas_name,targ_name,time_at) return (meas_name,targ_name,time_at)

View File

@ -1286,4 +1286,8 @@ class bank(design.design):
"""Precharge adds a loop between bitlines, can be excluded to reduce complexity""" """Precharge adds a loop between bitlines, can be excluded to reduce complexity"""
for inst in self.precharge_array_inst: for inst in self.precharge_array_inst:
if inst != None: if inst != None:
self.graph_inst_exclude.add(inst) self.graph_inst_exclude.add(inst)
def get_cell_name(self, inst_name, row, col):
"""Gets the spice name of the target bitcell."""
return self.bitcell_array_inst.mod.get_cell_name(inst_name+'.x'+self.bitcell_array_inst.name, row, col)

View File

@ -210,4 +210,6 @@ class bitcell_array(design.design):
continue continue
self.graph_inst_exclude.add(self.cell_inst[row,col]) self.graph_inst_exclude.add(self.cell_inst[row,col])
def get_cell_name(self, inst_name, row, col):
"""Gets the spice name of the target bitcell."""
return inst_name+'.x'+self.cell_inst[row,col].name, self.cell_inst[row,col]

View File

@ -343,9 +343,12 @@ class sram_1bank(sram_base):
debug.error("Signal={} not contained in control logic connections={}"\ debug.error("Signal={} not contained in control logic connections={}"\
.format(sen_name, control_conns)) .format(sen_name, control_conns))
if sen_name in self.pins: if sen_name in self.pins:
debug.error("Internal signal={} contained in port list. Name defined by the parent.") debug.error("Internal signal={} contained in port list. Name defined by the parent.")
debug.info(1,"pins={}".format(self.pins))
debug.info(1,"cl conns={}".format(control_conns))
return "X{}.{}".format(sram_name, sen_name) return "X{}.{}".format(sram_name, sen_name)
def get_cell_name(self, inst_name, row, col):
"""Gets the spice name of the target bitcell."""
#Sanity check in case it was forgotten
if inst_name.find('x') != 0:
inst_name = 'x'+inst_name
return self.bank_inst.mod.get_cell_name(inst_name+'.x'+self.bank_inst.name, row, col)

View File

@ -45,7 +45,9 @@ class timing_sram_test(openram_test):
c.recompute_sizes() c.recompute_sizes()
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank") debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
s = factory.create(module_type="sram", sram_config=c) s = factory.create(module_type="sram", sram_config=c)
#import sys
#sys.exit(1)
tempspice = OPTS.openram_temp + "temp.sp" tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice) s.sp_write(tempspice)