From 98a00f985b9bed12a85ec93cf001e392553c2627 Mon Sep 17 00:00:00 2001 From: Hunter Nichols Date: Thu, 25 Oct 2018 23:55:31 -0700 Subject: [PATCH] Changed the analytical delay model to accept multiport options. Little substance to the values generated. --- compiler/bitcells/pbitcell.py | 16 ++++++ compiler/characterizer/delay.py | 82 +++++++++++++++++++++---------- compiler/characterizer/lib.py | 2 +- compiler/modules/bank.py | 28 ++++++----- compiler/modules/bitcell_array.py | 12 ++++- 5 files changed, 98 insertions(+), 42 deletions(-) diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index 908df0e0..0242f2ce 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -884,3 +884,19 @@ class pbitcell(design.design): Q_bar_pos = self.inverter_pmos_right.get_pin("S").center() vdd_pos = self.inverter_pmos_right.get_pin("D").center() self.add_path("metal1", [Q_bar_pos, vdd_pos]) + + def analytical_delay(self, slew, load=0, swing = 0.5): + #FIXME: Delay copied exactly over from bitcell + from tech import spice + r = spice["min_tx_r"]*3 + c_para = spice["min_tx_drain_c"] + result = self.cal_delay_with_rc(r = r, c = c_para+load, slew = slew, swing = swing) + return result + + def analytical_power(self, proc, vdd, temp, load): + """Bitcell power in nW. Only characterizes leakage.""" + from tech import spice + leakage = spice["bitcell_leakage"] + dynamic = 0 #temporary + total_power = self.return_power(dynamic, leakage) + return total_power \ No newline at end of file diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index d699dc06..5fdc1fef 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -807,46 +807,74 @@ class delay(simulation): #Add test cycle of read/write port pair. One port could have been used already, but the other has not. self.gen_test_cycles_one_port(cur_read_port, cur_write_port) - def analytical_delay(self,sram, slews, loads): + def analytical_delay(self, slews, loads): """ Return the analytical model results for the SRAM. """ - debug.check(OPTS.num_rw_ports < 2 and OPTS.num_w_ports < 1 and OPTS.num_r_ports < 1 , - "Analytical characterization does not currently support multiport.") + 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.") - delay_lh = [] - delay_hl = [] - slew_lh = [] - slew_hl = [] + power = self.analytical_power(slews, loads) + port_data = self.get_empty_measure_data_dict() for slew in slews: for load in loads: self.set_load_slew(load,slew) - bank_delay = sram.analytical_delay(self.vdd_voltage, self.slew,self.load) - # Convert from ps to ns - delay_lh.append(bank_delay.delay/1e3) - delay_hl.append(bank_delay.delay/1e3) - slew_lh.append(bank_delay.slew/1e3) - slew_hl.append(bank_delay.slew/1e3) + bank_delay = self.sram.analytical_delay(self.vdd_voltage, self.slew,self.load) + for port in range(self.total_ports): + for mname in self.delay_meas_names+self.power_meas_names: + if "power" in mname: + port_data[port][mname].append(power.dynamic) + elif "delay" in mname: + port_data[port][mname].append(bank_delay[port].delay/1e3) + elif "slew" in mname: + port_data[port][mname].append(bank_delay[port].slew/1e3) + else: + debug.error("Measurement name not recognized: {}".format(mname),1) + sram_data = { "min_period": 0, + "leakage_power": power.leakage} + + return (sram_data,port_data) - power = sram.analytical_power(self.process, self.vdd_voltage, self.temperature, load) + # delay_lh = [] + # delay_hl = [] + # slew_lh = [] + # slew_hl = [] + # for slew in slews: + # for load in loads: + # self.set_load_slew(load,slew) + # bank_delay = sram.analytical_delay(self.vdd_voltage, self.slew,self.load) + # # Convert from ps to ns + # delay_lh.append(bank_delay.delay/1e3) + # delay_hl.append(bank_delay.delay/1e3) + # slew_lh.append(bank_delay.slew/1e3) + # slew_hl.append(bank_delay.slew/1e3) + + # power = self.analytical_power() + + # sram_data = { "min_period": 0, + # "leakage_power": power.leakage} + # port_data = [{"delay_lh": delay_lh, + # "delay_hl": delay_hl, + # "slew_lh": slew_lh, + # "slew_hl": slew_hl, + # "read0_power": power.dynamic, + # "read1_power": power.dynamic, + # "write0_power": power.dynamic, + # "write1_power": power.dynamic, + # }] + # return (sram_data,port_data) + + def analytical_power(self, slews, loads): + """Get the dynamic and leakage power from the SRAM""" + #slews unused, only last load is used + load = loads[-1] + power = self.sram.analytical_power(self.process, self.vdd_voltage, self.temperature, load) #convert from nW to mW power.dynamic /= 1e6 power.leakage /= 1e6 debug.info(1,"Dynamic Power: {0} mW".format(power.dynamic)) debug.info(1,"Leakage Power: {0} mW".format(power.leakage)) + return power - sram_data = { "min_period": 0, - "leakage_power": power.leakage} - port_data = [{"delay_lh": delay_lh, - "delay_hl": delay_hl, - "slew_lh": slew_lh, - "slew_hl": slew_hl, - "read0_power": power.dynamic, - "read1_power": power.dynamic, - "write0_power": power.dynamic, - "write1_power": power.dynamic, - }] - return (sram_data,port_data) - def gen_data(self): """ Generates the PWL data inputs for a simulation timing test. """ for write_port in self.write_index: diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index 6added12..6cc177f6 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -482,7 +482,7 @@ class lib: if not hasattr(self,"d"): self.d = delay(self.sram, self.sp_file, self.corner) if self.use_model: - char_results = self.d.analytical_delay(self.sram,self.slews,self.loads) + char_results = self.d.analytical_delay(self.slews,self.loads) self.char_sram_results, self.char_port_results = char_results else: probe_address = "1" * self.sram.addr_size diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 0fb6be60..1e9401b8 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -927,23 +927,27 @@ class bank(design.design): def analytical_delay(self, vdd, slew, load): """ return analytical delay of the bank""" + results = [] + decoder_delay = self.row_decoder.analytical_delay(slew, self.wordline_driver.input_load()) word_driver_delay = self.wordline_driver.analytical_delay(decoder_delay.slew, self.bitcell_array.input_load()) + #FIXME: Array delay is the same for every port. bitcell_array_delay = self.bitcell_array.analytical_delay(word_driver_delay.slew) - if self.words_per_row > 1: - port = 0 #Analytical delay only supports single port - column_mux_delay = self.column_mux_array[port].analytical_delay(vdd, bitcell_array_delay.slew, - self.sense_amp_array.input_load()) - else: - column_mux_delay = self.return_delay(delay = 0.0, slew=word_driver_delay.slew) - - bl_t_data_out_delay = self.sense_amp_array.analytical_delay(column_mux_delay.slew, - self.bitcell_array.output_load()) - # output load of bitcell_array is set to be only small part of bl for sense amp. + #This also essentially creates the same delay for each port. Good structure, no substance + for port in range(self.total_ports): + if self.words_per_row > 1: + column_mux_delay = self.column_mux_array[port].analytical_delay(vdd, bitcell_array_delay.slew, + self.sense_amp_array.input_load()) + else: + column_mux_delay = self.return_delay(delay = 0.0, slew=word_driver_delay.slew) + + bl_t_data_out_delay = self.sense_amp_array.analytical_delay(column_mux_delay.slew, + self.bitcell_array.output_load()) + # output load of bitcell_array is set to be only small part of bl for sense amp. + results.append(decoder_delay + word_driver_delay + bitcell_array_delay + column_mux_delay + bl_t_data_out_delay) - result = decoder_delay + word_driver_delay + bitcell_array_delay + column_mux_delay + bl_t_data_out_delay - return result + return results diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 511ef9a8..8328a0cf 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -199,13 +199,21 @@ class bitcell_array(design.design): return total_power def gen_wl_wire(self): - wl_wire = self.generate_rc_net(int(self.column_size), self.width, drc("minwidth_metal1")) + if OPTS.netlist_only: + width = 0 + else: + width = self.width + wl_wire = self.generate_rc_net(int(self.column_size), width, drc("minwidth_metal1")) wl_wire.wire_c = 2*spice["min_tx_gate_c"] + wl_wire.wire_c # 2 access tx gate per cell return wl_wire def gen_bl_wire(self): + if OPTS.netlist_only: + height = 0 + else: + height = self.height bl_pos = 0 - bl_wire = self.generate_rc_net(int(self.row_size-bl_pos), self.height, drc("minwidth_metal1")) + bl_wire = self.generate_rc_net(int(self.row_size-bl_pos), height, drc("minwidth_metal1")) bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell return bl_wire