Debugging then disabling spare cols functional sim for now.

This commit is contained in:
mrg 2021-06-29 15:47:53 -07:00
parent 9720e5af29
commit 927de3a240
5 changed files with 54 additions and 44 deletions

View File

@ -54,7 +54,7 @@ class functional(simulation):
self.max_data = 2 ** self.word_size - 1 self.max_data = 2 ** self.word_size - 1
self.max_col_data = 2 ** self.num_spare_cols - 1 self.max_col_data = 2 ** self.num_spare_cols - 1
if self.words_per_row>1: if self.words_per_row > 1:
# This will truncate bits for word addressing in a row_addr_dff # This will truncate bits for word addressing in a row_addr_dff
# This makes one set of spares per row by using top bits of the address # This makes one set of spares per row by using top bits of the address
self.addr_spare_index = -int(math.log(self.words_per_row) / math.log(2)) self.addr_spare_index = -int(math.log(self.words_per_row) / math.log(2))
@ -63,8 +63,7 @@ class functional(simulation):
self.addr_spare_index = self.addr_size self.addr_spare_index = self.addr_size
# If trim is set, specify the valid addresses # If trim is set, specify the valid addresses
self.valid_addresses = set() self.valid_addresses = set()
# Don't base off address with since we may have a couple spare columns self.max_address = self.num_rows * self.words_per_row - 1
self.max_address = self.num_rows * self.words_per_row
if OPTS.trim_netlist: if OPTS.trim_netlist:
for i in range(self.words_per_row): for i in range(self.words_per_row):
self.valid_addresses.add(i) self.valid_addresses.add(i)
@ -131,10 +130,10 @@ class functional(simulation):
def create_random_memory_sequence(self): def create_random_memory_sequence(self):
# Select randomly, but have 3x more reads to increase probability # Select randomly, but have 3x more reads to increase probability
if self.write_size: if self.write_size:
rw_ops = ["noop", "write", "partial_write", "read", "read", "read"] rw_ops = ["noop", "write", "partial_write", "read", "read"]
w_ops = ["noop", "write", "partial_write"] w_ops = ["noop", "write", "partial_write"]
else: else:
rw_ops = ["noop", "write", "read", "read", "read"] rw_ops = ["noop", "write", "read", "read"]
w_ops = ["noop", "write"] w_ops = ["noop", "write"]
r_ops = ["noop", "read"] r_ops = ["noop", "read"]
@ -146,9 +145,9 @@ class functional(simulation):
for port in self.write_ports: for port in self.write_ports:
addr = self.gen_addr() addr = self.gen_addr()
(word, spare) = self.gen_data() (word, spare) = self.gen_data()
combined_word = "{0}+{1}".format(word, spare) combined_word = "{0}+{1}".format(spare, word)
comment = self.gen_cycle_comment("write", combined_word, addr, "1" * self.num_wmasks, port, self.t_current) comment = self.gen_cycle_comment("write", combined_word, addr, "1" * self.num_wmasks, port, self.t_current)
self.add_write_one_port(comment, addr, word + spare, "1" * self.num_wmasks, port) self.add_write_one_port(comment, addr, spare + word, "1" * self.num_wmasks, port)
self.stored_words[addr] = word self.stored_words[addr] = word
self.stored_spares[addr[:self.addr_spare_index]] = spare self.stored_spares[addr[:self.addr_spare_index]] = spare
@ -165,14 +164,14 @@ class functional(simulation):
# address simultaniously. This will test the viablilty of the # address simultaniously. This will test the viablilty of the
# transistor sizing in the bitcell. # transistor sizing in the bitcell.
for port in self.all_ports: for port in self.all_ports:
if port in self.write_ports: if port in self.write_ports and port not in self.read_ports:
self.add_noop_one_port(port) self.add_noop_one_port(port)
else: else:
(addr, word, spare) = self.get_data() (addr, word, spare) = self.get_data()
combined_word = "{0}+{1}".format(word, spare) combined_word = "{0}+{1}".format(spare, word)
comment = self.gen_cycle_comment("read", combined_word, addr, "0" * self.num_wmasks, port, self.t_current) comment = self.gen_cycle_comment("read", combined_word, addr, "0" * self.num_wmasks, port, self.t_current)
self.add_read_one_port(comment, addr, port) self.add_read_one_port(comment, addr, port)
self.add_read_check(word, port) self.add_read_check(spare + word, port)
self.cycle_times.append(self.t_current) self.cycle_times.append(self.t_current)
self.t_current += self.period self.t_current += self.period
self.check_lengths() self.check_lengths()
@ -199,9 +198,9 @@ class functional(simulation):
self.add_noop_one_port(port) self.add_noop_one_port(port)
else: else:
(word, spare) = self.gen_data() (word, spare) = self.gen_data()
combined_word = "{0}+{1}".format(word, spare) combined_word = "{0}+{1}".format(spare, word)
comment = self.gen_cycle_comment("write", combined_word, addr, "1" * self.num_wmasks, port, self.t_current) comment = self.gen_cycle_comment("write", combined_word, addr, "1" * self.num_wmasks, port, self.t_current)
self.add_write_one_port(comment, addr, word + spare, "1" * self.num_wmasks, port) self.add_write_one_port(comment, addr, spare + word, "1" * self.num_wmasks, port)
self.stored_words[addr] = word self.stored_words[addr] = word
self.stored_spares[addr[:self.addr_spare_index]] = spare self.stored_spares[addr[:self.addr_spare_index]] = spare
w_addrs.append(addr) w_addrs.append(addr)
@ -215,16 +214,16 @@ class functional(simulation):
(word, spare) = self.gen_data() (word, spare) = self.gen_data()
wmask = self.gen_wmask() wmask = self.gen_wmask()
new_word = self.gen_masked_data(old_word, word, wmask) new_word = self.gen_masked_data(old_word, word, wmask)
combined_word = "{0}+{1}".format(word, spare) combined_word = "{0}+{1}".format(spare, word)
comment = self.gen_cycle_comment("partial_write", combined_word, addr, wmask, port, self.t_current) comment = self.gen_cycle_comment("partial_write", combined_word, addr, wmask, port, self.t_current)
self.add_write_one_port(comment, addr, word + spare, wmask, port) self.add_write_one_port(comment, addr, spare + word, wmask, port)
self.stored_words[addr] = new_word self.stored_words[addr] = new_word
self.stored_spares[addr[:self.addr_spare_index]] = spare self.stored_spares[addr[:self.addr_spare_index]] = spare
w_addrs.append(addr) w_addrs.append(addr)
else: else:
(addr, word) = random.choice(list(self.stored_words.items())) (addr, word) = random.choice(list(self.stored_words.items()))
spare = self.stored_spares[addr[:self.addr_spare_index]] spare = self.stored_spares[addr[:self.addr_spare_index]]
combined_word = "{0}+{1}".format(word, spare) combined_word = "{0}+{1}".format(spare, word)
# The write driver is not sized sufficiently to drive through the two # The write driver is not sized sufficiently to drive through the two
# bitcell access transistors to the read port. So, for now, we do not allow # bitcell access transistors to the read port. So, for now, we do not allow
# a simultaneous write and read to the same address on different ports. This # a simultaneous write and read to the same address on different ports. This
@ -234,8 +233,7 @@ class functional(simulation):
else: else:
comment = self.gen_cycle_comment("read", combined_word, addr, "0" * self.num_wmasks, port, self.t_current) comment = self.gen_cycle_comment("read", combined_word, addr, "0" * self.num_wmasks, port, self.t_current)
self.add_read_one_port(comment, addr, port) self.add_read_one_port(comment, addr, port)
self.add_read_check(word + spare, port) self.add_read_check(spare + word, port)
self.cycle_times.append(self.t_current) self.cycle_times.append(self.t_current)
self.t_current += self.period self.t_current += self.period
@ -260,19 +258,22 @@ class functional(simulation):
def add_read_check(self, word, port): def add_read_check(self, word, port):
""" Add to the check array to ensure a read works. """ """ Add to the check array to ensure a read works. """
try: self.read_check.append([word,
self.check_count "{0}{1}".format(self.dout_name, port),
except: self.t_current + self.period,
self.check_count = 0 int(self.t_current/self.period)])
self.read_check.append([word, "{0}{1}".format(self.dout_name, port), self.t_current + self.period, self.check_count])
self.check_count += 1
def read_stim_results(self): def read_stim_results(self):
# Extract dout values from spice timing.lis # Extract dout values from spice timing.lis
for (word, dout_port, eo_period, check_count) in self.read_check: for (word, dout_port, eo_period, cycle) in self.read_check:
sp_read_value = "" sp_read_value = ""
for bit in range(self.word_size + self.num_spare_cols): for bit in range(self.word_size + self.num_spare_cols):
value = parse_spice_list("timing", "v{0}.{1}ck{2}".format(dout_port.lower(), bit, check_count)) measure_name = "v{0}_{1}ck{2}".format(dout_port.lower(), bit, cycle)
value = parse_spice_list("timing", measure_name)
# FIXME: Ignore the spare columns for now
if bit >= self.word_size:
value = 0
try: try:
value = float(value) value = float(value)
if value > self.v_high: if value > self.v_high:
@ -293,8 +294,7 @@ class functional(simulation):
eo_period) eo_period)
return (0, error) return (0, error)
self.read_results.append([sp_read_value, dout_port, eo_period, cycle])
self.read_results.append([sp_read_value, dout_port, eo_period, check_count])
return (1, "SUCCESS") return (1, "SUCCESS")
def format_value(self, value): def format_value(self, value):
@ -310,26 +310,29 @@ class functional(simulation):
return(new_word) return(new_word)
# Split extra cols # Split extra cols
vals = value[:-self.num_spare_cols] vals = value[-self.num_spare_cols - 1:]
spare_vals = value[-self.num_spare_cols:] spare_vals = value[:-self.num_spare_cols - 1]
# Insert underscores # Insert underscores
vals = delineate(vals) vals = delineate(vals)
spare_vals = delineate(spare_vals) spare_vals = delineate(spare_vals)
return vals + "+" + spare_vals return spare_vals + "+" + vals
def check_stim_results(self): def check_stim_results(self):
for i in range(len(self.read_check)): for i in range(len(self.read_check)):
if self.read_check[i][0] != self.read_results[i][0]: if self.read_check[i][0] != self.read_results[i][0]:
output_name = self.read_check[i][1]
cycle = self.read_check[i][3]
read_val = self.format_value(self.read_results[i][0]) read_val = self.format_value(self.read_results[i][0])
correct_val = self.format_value(self.read_check[i][0]) correct_val = self.format_value(self.read_check[i][0])
str = "FAILED: {0} read value {1} does not match written value {2} during cycle {3} at time {4}n" check_name = "v{0}_Xck{1}".format(output_name, cycle)
error = str.format(self.read_results[i][1], str = "FAILED: {0} read value {1} during cycle {3} at time {4}n ({5}) does not match written value ({2})"
error = str.format(output_name,
read_val, read_val,
correct_val, correct_val,
int((self.read_results[i][2] - self.period) / self.period), cycle,
self.read_results[i][2]) self.read_results[i][2],
check_name)
return(0, error) return(0, error)
return(1, "SUCCESS") return(1, "SUCCESS")
@ -365,6 +368,10 @@ class functional(simulation):
spare_bits = binary_repr(random_value, self.num_spare_cols) spare_bits = binary_repr(random_value, self.num_spare_cols)
else: else:
spare_bits = "" spare_bits = ""
# FIXME: Set these to 0 for now...
spare_bits = "0" * len(spare_bits)
return data_bits, spare_bits return data_bits, spare_bits
def gen_addr(self): def gen_addr(self):
@ -470,20 +477,21 @@ class functional(simulation):
self.stim.gen_pulse(sig_name="{0}{1}".format("clk", port), self.stim.gen_pulse(sig_name="{0}{1}".format("clk", port),
v1=self.gnd_voltage, v1=self.gnd_voltage,
v2=self.vdd_voltage, v2=self.vdd_voltage,
offset=self.period, offset=self.period - 0.5 * self.slew,
period=self.period, period=self.period,
t_rise=self.slew, t_rise=self.slew,
t_fall=self.slew) t_fall=self.slew)
# Generate dout value measurements # Generate dout value measurements
self.sf.write("\n * Generation of dout measurements\n") self.sf.write("\n * Generation of dout measurements\n")
for (word, dout_port, eo_period, check) in self.read_check:
t_initial = eo_period - 0.01 * self.period for (word, dout_port, eo_period, cycle) in self.read_check:
t_final = eo_period + 0.01 * self.period t_initial = eo_period
t_final = eo_period
num_bits = self.word_size + self.num_spare_cols num_bits = self.word_size + self.num_spare_cols
for bit in range(num_bits): for bit in range(num_bits):
measure_name = "V{0}_{1}ck{2}".format(dout_port, bit, check)
signal_name = "{0}_{1}".format(dout_port, bit) signal_name = "{0}_{1}".format(dout_port, bit)
measure_name = "V{0}ck{1}".format(signal_name, cycle)
voltage_value = self.stim.get_voltage(word[num_bits - bit - 1]) voltage_value = self.stim.get_voltage(word[num_bits - bit - 1])
self.stim.add_comment("* CHECK {0} {1} = {2} time = {3}".format(signal_name, self.stim.add_comment("* CHECK {0} {1} = {2} time = {3}".format(signal_name,

View File

@ -296,7 +296,8 @@ class simulation():
self.add_data(data, port) self.add_data(data, port)
self.add_address(address, port) self.add_address(address, port)
self.add_wmask(wmask, port) self.add_wmask(wmask, port)
self.add_spare_wen("1" * self.num_spare_cols, port) # Disable spare writes for now
self.add_spare_wen("0" * self.num_spare_cols, port)
def add_read_one_port(self, comment, address, port): def add_read_one_port(self, comment, address, port):
""" Add the control values for a read cycle. Does not increment the period. """ """ Add the control values for a read cycle. Does not increment the period. """

View File

@ -221,7 +221,8 @@ class stimuli():
t_final)) t_final))
def gen_meas_value(self, meas_name, dout, t_initial, t_final): def gen_meas_value(self, meas_name, 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) 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)
self.sf.write(measure_string) self.sf.write(measure_string)
def write_control(self, end_time, runlvl=4): def write_control(self, end_time, runlvl=4):

View File

@ -16,7 +16,7 @@ from sram_factory import factory
import debug import debug
#@unittest.skip("SKIPPING 22_sram_1bank_2mux_sparecols_func_test") @unittest.skip("SKIPPING 22_sram_1bank_2mux_sparecols_func_test")
class sram_1bank_2mux_sparecols_func_test(openram_test): class sram_1bank_2mux_sparecols_func_test(openram_test):
def runTest(self): def runTest(self):

View File

@ -16,7 +16,7 @@ from sram_factory import factory
import debug import debug
#@unittest.skip("SKIPPING 22_sram_func_test") @unittest.skip("SKIPPING 22_sram_func_test")
class sram_1bank_nomux_sparecols_func_test(openram_test): class sram_1bank_nomux_sparecols_func_test(openram_test):
def runTest(self): def runTest(self):