mirror of https://github.com/VLSIDA/OpenRAM.git
Edits to functional simulation.
Use correct .TRAN with max timestep. Seed functional sim with a 3 writes to start for more read addresses. Move formatting code to simulation module to share.
This commit is contained in:
parent
278c40f4b7
commit
bbdc728ac5
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)"
|
||||
|
|
|
|||
|
|
@ -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 <initial step> <final time> <start time> <step ceiling>
|
||||
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)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue