diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 4b8dae7a..3939511f 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -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() diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index ca05648a..d1471d2f 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -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") diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index beca0502..e14ee635 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -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 + diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index 01111abd..6da966cc 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -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 """ diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index 96a8db84..2cdd3414 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -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