Added graph creation to characterizer, re-arranged pin creation.

This commit is contained in:
Hunter Nichols 2019-05-14 01:15:50 -07:00
parent b4cce65889
commit b30c20ffb5
5 changed files with 97 additions and 84 deletions

View File

@ -10,6 +10,7 @@ from globals import OPTS
from .simulation import simulation
from .measurements import *
import logical_effort
import graph_util
class delay(simulation):
"""Functions to measure the delay and power of an SRAM at a given address and
@ -37,6 +38,8 @@ class delay(simulation):
self.period = 0
self.set_load_slew(0,0)
self.set_corner(corner)
self.create_signal_names()
self.add_graph_exclusions()
def create_measurement_names(self):
"""Create measurement names. The names themselves currently define the type of measurement"""
@ -157,19 +160,31 @@ class delay(simulation):
self.debug_volt_meas[-1].meta_str = debug_meas.meta_str
return self.debug_delay_meas+self.debug_volt_meas
def create_signal_names(self):
self.addr_name = "A"
self.din_name = "DIN"
self.dout_name = "DOUT"
#This is TODO once multiport control has been finalized.
#self.control_name = "CSB"
def set_load_slew(self,load,slew):
""" Set the load and slew """
self.load = load
self.slew = slew
def add_graph_exclusions(self):
"""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
#for testing.
self.sram.bank.graph_exclude_precharge()
self.sram.graph_exclude_addr_dff()
self.sram.graph_exclude_data_dff()
self.sram.graph_exclude_ctrl_dffs()
def create_graph(self):
"""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.graph_exclude_bits(self.wordline_row, self.bitline_column)
#Generate new graph every analysis as edges might change depending on test bit
self.graph = graph_util.timing_graph()
self.sram.build_graph(self.graph,"X{}".format(self.sram.name),self.pins)
#debug.info(1,"{}".format(graph))
#graph.print_all_paths('clk0', 'DOUT0[0]')
def check_arguments(self):
"""Checks if arguments given for write_stimulus() meets requirements"""
try:
@ -198,12 +213,8 @@ class delay(simulation):
# instantiate the sram
self.sf.write("\n* Instantiation of the SRAM\n")
self.stim.inst_sram(sram=self.sram,
port_signal_names=(self.addr_name,self.din_name,self.dout_name),
port_info=(len(self.all_ports),self.write_ports,self.read_ports),
abits=self.addr_size,
dbits=self.word_size,
sram_name=self.name)
self.stim.inst_model(pins=self.pins,
model_name=self.sram.name)
self.sf.write("\n* SRAM output loads\n")
for port in self.read_ports:
for i in range(self.word_size):
@ -812,7 +823,7 @@ class delay(simulation):
char_sram_data = {}
self.set_probe(probe_address, probe_data)
self.create_signal_names()
self.create_graph()
self.create_measurement_names()
self.create_measurement_objects()
@ -998,7 +1009,6 @@ class delay(simulation):
"""
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.")
self.create_signal_names()
self.create_measurement_names()
power = self.analytical_power(slews, loads)
port_data = self.get_empty_measure_data_dict()

View File

@ -194,12 +194,7 @@ class functional(simulation):
new_value = "0" + new_value
#print("Binary Conversion: {} to {}".format(value, new_value))
return new_value
def create_signal_names(self):
self.addr_name = "A"
self.din_name = "DIN"
self.dout_name = "DOUT"
return new_value
def write_functional_stimulus(self):
""" Writes SPICE stimulus. """
@ -219,12 +214,8 @@ class functional(simulation):
#Instantiate the SRAM
self.sf.write("\n* Instantiation of the SRAM\n")
self.stim.inst_sram(sram=self.sram,
port_signal_names=(self.addr_name,self.din_name,self.dout_name),
port_info=(len(self.all_ports), self.write_ports, self.read_ports),
abits=self.addr_size,
dbits=self.word_size,
sram_name=self.name)
self.stim.inst_model(pins=self.pins,
model_name=self.sram.name)
# Add load capacitance to each of the read ports
self.sf.write("\n* SRAM output loads\n")

View File

@ -42,6 +42,19 @@ class simulation():
self.v_low = tech.spice["v_threshold_typical"]
self.gnd_voltage = 0
def create_signal_names(self):
self.addr_name = "A"
self.din_name = "DIN"
self.dout_name = "DOUT"
self.pins = self.gen_pin_names(port_signal_names=(self.addr_name,self.din_name,self.dout_name),
port_info=(len(self.all_ports),self.write_ports,self.read_ports),
abits=self.addr_size,
dbits=self.word_size)
debug.check(len(self.sram.pins) == len(self.pins), "Number of pins generated for characterization \
do match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(self.sram.pins,self.pins))
#This is TODO once multiport control has been finalized.
#self.control_name = "CSB"
def set_stimulus_variables(self):
# Clock signals
self.cycle_times = []
@ -223,3 +236,38 @@ class simulation():
t_current+self.period)
return comment
def gen_pin_names(self, port_signal_names, port_info, abits, dbits):
"""Creates the pins names of the SRAM based on the no. of ports."""
#This may seem redundant as the pin names are already defined in the sram. However, it is difficult
#to extract the functionality from the names, so they are recreated. As the order is static, changing
#the order of the pin names will cause issues here.
pin_names = []
(addr_name, din_name, dout_name) = port_signal_names
(total_ports, write_index, read_index) = port_info
for write_input in write_index:
for i in range(dbits):
pin_names.append("{0}{1}_{2}".format(din_name,write_input, i))
for port in range(total_ports):
for i in range(abits):
pin_names.append("{0}{1}_{2}".format(addr_name,port,i))
#Control signals not finalized.
for port in range(total_ports):
pin_names.append("CSB{0}".format(port))
for port in range(total_ports):
if (port in read_index) and (port in write_index):
pin_names.append("WEB{0}".format(port))
for port in range(total_ports):
pin_names.append("{0}{1}".format(tech.spice["clk"], port))
for read_output in read_index:
for i in range(dbits):
pin_names.append("{0}{1}_{2}".format(dout_name,read_output, i))
pin_names.append("{0}".format(tech.spice["vdd_name"]))
pin_names.append("{0}".format(tech.spice["gnd_name"]))
return pin_names

View File

@ -29,51 +29,15 @@ class stimuli():
(self.process, self.voltage, self.temperature) = corner
self.device_models = tech.spice["fet_models"][self.process]
def inst_sram(self, sram, port_signal_names, port_info, abits, dbits, sram_name):
self.sram_name = "Xsram"
def inst_sram(self, pins, inst_name):
""" Function to instatiate an SRAM subckt. """
pin_names = self.gen_pin_names(port_signal_names, port_info, abits, dbits)
#Only checking length. This should check functionality as well (TODO) and/or import that information from the SRAM
debug.check(len(sram.pins) == len(pin_names), "Number of pins generated for characterization do match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(sram.pins,pin_names))
self.sf.write("Xsram ")
for pin in pin_names:
self.sf.write("{} ".format(self.sram_name))
for pin in self.sram_pins:
self.sf.write("{0} ".format(pin))
self.sf.write("{0}\n".format(sram_name))
def gen_pin_names(self, port_signal_names, port_info, abits, dbits):
"""Creates the pins names of the SRAM based on the no. of ports."""
#This may seem redundant as the pin names are already defined in the sram. However, it is difficult to extract the
#functionality from the names, so they are recreated. As the order is static, changing the order of the pin names
#will cause issues here.
pin_names = []
(addr_name, din_name, dout_name) = port_signal_names
(total_ports, write_index, read_index) = port_info
for write_input in write_index:
for i in range(dbits):
pin_names.append("{0}{1}_{2}".format(din_name,write_input, i))
for port in range(total_ports):
for i in range(abits):
pin_names.append("{0}{1}_{2}".format(addr_name,port,i))
#Control signals not finalized.
for port in range(total_ports):
pin_names.append("CSB{0}".format(port))
for port in range(total_ports):
if (port in read_index) and (port in write_index):
pin_names.append("WEB{0}".format(port))
for port in range(total_ports):
pin_names.append("{0}{1}".format(tech.spice["clk"], port))
for read_output in read_index:
for i in range(dbits):
pin_names.append("{0}{1}_{2}".format(dout_name,read_output, i))
pin_names.append("{0}".format(self.vdd_name))
pin_names.append("{0}".format(self.gnd_name))
return pin_names
self.sf.write("{0}\n".format(inst_name))
def inst_model(self, pins, model_name):
""" Function to instantiate a generic model with a set of pins """

View File

@ -26,26 +26,26 @@ class timing_sram_test(openram_test):
reload(characterizer)
from characterizer import delay
from sram_config import sram_config
# c = sram_config(word_size=1,
# num_words=16,
# num_banks=1)
# c.words_per_row=1
c = sram_config(word_size=32,
num_words=256,
c = sram_config(word_size=1,
num_words=16,
num_banks=1)
c.words_per_row=2
OPTS.use_tech_delay_chain_size = True
c.words_per_row=1
# c = sram_config(word_size=32,
# num_words=256,
# num_banks=1)
# c.words_per_row=2
#OPTS.use_tech_delay_chain_size = True
c.recompute_sizes()
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
s = factory.create(module_type="sram", sram_config=c)
#Exclude things known not to be in critical path.
#Intended for characterizing read paths. Somewhat hacky implementation
s.s.bank.bitcell_array.graph_exclude_bits(15,0)
s.s.bank.graph_exclude_precharge()
s.s.graph_exclude_addr_dff()
s.s.graph_exclude_data_dff()
s.s.graph_exclude_ctrl_dffs()
# s.s.bank.bitcell_array.graph_exclude_bits(15,0)
# s.s.bank.graph_exclude_precharge()
# s.s.graph_exclude_addr_dff()
# s.s.graph_exclude_data_dff()
# s.s.graph_exclude_ctrl_dffs()
# debug.info(1,'pins={}'.format(s.s.pins))
# import graph_util