diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 8a7b4bfe..cbf45cd8 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -82,27 +82,25 @@ class delay(): self.sf.write("* Generation of data and address signals\n") for i in range(self.word_size): if i == self.probe_data: - stimuli.gen_data(stim_file=self.sf, - clk_times=self.cycle_times, - sig_name="data[{0}]".format(i), - period=period, - slew=slew) + self.gen_data(clk_times=self.cycle_times, + sig_name="data[{0}]".format(i), + period=period, + slew=slew) else: stimuli.gen_constant(stim_file=self.sf, sig_name="d[{0}]".format(i), v_val=self.gnd) - stimuli.gen_addr(self.sf, - clk_times=self.cycle_times, + self.gen_addr(clk_times=self.cycle_times, addr=self.probe_address, period=period, slew=slew) # generate control signals self.sf.write("* Generation of control signals\n") - stimuli.gen_csb(self.sf, self.cycle_times, period, slew) - stimuli.gen_web(self.sf, self.cycle_times, period, slew) - stimuli.gen_oeb(self.sf, self.cycle_times, period, slew) + self.gen_csb(self.cycle_times, period, slew) + self.gen_web(self.cycle_times, period, slew) + self.gen_oeb(self.cycle_times, period, slew) self.sf.write("* Generation of global clock signal\n") stimuli.gen_pulse(stim_file=self.sf, @@ -404,54 +402,95 @@ class delay(): and does not need a rising edge.""" self.cycle_comments = [] - # idle cycle, no operation - t_current = period self.cycle_times = [] - # cycle0: W data 1 address 1111 to initialize cell to a value + t_current = 0 + + # idle cycle, no operation + msg = "Idle cycle (no clock)" + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(0, + t_current, + msg)) self.cycle_times.append(t_current) - self.cycle_comments.append("Cycle0 {}ns: W data 1 address 11..11 to initialize cell".format(t_current)) t_current += period - # cycle1: W data 0 address 1111 (to ensure a write of value works) + # One period + msg = "W data 1 address 11..11 to initialize cell" self.cycle_times.append(t_current) - self.write0_cycle=1 - self.cycle_comments.append("Cycle1 {}ns: W data 0 address 11..11 (to ensure a write of value works)".format(t_current)) + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) + t_current += period + + # One period + msg = "W data 0 address 11..11 (to ensure a write of value works)" + self.cycle_times.append(t_current) + self.write0_cycle=len(self.cycle_times)-1 + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) t_current += period - # cycle2: W data 1 address 0000 (to clear the data bus cap) + # One period + msg = "W data 1 address 00..00 (to clear bus caps)" self.cycle_times.append(t_current) - self.cycle_comments.append("Cycle2 {}ns: W data 1 address 00..00 (to clear bus caps)".format(t_current)) + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) t_current += period - # cycle3: R data 0 address 1111 to check W0 works + # One period + msg = "R data 0 address 11..11 to check W0 worked" self.cycle_times.append(t_current) - self.read0_cycle=3 - self.cycle_comments.append("Cycle3 {}ns: R data 0 address 11..11 to check W0 worked".format(t_current)) + self.read0_cycle=len(self.cycle_times)-1 + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) t_current += period - # cycle4: W data 1 address 1111 (to ensure a write of value works) + # One period + msg = "Idle cycle" + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) self.cycle_times.append(t_current) - self.write1_cycle=4 - self.cycle_comments.append("Cycle4 {}ns: W data 1 address 11..11 (to ensure a write of value worked)".format(t_current)) t_current += period - # cycle5: W data 0 address 0000 (to clear the data bus cap) + # One period + msg = "W data 1 address 11..11 (to ensure a write of value worked)" self.cycle_times.append(t_current) - self.cycle_comments.append("Cycle5 {}ns: W data 0 address 00..00 (to clear bus caps)".format(t_current)) + self.write1_cycle=len(self.cycle_times)-1 + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) + t_current += period + + # One period + msg = "W data 0 address 00..00 (to clear bus caps)" + self.cycle_times.append(t_current) + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) t_current += period - # cycle6: R data 1 address 1111 to check W1 works + # One period + msg = "R data 1 address 11..11 to check W1 worked" self.cycle_times.append(t_current) - self.read1_cycle=6 - self.cycle_comments.append("Cycle6 {}ns: R data 1 address 11..11 to check W1 worked".format(t_current)) + self.read1_cycle=len(self.cycle_times)-1 + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) t_current += period - # cycle7: wait a clock period to end the simulation + # One period + msg = "Idle cycle" + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) self.cycle_times.append(t_current) - self.cycle_comments.append("Cycle7 {}ns: Idle period to end simulation".format(t_current)) t_current += period + def analytical_model(self,sram, slews, loads): """ Just return the analytical model results for the SRAM. """ @@ -480,3 +519,53 @@ class delay(): } return data + def gen_data(self, clk_times, sig_name, period, slew): + """Generates the PWL data inputs for a simulation timing test.""" + # values for NOP, W1, W0, W1, R0, NOP, W1, W0, R1, NOP + # we are asserting the opposite value on the other side of the tx gate during + # the read to be "worst case". Otherwise, it can actually assist the read. + values = [0, 1, 0, 1, 1, 1, 1, 0, 0, 0 ] + stimuli.gen_pwl(self.sf, sig_name, clk_times, values, period, slew, 0.05) + + def gen_addr(self, clk_times, addr, period, slew): + """Generates the address inputs for a simulation timing test. + One cycle is different to clear the bus + """ + + zero_values = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0 ] + ones_values = [1, 1, 1, 0, 1, 0, 1, 0, 1, 1 ] + + for i in range(len(addr)): + sig_name = "A[{0}]".format(i) + if addr[i]=="1": + stimuli.gen_pwl(self.sf, sig_name, clk_times, ones_values, period, slew, 0.05) + else: + stimuli.gen_pwl(self.sf, sig_name, clk_times, zero_values, period, slew, 0.05) + + + def gen_csb(self, clk_times, period, slew): + """ Generates the PWL CSb signal""" + # values for NOP, W1, W0, W1, R0, NOP, W1, W0, R1, NOP + # Keep CSb asserted in NOP for measuring >1 period + values = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] + stimuli.gen_pwl(self.sf, "csb", clk_times, values, period, slew, 0.05) + + def gen_web(self, clk_times, period, slew): + """ Generates the PWL WEb signal""" + # values for NOP, W1, W0, W1, R0, NOP, W1, W0, R1, NOP + # Keep WEb deasserted in NOP for measuring >1 period + values = [1, 0, 0, 0, 1, 1, 0, 0, 1, 1] + stimuli.gen_pwl(self.sf, "web", clk_times, values, period, slew, 0.05) + + # Keep acc_en deasserted in NOP for measuring >1 period + values = [1, 0, 0, 0, 1, 1, 0, 0, 1, 1] + stimuli.gen_pwl(self.sf, "acc_en", clk_times, values, period, slew, 0) + values = [0, 1, 1, 1, 0, 0, 1, 1, 0, 0] + stimuli.gen_pwl(self.sf, "acc_en_inv", clk_times, values, period, slew, 0) + + def gen_oeb(self, clk_times, period, slew): + """ Generates the PWL WEb signal""" + # values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP + # Keep OEb asserted in NOP for measuring >1 period + values = [1, 1, 1, 1, 0, 0, 1, 1, 0, 0] + stimuli.gen_pwl(self.sf, "oeb", clk_times, values, period, slew, 0.05) diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index b2a87479..fb93a105 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -1,8 +1,5 @@ -import os -import sys -import re +import os,sys,re,shutil import debug -import tech import math import setup_hold import delay @@ -34,7 +31,9 @@ class lib: self.sram.word_size) else: # Else, use the non-reduced netlist file for simulation - self.sim_sp_file = self.sp_file + self.sim_sp_file = "{}sram.sp".format(OPTS.openram_temp) + # Make a copy in temp for debugging + shutil.copy(self.sp_file, self.sim_sp_file) # These are the parameters to determine the table sizes #self.load_scales = np.array([0.1, 0.25, 0.5, 1, 2, 4, 8]) diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index 7986f11e..9bba2796 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -134,71 +134,25 @@ def gen_pulse(stim_file, sig_name, v1=gnd_voltage, v2=vdd_voltage, offset=0, per def gen_pwl(stim_file, sig_name, clk_times, data_values, period, slew, setup): # the initial value is not a clock time - debug.check(len(clk_times)+1==len(data_values),"Clock and data value lengths don't match.") + debug.check(len(clk_times)==len(data_values),"Clock and data value lengths don't match.") + # shift signal times earlier for setup time times = np.array(clk_times) - setup*period values = np.array(data_values) * vdd_voltage half_slew = 0.5 * slew stim_file.write("V{0} {0} 0 PWL (0n {1}v ".format(sig_name, values[0])) - for i in range(len(times)): + for i in range(1,len(times)-1): stim_file.write("{0}n {1}v {2}n {3}v ".format(times[i]-half_slew, - values[i], + values[i-1], times[i]+half_slew, - values[i+1])) + values[i])) stim_file.write(")\n") -def gen_data(stim_file, clk_times, sig_name, period, slew): - """Generates the PWL data inputs for a simulation timing test.""" - # values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP - # we are asserting the opposite value on the other side of the tx gate during - # the read to be "worst case". Otherwise, it can actually assist the read. - values = [0, 1, 0, 1, 1, 1, 0, 0, 0 ] - gen_pwl(stim_file, sig_name, clk_times, values, period, slew, 0.05) - - -def gen_addr(stim_file, clk_times, addr, period, slew): - """Generates the address inputs for a simulation timing test. - One cycle is different to clear the bus - """ - - zero_values = [0, 0, 0, 1, 0, 0, 1, 0, 0 ] - ones_values = [1, 1, 1, 0, 1, 1, 0, 1, 1 ] - - for i in range(len(addr)): - sig_name = "A[{0}]".format(i) - if addr[i]=="1": - gen_pwl(stim_file, sig_name, clk_times, ones_values, period, slew, 0.05) - else: - gen_pwl(stim_file, sig_name, clk_times, zero_values, period, slew, 0.05) def gen_constant(stim_file, sig_name, v_val): """Generates a constant signal with reference voltage and the voltage value""" stim_file.write("V{0} {0} 0 DC {1}\n".format(sig_name, v_val)) -def gen_csb(stim_file, clk_times, period, slew): - """ Generates the PWL CSb signal""" - # values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP - values = [1, 0, 0, 0, 0, 0, 0, 0, 1] - gen_pwl(stim_file, "csb", clk_times, values, period, slew, 0.05) - -def gen_web(stim_file, clk_times, period, slew): - """ Generates the PWL WEb signal""" - # values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP - values = [1, 0, 0, 0, 1, 0, 0, 1, 1] - gen_pwl(stim_file, "web", clk_times, values, period, slew, 0.05) - - values = [1, 0, 0, 0, 1, 0, 0, 1, 1] - gen_pwl(stim_file, "acc_en", clk_times, values, period, slew, 0) - values = [0, 1, 1, 1, 0, 1, 1, 0, 0] - gen_pwl(stim_file, "acc_en_inv", clk_times, values, period, slew, 0) - -def gen_oeb(stim_file, clk_times, period, slew): - """ Generates the PWL WEb signal""" - # values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP - values = [1, 1, 1, 1, 0, 1, 1, 0, 1] - gen_pwl(stim_file, "oeb", clk_times, values, period, slew, 0.05) - - def get_inverse_voltage(value): diff --git a/compiler/characterizer/trim_spice.py b/compiler/characterizer/trim_spice.py index f53ac184..ead653b9 100644 --- a/compiler/characterizer/trim_spice.py +++ b/compiler/characterizer/trim_spice.py @@ -75,7 +75,8 @@ class trim_spice(): self.remove_insts("bitcell_array",[wl_name,bl_name]) # 2. Keep sense amps basd on BL - self.remove_insts("sense_amp_array",[bl_name]) + # FIXME: The bit lines are not indexed the same in sense_amp_array + #self.remove_insts("sense_amp_array",[bl_name]) # 3. Keep column muxes basd on BL self.remove_insts("column_mux_array",[bl_name])