mirror of https://github.com/VLSIDA/OpenRAM.git
Improvements to functional test. Now will read or write in a random sequence, using randomly generated words and addresses, and using random ports in the multiported cases. Functional test still has some bugs that are being worked out so it will sometimes fail and sometimes not fail.
This commit is contained in:
parent
7b4e001885
commit
6ef1a3c755
|
|
@ -63,16 +63,16 @@ class design(hierarchy_design):
|
||||||
port_number = 0
|
port_number = 0
|
||||||
|
|
||||||
for port in range(OPTS.num_rw_ports):
|
for port in range(OPTS.num_rw_ports):
|
||||||
self.write_index.append("{}".format(port_number))
|
self.write_index.append(port_number)
|
||||||
self.read_index.append("{}".format(port_number))
|
self.read_index.append(port_number)
|
||||||
self.port_id.append("rw")
|
self.port_id.append("rw")
|
||||||
port_number += 1
|
port_number += 1
|
||||||
for port in range(OPTS.num_w_ports):
|
for port in range(OPTS.num_w_ports):
|
||||||
self.write_index.append("{}".format(port_number))
|
self.write_index.append(port_number)
|
||||||
self.port_id.append("w")
|
self.port_id.append("w")
|
||||||
port_number += 1
|
port_number += 1
|
||||||
for port in range(OPTS.num_r_ports):
|
for port in range(OPTS.num_r_ports):
|
||||||
self.read_index.append("{}".format(port_number))
|
self.read_index.append(port_number)
|
||||||
self.port_id.append("r")
|
self.port_id.append("r")
|
||||||
port_number += 1
|
port_number += 1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,325 +24,136 @@ class functional(simulation):
|
||||||
self.set_corner(corner)
|
self.set_corner(corner)
|
||||||
self.set_spice_constants()
|
self.set_spice_constants()
|
||||||
self.set_stimulus_variables()
|
self.set_stimulus_variables()
|
||||||
|
self.create_signal_names()
|
||||||
|
|
||||||
# Number of checks can be changed
|
# Number of checks can be changed
|
||||||
self.num_checks = 1
|
self.num_cycles = 2
|
||||||
self.cycles = 0
|
self.stored_words = {}
|
||||||
self.eo_period = []
|
self.write_check = []
|
||||||
|
self.read_check = []
|
||||||
# set to 1 if functional simulation fails during any check
|
|
||||||
self.functional_fail = 0
|
|
||||||
self.error = ""
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
""" Main function to generate random writes/reads, run spice, and analyze results """
|
# Generate a random sequence of reads and writes
|
||||||
self.noop()
|
self.write_random_memory_sequence()
|
||||||
|
|
||||||
self.overwrite_test()
|
|
||||||
self.write_read_test()
|
|
||||||
|
|
||||||
self.noop()
|
|
||||||
|
|
||||||
# Run SPICE simulation
|
# Run SPICE simulation
|
||||||
self.write_functional_stimulus()
|
self.write_functional_stimulus()
|
||||||
self.stim.run_sim()
|
self.stim.run_sim()
|
||||||
|
|
||||||
# Extrat DOUT values from spice timing.lis
|
# read DOUT values from SPICE simulation. If the values do not fall within the noise margins, return the error.
|
||||||
for i in range(2*self.num_checks):
|
(success, error) = self.read_stim_results()
|
||||||
self.sp_read_value = ["" for port in range(self.total_read)]
|
if not success:
|
||||||
for port in range(self.total_read):
|
return (0, error)
|
||||||
for bit in range(self.word_size):
|
|
||||||
value = parse_spice_list("timing", "vdout{0}.{1}.ck{2}".format(self.read_index[port],bit,i))
|
|
||||||
if value > 0.9 * self.vdd_voltage:
|
|
||||||
self.sp_read_value[port] = "1" + self.sp_read_value[port]
|
|
||||||
elif value < 0.1 * self.vdd_voltage:
|
|
||||||
self.sp_read_value[port] = "0" + self.sp_read_value[port]
|
|
||||||
else:
|
|
||||||
self.functional_fail = 1
|
|
||||||
self.error ="FAILED: DOUT{0}[{1}] value {2} at time {3}n does not fall within noise margins <{4} or >{5}.".format(port,
|
|
||||||
bit,
|
|
||||||
value,
|
|
||||||
self.eo_period[i],
|
|
||||||
0.1*self.vdd_voltage,
|
|
||||||
0.9*self.vdd_voltage)
|
|
||||||
|
|
||||||
if self.functional_fail:
|
|
||||||
return (self.functional_fail, self.error)
|
|
||||||
|
|
||||||
if i < self.num_checks:
|
|
||||||
self.read_values_over_test[i].append(self.sp_read_value[port])
|
|
||||||
else:
|
|
||||||
self.read_values_test[i-self.num_checks].append(self.sp_read_value[port])
|
|
||||||
|
|
||||||
# Compare written values to read values
|
|
||||||
for i in range(self.num_checks):
|
|
||||||
debug.info(1, "Stored Word - Overwrite Test: {}".format(self.stored_values_over_test[i]))
|
|
||||||
debug.info(1, "Read Word - Overwrite Test: {}".format(self.read_values_over_test[i]))
|
|
||||||
for port in range(self.total_read):
|
|
||||||
if self.stored_values_over_test[i] != self.read_values_over_test[i][port]:
|
|
||||||
self.functional_fail = 1
|
|
||||||
self.error ="FAILED: Overwrite Test - read value {0} does not match writen value {1}.".format(self.read_values_over_test[i][port],
|
|
||||||
self.stored_values_over_test[i])
|
|
||||||
|
|
||||||
for i in range(self.num_checks):
|
|
||||||
debug.info(1, "Stored Word - Standard W/R Test: {}".format(self.stored_values_test[i]))
|
|
||||||
debug.info(1, "Read Word - Standard W/R Test: {}".format(self.read_values_test[i]))
|
|
||||||
for port in range(self.total_read):
|
|
||||||
if self.stored_values_test[i] != self.read_values_test[i][port]:
|
|
||||||
self.functional_fail = 1
|
|
||||||
self.error ="FAILED: Standard W/R Test - read value {0} does not match writen value {1}.".format(self.read_values_test[i][port],
|
|
||||||
self.stored_values_test[i])
|
|
||||||
|
|
||||||
return (self.functional_fail, self.error)
|
|
||||||
|
|
||||||
def multiport_run(self):
|
|
||||||
""" Main function to generate random writes/reads, run spice, and analyze results. This function includes a multiport check. """
|
|
||||||
self.noop()
|
|
||||||
|
|
||||||
self.multi_read_test()
|
|
||||||
self.overwrite_test()
|
|
||||||
self.write_read_test()
|
|
||||||
|
|
||||||
self.noop()
|
|
||||||
|
|
||||||
# Run SPICE simulation
|
|
||||||
self.write_functional_stimulus()
|
|
||||||
self.stim.run_sim()
|
|
||||||
|
|
||||||
# Extrat DOUT values from spice timing.lis
|
|
||||||
for i in range(3*self.num_checks):
|
|
||||||
self.sp_read_value = ["" for port in range(self.total_read)]
|
|
||||||
for port in range(self.total_read):
|
|
||||||
for bit in range(self.word_size):
|
|
||||||
value = parse_spice_list("timing", "vdout{0}.{1}.ck{2}".format(self.read_index[port],bit,i))
|
|
||||||
if value > 0.9 * self.vdd_voltage:
|
|
||||||
self.sp_read_value[port] = "1" + self.sp_read_value[port]
|
|
||||||
elif value < 0.1 * self.vdd_voltage:
|
|
||||||
self.sp_read_value[port] = "0" + self.sp_read_value[port]
|
|
||||||
else:
|
|
||||||
self.functional_fail = 1
|
|
||||||
self.error ="FAILED: DOUT{0}[{1}] value {2} at time {3}n does not fall within noise margins <{4} or >{5}.".format(port,
|
|
||||||
bit,
|
|
||||||
value,
|
|
||||||
self.eo_period[i],
|
|
||||||
0.1*self.vdd_voltage,
|
|
||||||
0.9*self.vdd_voltage)
|
|
||||||
|
|
||||||
if self.functional_fail:
|
|
||||||
return (self.functional_fail, self.error)
|
|
||||||
|
|
||||||
if i < self.num_checks:
|
|
||||||
self.read_values_multi_test[i][self.multi_addrs[i][port]] = self.sp_read_value[port]
|
|
||||||
elif i < 2*self.num_checks:
|
|
||||||
self.read_values_over_test[i-self.num_checks].append(self.sp_read_value[port])
|
|
||||||
else:
|
|
||||||
self.read_values_test[i-2*self.num_checks].append(self.sp_read_value[port])
|
|
||||||
|
|
||||||
# Compare written values to read values
|
|
||||||
for i in range(self.num_checks):
|
|
||||||
debug.info(1, "Stored Words - Multi Test (addr:word): {}".format(self.stored_values_multi_test[i]))
|
|
||||||
debug.info(1, "Read Words - Mutlti Test (addr:word): {}".format(self.read_values_multi_test[i]))
|
|
||||||
for addr in self.multi_addrs[i]:
|
|
||||||
if self.stored_values_multi_test[i][addr] != self.read_values_multi_test[i][addr]:
|
|
||||||
self.functional_fail = 1
|
|
||||||
self.error ="FAILED: Multi Test - read value {0} does not match writen value {1}.".format(self.read_values_multi_test[i][addr],
|
|
||||||
self.stored_values_multi_test[i][addr])
|
|
||||||
|
|
||||||
for i in range(self.num_checks):
|
|
||||||
debug.info(1, "Stored Word - Overwrite Test: {}".format(self.stored_values_over_test[i]))
|
|
||||||
debug.info(1, "Read Word - Overwrite Test: {}".format(self.read_values_over_test[i]))
|
|
||||||
for port in range(self.total_read):
|
|
||||||
if self.stored_values_over_test[i] != self.read_values_over_test[i][port]:
|
|
||||||
self.functional_fail = 1
|
|
||||||
self.error ="FAILED: Overwrite Test - read value {0} does not match writen value {1}.".format(self.read_values_over_test[i][port],
|
|
||||||
self.stored_values_over_test[i])
|
|
||||||
|
|
||||||
for i in range(self.num_checks):
|
|
||||||
debug.info(1, "Stored Word - Standard W/R Test: {}".format(self.stored_values_test[i]))
|
|
||||||
debug.info(1, "Read Word - Standard W/R Test: {}".format(self.read_values_test[i]))
|
|
||||||
for port in range(self.total_read):
|
|
||||||
if self.stored_values_test[i] != self.read_values_test[i][port]:
|
|
||||||
self.functional_fail = 1
|
|
||||||
self.error ="FAILED: Standard W/R Test - read value {0} does not match writen value {1}.".format(self.read_values_test[i][port],
|
|
||||||
self.stored_values_test[i])
|
|
||||||
|
|
||||||
return (self.functional_fail, self.error)
|
|
||||||
|
|
||||||
def multi_read_test(self):
|
|
||||||
""" Multiport functional test to see if mutliple words on multiple addresses can be accessed at the same time. """
|
|
||||||
self.stored_values_multi_test = [{} for i in range(self.num_checks)]
|
|
||||||
self.read_values_multi_test = [{} for i in range(self.num_checks)]
|
|
||||||
self.multi_addrs = []
|
|
||||||
|
|
||||||
for i in range(self.num_checks):
|
|
||||||
# Write random words to a random addresses until there are as many stored words as there are RW and R ports
|
|
||||||
while(len(self.stored_values_multi_test[i]) < self.total_read):
|
|
||||||
addr = self.gen_addr()
|
|
||||||
word = self.gen_data()
|
|
||||||
self.write(addr,word)
|
|
||||||
self.stored_values_multi_test[i][addr] = word
|
|
||||||
|
|
||||||
# Each RW and R port will read from a different address
|
|
||||||
stored_addrs = []
|
|
||||||
stored_words = []
|
|
||||||
for (addr,word) in self.stored_values_multi_test[i].items():
|
|
||||||
stored_addrs.append(addr)
|
|
||||||
stored_words.append(word)
|
|
||||||
|
|
||||||
self.multi_addrs.append(stored_addrs)
|
|
||||||
self.multi_read(stored_addrs,stored_words)
|
|
||||||
|
|
||||||
def overwrite_test(self):
|
|
||||||
""" Functional test to see if a word at a particular address can be overwritten without being corrupted. """
|
|
||||||
self.stored_values_over_test = []
|
|
||||||
self.read_values_over_test = [[] for i in range(self.num_checks)]
|
|
||||||
|
|
||||||
for i in range(self.num_checks):
|
|
||||||
# Write a random word to a random address 3 different times, overwriting the stored word twice
|
|
||||||
addr = self.gen_addr()
|
|
||||||
for j in range(2):
|
|
||||||
word = self.gen_data()
|
|
||||||
self.write(addr,word)
|
|
||||||
self.stored_values_over_test.append(word)
|
|
||||||
|
|
||||||
# Read word from address (use all RW and R ports)
|
# Check read values with written values. If the values do not match, return an error.
|
||||||
self.read(addr,word)
|
return self.check_stim_results()
|
||||||
|
|
||||||
def write_read_test(self):
|
def write_random_memory_sequence(self):
|
||||||
""" A standard functional test for writing to an address and reading back the value. """
|
rw_ops = ["noop", "write", "read"]
|
||||||
self.stored_values_test = []
|
w_ops = ["noop", "write"]
|
||||||
self.read_values_test = [[] for i in range(self.num_checks)]
|
r_ops = ["noop", "read"]
|
||||||
|
rw_read_data = "0"*self.word_size
|
||||||
|
check = 0
|
||||||
|
|
||||||
for i in range(self.num_checks):
|
# First cycle idle
|
||||||
# Write a random word to a random address
|
self.add_noop_all_ports("Idle at time {0}n".format(self.t_current),
|
||||||
addr = self.gen_addr()
|
"0"*self.addr_size, "0"*self.word_size)
|
||||||
word = self.gen_data()
|
|
||||||
self.write(addr,word)
|
|
||||||
self.stored_values_test.append(word)
|
|
||||||
|
|
||||||
# Read word from address (use all RW and R ports)
|
|
||||||
self.read(addr,word)
|
|
||||||
|
|
||||||
def noop(self):
|
|
||||||
""" Noop cycle. """
|
|
||||||
self.cycle_times.append(self.t_current)
|
|
||||||
self.t_current += self.period
|
|
||||||
|
|
||||||
for port in range(self.total_ports):
|
# Write at least once
|
||||||
self.csb_values[port].append(1)
|
addr = self.gen_addr()
|
||||||
|
word = self.gen_data()
|
||||||
for port in range(self.total_write):
|
self.add_write("Writing {0} to address {1} (from port {2}) at time {3}n".format(word, addr, 0, self.t_current),
|
||||||
self.web_values[port].append(1)
|
addr, word, 0)
|
||||||
|
self.stored_words[addr] = word
|
||||||
for port in range(self.total_ports):
|
|
||||||
for bit in range(self.addr_size):
|
|
||||||
self.addr_values[port][bit].append(0)
|
|
||||||
|
|
||||||
for port in range(self.total_write):
|
# Read at least once. For multiport, it is important that one read cycle uses all RW and R port to read from the same address simultaniously.
|
||||||
for bit in range(self.word_size):
|
# This will test the viablilty of the transistor sizing in the bitcell.
|
||||||
self.data_values[port][bit].append(0)
|
|
||||||
|
|
||||||
def write(self,addr,word,write_port=0):
|
|
||||||
""" Generates signals for a write cycle. """
|
|
||||||
debug.info(1, "Writing {0} to address {1} in cycle {2}...".format(word,addr,self.cycles))
|
|
||||||
self.cycles += 1
|
|
||||||
self.cycle_times.append(self.t_current)
|
|
||||||
self.t_current += self.period
|
|
||||||
|
|
||||||
# Write control signals
|
|
||||||
for port in range(self.total_ports):
|
|
||||||
if port == write_port:
|
|
||||||
self.csb_values[port].append(0)
|
|
||||||
else:
|
|
||||||
self.csb_values[port].append(1)
|
|
||||||
|
|
||||||
for port in range(self.total_write):
|
|
||||||
if port == write_port:
|
|
||||||
self.web_values[port].append(0)
|
|
||||||
else:
|
|
||||||
self.web_values[port].append(1)
|
|
||||||
|
|
||||||
# Write address
|
|
||||||
for port in range(self.total_ports):
|
|
||||||
for bit in range(self.addr_size):
|
|
||||||
current_address_bit = int(addr[self.addr_size-1-bit])
|
|
||||||
self.addr_values[port][bit].append(current_address_bit)
|
|
||||||
|
|
||||||
# Write data
|
|
||||||
for port in range(self.total_write):
|
|
||||||
for bit in range(self.word_size):
|
|
||||||
current_word_bit = int(word[self.word_size-1-bit])
|
|
||||||
self.data_values[port][bit].append(current_word_bit)
|
|
||||||
|
|
||||||
def read(self,addr,word):
|
|
||||||
""" Generates signals for a read cycle. """
|
|
||||||
debug.info(1, "Reading {0} from address {1} in cycle {2}...".format(word,addr,self.cycles))
|
|
||||||
self.cycles += 1
|
|
||||||
self.cycle_times.append(self.t_current)
|
|
||||||
self.t_current += self.period
|
|
||||||
|
|
||||||
# Read control signals
|
|
||||||
for port in range(self.total_ports):
|
for port in range(self.total_ports):
|
||||||
if self.port_id[port] == "w":
|
if self.port_id[port] == "w":
|
||||||
self.csb_values[port].append(1)
|
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
|
||||||
else:
|
else:
|
||||||
self.csb_values[port].append(0)
|
self.add_read_one_port("Reading {0} from address {1} (from port {2}) at time {3}n".format(word, addr, port, self.t_current),
|
||||||
|
addr, rw_read_data, port)
|
||||||
for port in range(self.total_write):
|
self.write_check.append([word, "{0}{1}".format(self.dout_name,port), self.t_current+self.period, check])
|
||||||
self.web_values[port].append(1)
|
check += 1
|
||||||
|
|
||||||
# Read address
|
|
||||||
for port in range(self.total_ports):
|
|
||||||
for bit in range(self.addr_size):
|
|
||||||
current_address_bit = int(addr[self.addr_size-1-bit])
|
|
||||||
self.addr_values[port][bit].append(current_address_bit)
|
|
||||||
|
|
||||||
# Data input doesn't matter during read cycle, so arbitrarily set to 0 for simulation
|
|
||||||
for port in range(self.total_write):
|
|
||||||
for bit in range(self.word_size):
|
|
||||||
self.data_values[port][bit].append(0)
|
|
||||||
|
|
||||||
# Record the end of the period that the read operation occured in
|
|
||||||
self.eo_period.append(self.t_current)
|
|
||||||
|
|
||||||
def multi_read(self,addrs,words):
|
|
||||||
""" Generates signals for a read cycle but all ports read from a different address. The inputs 'addrs' and 'words' are lists. """
|
|
||||||
debug.info(1, "Reading {0} from addresses {1} in cycle {2}...".format(words,addrs,self.cycles))
|
|
||||||
self.cycles += 1
|
|
||||||
self.cycle_times.append(self.t_current)
|
self.cycle_times.append(self.t_current)
|
||||||
self.t_current += self.period
|
self.t_current += self.period
|
||||||
|
|
||||||
# Read control signals
|
# Perform a random sequence of writes and reads on random ports, using random addresses and random words
|
||||||
for port in range(self.total_ports):
|
for i in range(self.num_cycles):
|
||||||
if self.port_id[port] == "w":
|
w_addrs = []
|
||||||
self.csb_values[port].append(1)
|
for port in range(self.total_ports):
|
||||||
else:
|
if self.port_id[port] == "rw":
|
||||||
self.csb_values[port].append(0)
|
op = random.choice(rw_ops)
|
||||||
|
elif self.port_id[port] == "w":
|
||||||
for port in range(self.total_write):
|
op = random.choice(w_ops)
|
||||||
self.web_values[port].append(1)
|
|
||||||
|
|
||||||
# Read address
|
|
||||||
addr_index = 0
|
|
||||||
for port in range(self.total_ports):
|
|
||||||
for bit in range(self.addr_size):
|
|
||||||
if self.port_id[port] == "w":
|
|
||||||
current_address_bit = 0
|
|
||||||
else:
|
else:
|
||||||
current_address_bit = int(addrs[addr_index][self.addr_size-1-bit])
|
op = random.choice(r_ops)
|
||||||
|
|
||||||
|
if op == "noop":
|
||||||
|
addr = "0"*self.addr_size
|
||||||
|
word = "0"*self.word_size
|
||||||
|
self.add_noop_one_port(addr, word, port)
|
||||||
|
elif op == "write":
|
||||||
|
addr = self.gen_addr()
|
||||||
|
word = self.gen_data()
|
||||||
|
# two ports cannot write to the same address
|
||||||
|
if addr in w_addrs:
|
||||||
|
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
|
||||||
|
else:
|
||||||
|
self.add_write_one_port("Writing {0} to address {1} (from port {2}) at time {3}n".format(word, addr, port, self.t_current),
|
||||||
|
addr, word, port)
|
||||||
|
self.stored_words[addr] = word
|
||||||
|
w_addrs.append(addr)
|
||||||
|
else:
|
||||||
|
(addr,word) = random.choice(list(self.stored_words.items()))
|
||||||
|
# cannot read from an address that is currently being written to
|
||||||
|
if addr in w_addrs:
|
||||||
|
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
|
||||||
|
else:
|
||||||
|
self.add_read_one_port("Reading {0} from address {1} (from port {2}) at time {3}n".format(word, addr, port, self.t_current),
|
||||||
|
addr, rw_read_data, port)
|
||||||
|
self.write_check.append([word, "{0}{1}".format(self.dout_name,port), self.t_current+self.period, check])
|
||||||
|
check += 1
|
||||||
|
|
||||||
self.addr_values[port][bit].append(current_address_bit)
|
self.cycle_times.append(self.t_current)
|
||||||
|
self.t_current += self.period
|
||||||
if self.port_id[port] != "w":
|
|
||||||
addr_index += 1
|
|
||||||
|
|
||||||
# Data input doesn't matter during read cycle, so arbitrarily set to 0 for simulation
|
|
||||||
for port in range(self.total_write):
|
|
||||||
for bit in range(self.word_size):
|
|
||||||
self.data_values[port][bit].append(0)
|
|
||||||
|
|
||||||
# Record the end of the period that the read operation occured in
|
# Last cycle idle needed to correctly measure the value on the second to last clock edge
|
||||||
self.eo_period.append(self.t_current)
|
self.add_noop_all_ports("Idle at time {0}n".format(self.t_current),
|
||||||
|
"0"*self.addr_size, "0"*self.word_size)
|
||||||
|
|
||||||
|
def read_stim_results(self):
|
||||||
|
# Extrat DOUT values from spice timing.lis
|
||||||
|
for (word, dout_port, eo_period, check) in self.write_check:
|
||||||
|
sp_read_value = ""
|
||||||
|
for bit in range(self.word_size):
|
||||||
|
value = parse_spice_list("timing", "v{0}.{1}ck{2}".format(dout_port.lower(),bit,check))
|
||||||
|
if value > 0.9 * self.vdd_voltage:
|
||||||
|
sp_read_value = "1" + sp_read_value
|
||||||
|
elif value < 0.1 * self.vdd_voltage:
|
||||||
|
sp_read_value = "0" + sp_read_value
|
||||||
|
else:
|
||||||
|
error ="FAILED: {0}_{1} value {2} at time {3}n does not fall within noise margins <{4} or >{5}.".format(dout_port,
|
||||||
|
bit,
|
||||||
|
value,
|
||||||
|
eo_period,
|
||||||
|
0.1*self.vdd_voltage,
|
||||||
|
0.9*self.vdd_voltage)
|
||||||
|
return (0, error)
|
||||||
|
|
||||||
|
self.read_check.append([sp_read_value, dout_port, eo_period, check])
|
||||||
|
return (1, "SUCCESS")
|
||||||
|
|
||||||
|
def check_stim_results(self):
|
||||||
|
for i in range(len(self.write_check)):
|
||||||
|
if self.write_check[i][0] != self.read_check[i][0]:
|
||||||
|
error = "FAILED: {0} value {1} does not match written value {2} read at time {3}n".format(self.read_check[i][1],
|
||||||
|
self.read_check[i][0],
|
||||||
|
self.write_check[i][0],
|
||||||
|
self.read_check[i][2])
|
||||||
|
return(0, error)
|
||||||
|
return(1, "SUCCESS")
|
||||||
|
|
||||||
def gen_data(self):
|
def gen_data(self):
|
||||||
""" Generates a random word to write. """
|
""" Generates a random word to write. """
|
||||||
|
|
@ -375,18 +186,14 @@ class functional(simulation):
|
||||||
|
|
||||||
#print("Binary Conversion: {} to {}".format(value, new_value))
|
#print("Binary Conversion: {} to {}".format(value, new_value))
|
||||||
return new_value
|
return new_value
|
||||||
|
|
||||||
def obtain_cycle_times(self,period):
|
def create_signal_names(self):
|
||||||
""" Generate clock cycle times based on period and number of cycles. """
|
self.addr_name = "A"
|
||||||
t_current = 0
|
self.din_name = "DIN"
|
||||||
self.cycle_times = []
|
self.dout_name = "DOUT"
|
||||||
for i in range(self.cycles):
|
|
||||||
self.cycle_times.append(t_current)
|
|
||||||
t_current += period
|
|
||||||
|
|
||||||
def write_functional_stimulus(self):
|
def write_functional_stimulus(self):
|
||||||
""" Writes SPICE stimulus. """
|
""" Writes SPICE stimulus. """
|
||||||
#self.obtain_cycle_times(self.period)
|
|
||||||
temp_stim = "{0}/stim.sp".format(OPTS.openram_temp)
|
temp_stim = "{0}/stim.sp".format(OPTS.openram_temp)
|
||||||
self.sf = open(temp_stim,"w")
|
self.sf = open(temp_stim,"w")
|
||||||
self.sf.write("* Functional test stimulus file for {}ns period\n\n".format(self.period))
|
self.sf.write("* Functional test stimulus file for {}ns period\n\n".format(self.period))
|
||||||
|
|
@ -403,30 +210,31 @@ class functional(simulation):
|
||||||
|
|
||||||
#Instantiate the SRAM
|
#Instantiate the SRAM
|
||||||
self.sf.write("\n* Instantiation of the SRAM\n")
|
self.sf.write("\n* Instantiation of the SRAM\n")
|
||||||
self.stim.inst_full_sram(sram=self.sram,
|
self.stim.inst_sram(sram=self.sram,
|
||||||
sram_name=self.name)
|
port_signal_names=(self.addr_name,self.din_name,self.dout_name),
|
||||||
#self.stim.inst_sram(abits=self.addr_size,
|
port_info=(self.total_ports, self.write_index, self.read_index),
|
||||||
# dbits=self.word_size,
|
abits=self.addr_size,
|
||||||
# port_info=(self.total_ports,self.total_write,self.read_index,self.write_index),
|
dbits=self.word_size,
|
||||||
# sram_name=self.name)
|
sram_name=self.name)
|
||||||
|
|
||||||
# Add load capacitance to each of the read ports
|
# Add load capacitance to each of the read ports
|
||||||
self.sf.write("\n* SRAM output loads\n")
|
self.sf.write("\n* SRAM output loads\n")
|
||||||
for port in range(self.total_read):
|
for port in range(self.total_read):
|
||||||
for bit in range(self.word_size):
|
for bit in range(self.word_size):
|
||||||
self.sf.write("CD{0}{1} DOUT{0}[{1}] 0 {2}f\n".format(self.read_index[port], bit, self.load))
|
sig_name="{0}{1}_{2} ".format(self.dout_name, self.read_index[port], bit)
|
||||||
|
self.sf.write("CD{0}{1} {2} 0 {3}f\n".format(self.read_index[port], bit, sig_name, self.load))
|
||||||
|
|
||||||
# Generate data input bits
|
# Generate data input bits
|
||||||
self.sf.write("\n* Generation of data and address signals\n")
|
self.sf.write("\n* Generation of data and address signals\n")
|
||||||
for port in range(self.total_write):
|
for port in range(self.total_write):
|
||||||
for bit in range(self.word_size):
|
for bit in range(self.word_size):
|
||||||
sig_name = "DIN{0}[{1}]".format(port,bit)
|
sig_name="{0}{1}_{2} ".format(self.din_name, port, bit)
|
||||||
self.stim.gen_pwl(sig_name, self.cycle_times, self.data_values[port][bit], self.period, self.slew, 0.05)
|
self.stim.gen_pwl(sig_name, self.cycle_times, self.data_values[port][bit], self.period, self.slew, 0.05)
|
||||||
|
|
||||||
# Generate address bits
|
# Generate address bits
|
||||||
for port in range(self.total_ports):
|
for port in range(self.total_ports):
|
||||||
for bit in range(self.addr_size):
|
for bit in range(self.addr_size):
|
||||||
sig_name = "ADDR{0}[{1}]".format(port,bit)
|
sig_name="{0}{1}_{2} ".format(self.addr_name, port, bit)
|
||||||
self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][bit], self.period, self.slew, 0.05)
|
self.stim.gen_pwl(sig_name, self.cycle_times, self.addr_values[port][bit], self.period, self.slew, 0.05)
|
||||||
|
|
||||||
# Generate control signals
|
# Generate control signals
|
||||||
|
|
@ -434,12 +242,12 @@ class functional(simulation):
|
||||||
for port in range(self.total_ports):
|
for port in range(self.total_ports):
|
||||||
self.stim.gen_pwl("CSB{}".format(port), self.cycle_times , self.csb_values[port], self.period, self.slew, 0.05)
|
self.stim.gen_pwl("CSB{}".format(port), self.cycle_times , self.csb_values[port], self.period, self.slew, 0.05)
|
||||||
|
|
||||||
for port in range(self.total_write):
|
for port in range(self.num_rw_ports):
|
||||||
self.stim.gen_pwl("WEB{}".format(port), self.cycle_times , self.web_values[port], self.period, self.slew, 0.05)
|
self.stim.gen_pwl("WEB{}".format(port), self.cycle_times , self.web_values[port], self.period, self.slew, 0.05)
|
||||||
|
|
||||||
# Generate CLK signals
|
# Generate CLK signals
|
||||||
for port in range(self.total_ports):
|
for port in range(self.total_ports):
|
||||||
self.stim.gen_pulse(sig_name="CLK{}".format(port),
|
self.stim.gen_pulse(sig_name="{0}{1}".format(tech.spice["clk"], port),
|
||||||
v1=self.gnd_voltage,
|
v1=self.gnd_voltage,
|
||||||
v2=self.vdd_voltage,
|
v2=self.vdd_voltage,
|
||||||
offset=self.period,
|
offset=self.period,
|
||||||
|
|
@ -448,21 +256,15 @@ class functional(simulation):
|
||||||
t_fall=self.slew)
|
t_fall=self.slew)
|
||||||
|
|
||||||
# Generate DOUT value measurements
|
# Generate DOUT value measurements
|
||||||
if self.total_ports > 1:
|
|
||||||
num_tests = 3
|
|
||||||
else:
|
|
||||||
num_tests = 2
|
|
||||||
|
|
||||||
self.sf.write("\n * Generation of dout measurements\n")
|
self.sf.write("\n * Generation of dout measurements\n")
|
||||||
for i in range(num_tests*self.num_checks):
|
for (word, dout_port, eo_period, check) in self.write_check:
|
||||||
t_intital = self.eo_period[i] - 0.01*self.period
|
t_intital = eo_period - 0.01*self.period
|
||||||
t_final = self.eo_period[i] + 0.01*self.period
|
t_final = eo_period + 0.01*self.period
|
||||||
for port in range(self.total_read):
|
for bit in range(self.word_size):
|
||||||
for bit in range(self.word_size):
|
self.stim.gen_meas_value(meas_name="V{0}_{1}ck{2}".format(dout_port,bit,check),
|
||||||
self.stim.gen_meas_value(meas_name="VDOUT{0}[{1}]ck{2}".format(self.read_index[port],bit,i),
|
dout="{0}_{1}".format(dout_port,bit),
|
||||||
dout="DOUT{0}[{1}]".format(self.read_index[port],bit),
|
t_intital=t_intital,
|
||||||
t_intital=t_intital,
|
t_final=t_final)
|
||||||
t_final=t_final)
|
|
||||||
|
|
||||||
self.stim.write_control(self.cycle_times[-1] + self.period)
|
self.stim.write_control(self.cycle_times[-1] + self.period)
|
||||||
self.sf.close()
|
self.sf.close()
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ class simulation():
|
||||||
self.total_read = self.sram.total_read
|
self.total_read = self.sram.total_read
|
||||||
self.read_index = self.sram.read_index
|
self.read_index = self.sram.read_index
|
||||||
self.write_index = self.sram.write_index
|
self.write_index = self.sram.write_index
|
||||||
|
self.num_rw_ports = self.sram.num_rw_ports
|
||||||
self.port_id = self.sram.port_id
|
self.port_id = self.sram.port_id
|
||||||
|
|
||||||
def set_corner(self,corner):
|
def set_corner(self,corner):
|
||||||
|
|
@ -49,11 +50,14 @@ class simulation():
|
||||||
|
|
||||||
# control signals: only one cs_b for entire multiported sram, one we_b for each write port
|
# control signals: only one cs_b for entire multiported sram, one we_b for each write port
|
||||||
self.csb_values = [[] for port in range(self.total_ports)]
|
self.csb_values = [[] for port in range(self.total_ports)]
|
||||||
self.web_values = [[] for port in range(self.total_write)]
|
self.web_values = [[] for port in range(self.num_rw_ports)]
|
||||||
|
|
||||||
# Three dimensional list to handle each addr and data bits for wach port over the number of checks
|
# Three dimensional list to handle each addr and data bits for wach port over the number of checks
|
||||||
self.addr_values = [[[] for bit in range(self.addr_size)] for port in range(self.total_ports)]
|
self.addr_values = [[[] for bit in range(self.addr_size)] for port in range(self.total_ports)]
|
||||||
self.data_values = [[[] for bit in range(self.word_size)] for port in range(self.total_write)]
|
self.data_values = [[[] for bit in range(self.word_size)] for port in range(self.total_write)]
|
||||||
|
|
||||||
|
# For generating comments in SPICE stimulus
|
||||||
|
self.cycle_comments = []
|
||||||
|
|
||||||
def add_control_one_port(self, port, op):
|
def add_control_one_port(self, port, op):
|
||||||
"""Appends control signals for operation to a given port"""
|
"""Appends control signals for operation to a given port"""
|
||||||
|
|
@ -61,7 +65,7 @@ class simulation():
|
||||||
web_val = 1
|
web_val = 1
|
||||||
csb_val = 1
|
csb_val = 1
|
||||||
if op == "read":
|
if op == "read":
|
||||||
self.cs_b = 0
|
csb_val = 0
|
||||||
elif op == "write":
|
elif op == "write":
|
||||||
csb_val = 0
|
csb_val = 0
|
||||||
web_val = 0
|
web_val = 0
|
||||||
|
|
@ -105,7 +109,8 @@ class simulation():
|
||||||
|
|
||||||
def add_write(self, comment, address, data, port):
|
def add_write(self, comment, address, data, port):
|
||||||
""" Add the control values for a write cycle. """
|
""" Add the control values for a write cycle. """
|
||||||
debug.check(port in self.write_ports, "Cannot add read cycle to a read port.")
|
debug.info(1, comment)
|
||||||
|
debug.check(port in self.write_index, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_index))
|
||||||
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
|
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
|
||||||
self.t_current,
|
self.t_current,
|
||||||
comment,
|
comment,
|
||||||
|
|
@ -120,27 +125,14 @@ class simulation():
|
||||||
#This value is hard coded here. Possibly change to member variable or set in add_noop_one_port
|
#This value is hard coded here. Possibly change to member variable or set in add_noop_one_port
|
||||||
noop_data = "0"*self.word_size
|
noop_data = "0"*self.word_size
|
||||||
#Add noops to all other ports.
|
#Add noops to all other ports.
|
||||||
for unselected_port in range(self.total_port_num):
|
for unselected_port in range(self.total_ports):
|
||||||
if unselected_port != port:
|
if unselected_port != port:
|
||||||
self.add_noop_one_port(address, noop_data, unselected_port)
|
self.add_noop_one_port(address, noop_data, unselected_port)
|
||||||
|
|
||||||
def add_write_one_port(self, comment, address, data, port):
|
|
||||||
""" Add the control values for a write cycle. """
|
|
||||||
debug.check(port in self.write_ports, "Cannot add read cycle to a read port.")
|
|
||||||
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
|
|
||||||
self.t_current,
|
|
||||||
comment,
|
|
||||||
port))
|
|
||||||
self.cycle_times.append(self.t_current)
|
|
||||||
self.t_current += self.period
|
|
||||||
|
|
||||||
self.add_control_one_port(port, "write")
|
|
||||||
self.add_data(data,port)
|
|
||||||
self.add_address(address,port)
|
|
||||||
|
|
||||||
def add_read(self, comment, address, data, port):
|
def add_read(self, comment, address, data, port):
|
||||||
""" Add the control values for a read cycle. """
|
""" Add the control values for a read cycle. """
|
||||||
debug.check(port in self.read_ports, "Cannot add read cycle to a write port.")
|
debug.info(1, comment)
|
||||||
|
debug.check(port in self.read_index, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_index))
|
||||||
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
|
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
|
||||||
self.t_current,
|
self.t_current,
|
||||||
comment,
|
comment,
|
||||||
|
|
@ -150,48 +142,59 @@ class simulation():
|
||||||
self.add_control_one_port(port, "read")
|
self.add_control_one_port(port, "read")
|
||||||
|
|
||||||
#If the port is also a readwrite then add data.
|
#If the port is also a readwrite then add data.
|
||||||
if port in self.write_ports:
|
if port in self.write_index:
|
||||||
self.add_data(data,port)
|
self.add_data(data,port)
|
||||||
self.add_address(address, port)
|
self.add_address(address, port)
|
||||||
|
|
||||||
#This value is hard coded here. Possibly change to member variable or set in add_noop_one_port
|
#This value is hard coded here. Possibly change to member variable or set in add_noop_one_port
|
||||||
noop_data = "0"*self.word_size
|
noop_data = "0"*self.word_size
|
||||||
#Add noops to all other ports.
|
#Add noops to all other ports.
|
||||||
for unselected_port in range(self.total_port_num):
|
for unselected_port in range(self.total_ports):
|
||||||
if unselected_port != port:
|
if unselected_port != port:
|
||||||
self.add_noop_one_port(address, noop_data, unselected_port)
|
self.add_noop_one_port(address, noop_data, unselected_port)
|
||||||
|
|
||||||
def add_read_one_port(self, comment, address, data, port):
|
|
||||||
""" Add the control values for a read cycle. """
|
|
||||||
debug.check(port in self.read_ports, "Cannot add read cycle to a write port.")
|
|
||||||
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
|
|
||||||
self.t_current,
|
|
||||||
comment,
|
|
||||||
port))
|
|
||||||
self.cycle_times.append(self.t_current)
|
|
||||||
self.t_current += self.period
|
|
||||||
self.add_control_one_port(port, "read")
|
|
||||||
|
|
||||||
#If the port is also a readwrite then add data.
|
|
||||||
if port in self.write_ports:
|
|
||||||
self.add_data(data,port)
|
|
||||||
self.add_address(address, port)
|
|
||||||
|
|
||||||
def add_noop_one_port(self, address, data, port):
|
|
||||||
""" Add the control values for a noop to a single port. """
|
|
||||||
#This is to be used as a helper function for the other add functions. Cycle and comments are omitted.
|
|
||||||
self.add_control_one_port(port, "noop")
|
|
||||||
if port in self.write_ports:
|
|
||||||
self.add_data(data,port)
|
|
||||||
self.add_address(address, port)
|
|
||||||
|
|
||||||
def add_noop_all_ports(self, comment, address, data):
|
def add_noop_all_ports(self, comment, address, data):
|
||||||
""" Add the control values for a noop to all ports. """
|
""" Add the control values for a noop to all ports. """
|
||||||
|
debug.info(1, comment)
|
||||||
self.cycle_comments.append("Cycle {0:2d}\tPort All\t{1:5.2f}ns:\t{2}".format(len(self.cycle_times),
|
self.cycle_comments.append("Cycle {0:2d}\tPort All\t{1:5.2f}ns:\t{2}".format(len(self.cycle_times),
|
||||||
self.t_current,
|
self.t_current,
|
||||||
comment))
|
comment))
|
||||||
self.cycle_times.append(self.t_current)
|
self.cycle_times.append(self.t_current)
|
||||||
self.t_current += self.period
|
self.t_current += self.period
|
||||||
|
|
||||||
for port in range(self.total_port_num):
|
for port in range(self.total_ports):
|
||||||
self.add_noop_one_port(address, data, port)
|
self.add_noop_one_port(address, data, port)
|
||||||
|
|
||||||
|
def add_write_one_port(self, comment, address, data, port):
|
||||||
|
""" Add the control values for a write cycle. Does not increment the period. """
|
||||||
|
debug.check(port in self.write_index, "Cannot add write cycle to a read port. Port {0}, Write Ports {1}".format(port, self.write_index))
|
||||||
|
debug.info(1, comment)
|
||||||
|
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
|
||||||
|
self.t_current,
|
||||||
|
comment,
|
||||||
|
port))
|
||||||
|
self.add_control_one_port(port, "write")
|
||||||
|
self.add_data(data,port)
|
||||||
|
self.add_address(address,port)
|
||||||
|
|
||||||
|
def add_read_one_port(self, comment, address, data, port):
|
||||||
|
""" Add the control values for a read cycle. Does not increment the period. """
|
||||||
|
debug.check(port in self.read_index, "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_index))
|
||||||
|
debug.info(1, comment)
|
||||||
|
self.cycle_comments.append("Cycle {0:2d}\tPort {3}\t{1:5.2f}ns:\t{2}".format(len(self.cycle_comments),
|
||||||
|
self.t_current,
|
||||||
|
comment,
|
||||||
|
port))
|
||||||
|
self.add_control_one_port(port, "read")
|
||||||
|
#If the port is also a readwrite then add data.
|
||||||
|
if port in self.write_index:
|
||||||
|
self.add_data(data,port)
|
||||||
|
self.add_address(address, port)
|
||||||
|
|
||||||
|
def add_noop_one_port(self, address, data, port):
|
||||||
|
""" Add the control values for a noop to a single port. Does not increment the period. """
|
||||||
|
self.add_control_one_port(port, "noop")
|
||||||
|
if port in self.write_index:
|
||||||
|
self.add_data(data,port)
|
||||||
|
self.add_address(address, port)
|
||||||
|
|
||||||
|
|
@ -28,24 +28,12 @@ class stimuli():
|
||||||
|
|
||||||
(self.process, self.voltage, self.temperature) = corner
|
(self.process, self.voltage, self.temperature) = corner
|
||||||
self.device_models = tech.spice["fet_models"][self.process]
|
self.device_models = tech.spice["fet_models"][self.process]
|
||||||
|
|
||||||
|
|
||||||
def inst_full_sram(self, sram, sram_name):
|
|
||||||
""" Function to instatiate an SRAM subckt. """
|
|
||||||
self.sf.write("Xsram ")
|
|
||||||
for pin in sram.pins:
|
|
||||||
if (pin=="vdd") or (pin=="gnd"):
|
|
||||||
self.sf.write("{0} ".format(pin))
|
|
||||||
else:
|
|
||||||
self.sf.write("{0} ".format(pin.upper()))
|
|
||||||
self.sf.write("{0}\n".format(sram_name))
|
|
||||||
|
|
||||||
|
|
||||||
def inst_sram(self, sram, port_signal_names, port_info, abits, dbits, sram_name):
|
def inst_sram(self, sram, port_signal_names, port_info, abits, dbits, sram_name):
|
||||||
""" Function to instatiate an SRAM subckt. """
|
""" Function to instatiate an SRAM subckt. """
|
||||||
pin_names = self.gen_pin_names(port_signal_names, port_info, abits, dbits)
|
pin_names = self.gen_pin_names(port_signal_names, port_info, abits, dbits)
|
||||||
#Only checking length. This should check functionality as well (TODO) and/or import that information from the SRAM
|
#Only checking length. This should check functionality as well (TODO) and/or import that information from the SRAM
|
||||||
debug.check(len(sram.pins) == len(pin_names), "Number of pins generated for characterization do match pins of SRAM")
|
debug.check(len(sram.pins) == len(pin_names), "Number of pins generated for characterization do match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(sram.pins,pin_names))
|
||||||
|
|
||||||
self.sf.write("Xsram ")
|
self.sf.write("Xsram ")
|
||||||
for pin in pin_names:
|
for pin in pin_names:
|
||||||
|
|
@ -59,27 +47,27 @@ class stimuli():
|
||||||
#will cause issues here.
|
#will cause issues here.
|
||||||
pin_names = []
|
pin_names = []
|
||||||
(addr_name, din_name, dout_name) = port_signal_names
|
(addr_name, din_name, dout_name) = port_signal_names
|
||||||
(total_port_num, write_ports, read_ports) = port_info
|
(total_ports, write_index, read_index) = port_info
|
||||||
|
|
||||||
for write_input in write_ports:
|
for write_input in write_index:
|
||||||
for i in range(dbits):
|
for i in range(dbits):
|
||||||
pin_names.append("{0}{1}_{2}".format(din_name,write_input, i))
|
pin_names.append("{0}{1}_{2}".format(din_name,write_input, i))
|
||||||
|
|
||||||
for port in range(total_port_num):
|
for port in range(total_ports):
|
||||||
for i in range(abits):
|
for i in range(abits):
|
||||||
pin_names.append("{0}{1}_{2}".format(addr_name,port,i))
|
pin_names.append("{0}{1}_{2}".format(addr_name,port,i))
|
||||||
|
|
||||||
#Control signals not finalized.
|
#Control signals not finalized.
|
||||||
for port in range(total_port_num):
|
for port in range(total_ports):
|
||||||
pin_names.append("CSB{0}".format(port))
|
pin_names.append("CSB{0}".format(port))
|
||||||
for port in range(total_port_num):
|
for port in range(total_ports):
|
||||||
if port in read_ports and port in write_ports:
|
if (port in read_index) and (port in write_index):
|
||||||
pin_names.append("WEB{0}".format(port))
|
pin_names.append("WEB{0}".format(port))
|
||||||
|
|
||||||
for port in range(total_port_num):
|
for port in range(total_ports):
|
||||||
pin_names.append("{0}{1}".format(tech.spice["clk"], port))
|
pin_names.append("{0}{1}".format(tech.spice["clk"], port))
|
||||||
|
|
||||||
for read_output in read_ports:
|
for read_output in read_index:
|
||||||
for i in range(dbits):
|
for i in range(dbits):
|
||||||
pin_names.append("{0}{1}_{2}".format(dout_name,read_output, i))
|
pin_names.append("{0}{1}_{2}".format(dout_name,read_output, i))
|
||||||
|
|
||||||
|
|
@ -179,7 +167,7 @@ class stimuli():
|
||||||
to the initial value.
|
to the initial value.
|
||||||
"""
|
"""
|
||||||
# the initial value is not a clock time
|
# the initial value is not a clock time
|
||||||
debug.check(len(clk_times)==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. {0} clock values, {1} data values for {2}".format(len(clk_times), len(data_values), sig_name))
|
||||||
|
|
||||||
# shift signal times earlier for setup time
|
# shift signal times earlier for setup time
|
||||||
times = np.array(clk_times) - setup*period
|
times = np.array(clk_times) - setup*period
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import globals
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
@unittest.skip("SKIPPING 20_psram_1bank_test, multiport layout not complete")
|
#@unittest.skip("SKIPPING 20_psram_1bank_test, multiport layout not complete")
|
||||||
class sram_1bank_test(openram_test):
|
class sram_1bank_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
|
|
@ -40,7 +40,7 @@ class sram_1bank_test(openram_test):
|
||||||
debug.info(1, "Single bank two way column mux with control logic")
|
debug.info(1, "Single bank two way column mux with control logic")
|
||||||
a = sram(c, "sram2")
|
a = sram(c, "sram2")
|
||||||
self.local_check(a, final_verification=True)
|
self.local_check(a, final_verification=True)
|
||||||
|
"""
|
||||||
c.num_words=64
|
c.num_words=64
|
||||||
c.words_per_row=4
|
c.words_per_row=4
|
||||||
debug.info(1, "Single bank, four way column mux with control logic")
|
debug.info(1, "Single bank, four way column mux with control logic")
|
||||||
|
|
@ -69,7 +69,7 @@ class sram_1bank_test(openram_test):
|
||||||
debug.info(1, "Single bank, no column mux with control logic")
|
debug.info(1, "Single bank, no column mux with control logic")
|
||||||
a = sram(c, "sram1")
|
a = sram(c, "sram1")
|
||||||
self.local_check(a, final_verification=True)
|
self.local_check(a, final_verification=True)
|
||||||
|
"""
|
||||||
OPTS.num_rw_ports = 0
|
OPTS.num_rw_ports = 0
|
||||||
OPTS.num_w_ports = 2
|
OPTS.num_w_ports = 2
|
||||||
OPTS.num_r_ports = 2
|
OPTS.num_r_ports = 2
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,8 @@ class psram_func_test(openram_test):
|
||||||
c.words_per_row=2
|
c.words_per_row=2
|
||||||
|
|
||||||
OPTS.num_rw_ports = 1
|
OPTS.num_rw_ports = 1
|
||||||
OPTS.num_w_ports = 2
|
OPTS.num_w_ports = 1
|
||||||
OPTS.num_r_ports = 4
|
OPTS.num_r_ports = 1
|
||||||
|
|
||||||
debug.info(1, "Functional test for 1bit, 16word SRAM, with 1 bank. Multiport with {}RW {}W {}R.".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports))
|
debug.info(1, "Functional test for 1bit, 16word SRAM, with 1 bank. Multiport with {}RW {}W {}R.".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports))
|
||||||
s = sram(c, name="sram1")
|
s = sram(c, name="sram1")
|
||||||
|
|
@ -49,9 +49,10 @@ class psram_func_test(openram_test):
|
||||||
|
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
f = functional(s.s, tempspice, corner)
|
f = functional(s.s, tempspice, corner)
|
||||||
(success,error) = f.multiport_run()
|
f.num_cycles = 5
|
||||||
|
(fail,error) = f.run()
|
||||||
|
|
||||||
self.assertTrue(not success,error)
|
self.assertTrue(fail,error)
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,10 @@ class sram_func_test(openram_test):
|
||||||
|
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
f = functional(s.s, tempspice, corner)
|
f = functional(s.s, tempspice, corner)
|
||||||
(success, error) = f.run()
|
f.num_cycles = 10
|
||||||
|
(fail, error) = f.run()
|
||||||
|
|
||||||
self.assertTrue(not success,error)
|
self.assertTrue(fail,error)
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,8 @@ class psram_func_test(openram_test):
|
||||||
c.words_per_row=2
|
c.words_per_row=2
|
||||||
|
|
||||||
OPTS.num_rw_ports = 1
|
OPTS.num_rw_ports = 1
|
||||||
OPTS.num_w_ports = 2
|
OPTS.num_w_ports = 1
|
||||||
OPTS.num_r_ports = 4
|
OPTS.num_r_ports = 1
|
||||||
|
|
||||||
debug.info(1, "Functional test for 1bit, 16word SRAM, with 1 bank. Multiport with {}RW {}W {}R.".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports))
|
debug.info(1, "Functional test for 1bit, 16word SRAM, with 1 bank. Multiport with {}RW {}W {}R.".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports))
|
||||||
s = sram(c, name="sram1")
|
s = sram(c, name="sram1")
|
||||||
|
|
@ -49,9 +49,10 @@ class psram_func_test(openram_test):
|
||||||
|
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
f = functional(s.s, tempspice, corner)
|
f = functional(s.s, tempspice, corner)
|
||||||
(success,error) = f.multiport_run()
|
f.num_cycles = 5
|
||||||
|
(fail,error) = f.run()
|
||||||
|
|
||||||
self.assertTrue(not success,error)
|
self.assertTrue(fail,error)
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,10 @@ class sram_func_test(openram_test):
|
||||||
|
|
||||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
f = functional(s.s, tempspice, corner)
|
f = functional(s.s, tempspice, corner)
|
||||||
(success, error) = f.run()
|
f.num_cycles = 10
|
||||||
|
(fail, error) = f.run()
|
||||||
|
|
||||||
self.assertTrue(not success,error)
|
self.assertTrue(fail,error)
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue