Use built in binary conversion. Improve spare debug output.

This commit is contained in:
mrg 2021-04-07 14:23:47 -07:00
parent 229b0059c4
commit 61b1b90dd3
1 changed files with 29 additions and 23 deletions

View File

@ -9,6 +9,7 @@ import collections
import debug import debug
import random import random
import math import math
from numpy import binary_repr
from .stimuli import * from .stimuli import *
from .charutils import * from .charutils import *
from globals import OPTS from globals import OPTS
@ -53,7 +54,13 @@ 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
self.words_per_row_bits = int(math.log(self.words_per_row) / math.log(2)) if self.words_per_row>1:
# 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
self.addr_spare_index = -int(math.log(self.words_per_row) / math.log(2))
else:
# This will select the entire address when one word per row
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()
self.max_address = 2**self.addr_size - 1 + (self.num_spare_rows * self.words_per_row) self.max_address = 2**self.addr_size - 1 + (self.num_spare_rows * self.words_per_row)
@ -137,10 +144,11 @@ 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()
comment = self.gen_cycle_comment("write", word, addr, "1" * self.num_wmasks, port, self.t_current) combined_word = "{}+{}".format(word, spare)
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, word + spare, "1" * self.num_wmasks, port)
self.stored_words[addr] = word self.stored_words[addr] = word
self.stored_spares[addr[:-self.words_per_row_bits]] = spare self.stored_spares[addr[:self.addr_spare_index]] = spare
# All other read-only ports are noops. # All other read-only ports are noops.
for port in self.read_ports: for port in self.read_ports:
@ -158,7 +166,9 @@ class functional(simulation):
if port in self.write_ports: if port in self.write_ports:
self.add_noop_one_port(port) self.add_noop_one_port(port)
else: else:
comment = self.gen_cycle_comment("read", word, addr, "0" * self.num_wmasks, port, self.t_current) (addr, word, spare) = self.get_data()
combined_word = "{}+{}".format(word, spare)
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(word, port)
self.cycle_times.append(self.t_current) self.cycle_times.append(self.t_current)
@ -187,14 +197,15 @@ 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()
comment = self.gen_cycle_comment("write", word, addr, "1" * self.num_wmasks, port, self.t_current) combined_word = "{}+{}".format(word, spare)
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, word + spare, "1" * self.num_wmasks, port)
self.stored_words[addr] = word self.stored_words[addr] = word
self.stored_spares[addr[:-self.words_per_row_bits]] = spare self.stored_spares[addr[:self.addr_spare_index]] = spare
w_addrs.append(addr) w_addrs.append(addr)
elif op == "partial_write": elif op == "partial_write":
# write only to a word that's been written to # write only to a word that's been written to
(addr, old_word, old_spares) = self.get_data() (addr, old_word, old_spare) = self.get_data()
# two ports cannot write to the same address # two ports cannot write to the same address
if addr in w_addrs: if addr in w_addrs:
self.add_noop_one_port(port) self.add_noop_one_port(port)
@ -202,15 +213,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)
comment = self.gen_cycle_comment("partial_write", word, addr, wmask, port, self.t_current) combined_word = "{}+{}".format(word, spare)
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, word + spare, wmask, port)
self.stored_words[addr] = new_word self.stored_words[addr] = new_word
self.stored_spares[addr[:-self.words_per_row_bits]] = 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.words_per_row_bits]] spare = self.stored_spares[addr[:self.addr_spare_index]]
combined_word = word + spare combined_word = "{}+{}".format(word, spare)
# 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
@ -220,7 +232,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(combined_word, port) self.add_read_check(word + spare, 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
@ -286,7 +298,7 @@ class functional(simulation):
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]:
str = "FAILED: {0} value {1} does not match written value {2} read during cycle {3} at time {4}n" str = "FAILED: {0} read value {1} does not match written value {2} during cycle {3} at time {4}n"
error = str.format(self.read_results[i][1], error = str.format(self.read_results[i][1],
self.read_results[i][0], self.read_results[i][0],
self.read_check[i][0], self.read_check[i][0],
@ -321,10 +333,10 @@ class functional(simulation):
def gen_data(self): def gen_data(self):
""" Generates a random word to write. """ """ Generates a random word to write. """
random_value = random.randint(0, self.max_data) random_value = random.randint(0, self.max_data)
data_bits = self.convert_to_bin(random_value, self.word_size) data_bits = binary_repr(random_value, self.word_size)
if self.num_spare_cols>0: if self.num_spare_cols>0:
random_value = random.randint(0, self.max_col_data) random_value = random.randint(0, self.max_col_data)
spare_bits = self.convert_to_bin(random_value, self.num_spare_cols) spare_bits = binary_repr(random_value, self.num_spare_cols)
else: else:
spare_bits = "" spare_bits = ""
return data_bits, spare_bits return data_bits, spare_bits
@ -335,7 +347,7 @@ class functional(simulation):
random_value = random.sample(self.valid_addresses, 1)[0] random_value = random.sample(self.valid_addresses, 1)[0]
else: else:
random_value = random.randint(0, self.max_address) random_value = random.randint(0, self.max_address)
addr_bits = self.convert_to_bin(random_value, self.addr_size) addr_bits = binary_repr(random_value, self.addr_size)
return addr_bits return addr_bits
def get_data(self): def get_data(self):
@ -343,15 +355,9 @@ class functional(simulation):
# Used for write masks since they should be writing to previously written addresses # Used for write masks since they should be writing to previously written addresses
addr = random.choice(list(self.stored_words.keys())) addr = random.choice(list(self.stored_words.keys()))
word = self.stored_words[addr] word = self.stored_words[addr]
spare = self.stored_spares[addr[:-self.words_per_row_bits]] spare = self.stored_spares[addr[:self.addr_spare_index]]
return (addr, word, spare) return (addr, word, spare)
def convert_to_bin(self, value, size):
new_value = str.replace(bin(value), "0b", "")
for i in range(size - len(new_value)):
new_value = "0" + new_value
return new_value
def write_functional_stimulus(self): def write_functional_stimulus(self):
""" Writes SPICE stimulus. """ """ Writes SPICE stimulus. """
self.stim_sp = "functional_stim.sp" self.stim_sp = "functional_stim.sp"