diff --git a/compiler/characterizer/functional.py b/compiler/characterizer/functional.py index 9fad2be5..9b3a1fd2 100644 --- a/compiler/characterizer/functional.py +++ b/compiler/characterizer/functional.py @@ -141,23 +141,25 @@ class functional(simulation): comment = self.gen_cycle_comment("noop", "0" * self.word_size, "0" * self.addr_size, "0" * self.num_wmasks, 0, self.t_current) self.add_noop_all_ports(comment) - # 1. Write all the write ports first to seed a bunch of locations. - for port in self.write_ports: - addr = self.gen_addr() - (word, spare) = self.gen_data() - combined_word = self.combine_word(spare, word) - comment = self.gen_cycle_comment("write", combined_word, addr, "1" * self.num_wmasks, port, self.t_current) - self.add_write_one_port(comment, addr, spare + word, "1" * self.num_wmasks, port) - self.stored_words[addr] = word - self.stored_spares[addr[:self.addr_spare_index]] = spare - # All other read-only ports are noops. - for port in self.read_ports: - if port not in self.write_ports: - self.add_noop_one_port(port) - self.cycle_times.append(self.t_current) - self.t_current += self.period - self.check_lengths() + # 1. Write all the write ports 2x to seed a bunch of locations. + for i in range(3): + for port in self.write_ports: + addr = self.gen_addr() + (word, spare) = self.gen_data() + combined_word = self.combine_word(spare, word) + comment = self.gen_cycle_comment("write", combined_word, addr, "1" * self.num_wmasks, port, self.t_current) + self.add_write_one_port(comment, addr, spare + word, "1" * self.num_wmasks, port) + self.stored_words[addr] = word + self.stored_spares[addr[:self.addr_spare_index]] = spare + + # All other read-only ports are noops. + for port in self.read_ports: + if port not in self.write_ports: + self.add_noop_one_port(port) + self.cycle_times.append(self.t_current) + self.t_current += self.period + self.check_lengths() # 2. Read at least once. For multiport, it is important that one # read cycle uses all RW and R port to read from the same @@ -297,38 +299,6 @@ class functional(simulation): self.read_results.append([sp_read_value, dout_port, eo_period, cycle]) return (1, "SUCCESS") - def combine_word(self, spare, word): - if len(spare) > 0: - return spare + "+" + word - - return word - - def format_value(self, value): - """ Format in better readable manner """ - - def delineate(word): - # Create list of chars in reverse order - split_word = list(reversed([x for x in word])) - # Add underscore every 4th char - split_word2 = [x + '_' * (n != 0 and n % 4 == 0) for n, x in enumerate(split_word)] - # Join the word unreversed back together - new_word = ''.join(reversed(split_word2)) - return(new_word) - - # Split extra cols - if self.num_spare_cols > 0: - vals = value[self.num_spare_cols:] - spare_vals = value[:self.num_spare_cols] - else: - vals = value - spare_vals = "" - - # Insert underscores - vals = delineate(vals) - spare_vals = delineate(spare_vals) - - return self.combine_word(spare_vals, vals) - def check_stim_results(self): for i in range(len(self.read_check)): if self.read_check[i][0] != self.read_results[i][0]: @@ -372,10 +342,12 @@ class functional(simulation): def gen_data(self): """ Generates a random word to write. """ - random_value = random.randint(0, self.max_data) + # Don't use 0 or max value + random_value = random.randint(1, self.max_data - 1) data_bits = binary_repr(random_value, self.word_size) if self.num_spare_cols>0: - random_value = random.randint(0, self.max_col_data) + # Don't use 0 or max value + random_value = random.randint(1, self.max_col_data - 1) spare_bits = binary_repr(random_value, self.num_spare_cols) else: spare_bits = "" @@ -498,7 +470,7 @@ class functional(simulation): for (word, dout_port, eo_period, cycle) in self.read_check: t_initial = eo_period - t_final = eo_period + t_final = eo_period + 0.01 * self.period num_bits = self.word_size + self.num_spare_cols for bit in range(num_bits): signal_name = "{0}_{1}".format(dout_port, bit) diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index 2f319b93..d7539dc4 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -372,6 +372,38 @@ class simulation(): time_spacing, comment)) + def combine_word(self, spare, word): + if len(spare) > 0: + return spare + "+" + word + + return word + + def format_value(self, value): + """ Format in better readable manner """ + + def delineate(word): + # Create list of chars in reverse order + split_word = list(reversed([x for x in word])) + # Add underscore every 4th char + split_word2 = [x + '_' * (n != 0 and n % 4 == 0) for n, x in enumerate(split_word)] + # Join the word unreversed back together + new_word = ''.join(reversed(split_word2)) + return(new_word) + + # Split extra cols + if self.num_spare_cols > 0: + vals = value[self.num_spare_cols:] + spare_vals = value[:self.num_spare_cols] + else: + vals = value + spare_vals = "" + + # Insert underscores + vals = delineate(vals) + spare_vals = delineate(spare_vals) + + return self.combine_word(spare_vals, vals) + def gen_cycle_comment(self, op, word, addr, wmask, port, t_current): if op == "noop": str = "\tIdle during cycle {0} ({1}ns - {2}ns)" diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index f546cb96..b9e4b3c7 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -222,7 +222,7 @@ class stimuli(): def gen_meas_value(self, meas_name, dout, t_initial, t_final): measure_string=".meas tran {0} FIND v({1}) AT={2}n\n\n".format(meas_name.lower(), dout, (t_initial + t_final) / 2) - # measure_string=".meas tran {0} AVG v({1}) FROM={2}n TO={3}n\n\n".format(meas_name.lower(), dout, t_initial, t_final) + #measure_string=".meas tran {0} AVG v({1}) FROM={2}n TO={3}n\n\n".format(meas_name.lower(), dout, t_initial, t_final) self.sf.write(measure_string) def write_control(self, end_time, runlvl=4): @@ -237,12 +237,13 @@ class stimuli(): reltol = 0.005 # 0.5% else: reltol = 0.001 # 0.1% - timestep = 10 # ps, was 5ps but ngspice was complaining the timestep was too small in certain tests. + timestep = 10 # ps if OPTS.spice_name == "ngspice": self.sf.write(".TEMP {}\n".format(self.temperature)) # UIC is needed for ngspice to converge - self.sf.write(".TRAN {0}p {1}n UIC\n".format(timestep, end_time)) + # Format: .tran tstep tstop < tstart < tmax >> + self.sf.write(".TRAN {0}p {1}n 0n {0}p UIC\n".format(timestep, end_time)) # ngspice sometimes has convergence problems if not using gear method # which is more accurate, but slower than the default trapezoid method # Do not remove this or it may not converge due to some "pa_00" nodes @@ -268,7 +269,8 @@ class stimuli(): self.sf.write("simulator lang=spice\n") elif OPTS.spice_name in ["hspice", "xa"]: self.sf.write(".TEMP {}\n".format(self.temperature)) - self.sf.write(".TRAN {0}p {1}n UIC\n".format(timestep, end_time)) + # Format: .tran tstep tstop < tstart < tmax >> + self.sf.write(".TRAN {0}p {1}n 0n {0}p UIC\n".format(timestep, end_time)) self.sf.write(".OPTIONS POST=1 RUNLVL={0} PROBE\n".format(runlvl)) self.sf.write(".OPTIONS PSF=1 \n") self.sf.write(".OPTIONS HIER_DELIM=1 \n") @@ -276,7 +278,9 @@ class stimuli(): self.sf.write(".OPTIONS DEVICE TEMP={}\n".format(self.temperature)) self.sf.write(".OPTIONS MEASURE MEASFAIL=1\n") self.sf.write(".OPTIONS LINSOL type=klu\n") - self.sf.write(".TRAN {0}p {1}n\n".format(timestep, end_time)) + self.sf.write(".OPTIONS TIMEINT RELTOL=1e-6 ABSTOL=1e-10 method=gear minorder=2\n") + # Format: .TRAN + self.sf.write(".TRAN {0}p {1}n 0n {0}p\n".format(timestep, end_time)) elif OPTS.spice_name: debug.error("Unkown spice simulator {}".format(OPTS.spice_name), -1)