mirror of https://github.com/VLSIDA/OpenRAM.git
Adding debug comments to stim file for functional test and cleaning up comment code in simulation.py. Adding multiple tests for different mux configurations to functional unit tests.
This commit is contained in:
parent
6716aac1a6
commit
ceab1a5daf
|
|
@ -52,18 +52,16 @@ class functional(simulation):
|
|||
rw_ops = ["noop", "write", "read"]
|
||||
w_ops = ["noop", "write"]
|
||||
r_ops = ["noop", "read"]
|
||||
rw_read_data = "0"*self.word_size
|
||||
rw_read_din_data = "0"*self.word_size
|
||||
check = 0
|
||||
|
||||
# First cycle idle
|
||||
debug_comment = self.cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, 0, self.t_current)
|
||||
self.add_noop_all_ports(debug_comment, "0"*self.addr_size, "0"*self.word_size)
|
||||
self.add_noop_all_ports("0"*self.addr_size, "0"*self.word_size)
|
||||
|
||||
# Write at least once
|
||||
addr = self.gen_addr()
|
||||
word = self.gen_data()
|
||||
debug_comment = self.cycle_comment("write", word, addr, 0, self.t_current)
|
||||
self.add_write(debug_comment, addr, word, 0)
|
||||
self.add_write(addr, word, 0)
|
||||
self.stored_words[addr] = word
|
||||
|
||||
# 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.
|
||||
|
|
@ -72,8 +70,7 @@ class functional(simulation):
|
|||
if self.port_id[port] == "w":
|
||||
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
|
||||
else:
|
||||
debug_comment = self.cycle_comment("read", word, addr, port, self.t_current)
|
||||
self.add_read_one_port(debug_comment, addr, rw_read_data, port)
|
||||
self.add_read_one_port(addr, rw_read_din_data, word, port)
|
||||
self.write_check.append([word, "{0}{1}".format(self.dout_name,port), self.t_current+self.period, check])
|
||||
check += 1
|
||||
self.cycle_times.append(self.t_current)
|
||||
|
|
@ -101,8 +98,7 @@ class functional(simulation):
|
|||
if addr in w_addrs:
|
||||
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
|
||||
else:
|
||||
debug_comment = self.cycle_comment("write", word, addr, port, self.t_current)
|
||||
self.add_write_one_port(debug_comment, addr, word, port)
|
||||
self.add_write_one_port(addr, word, port)
|
||||
self.stored_words[addr] = word
|
||||
w_addrs.append(addr)
|
||||
else:
|
||||
|
|
@ -111,8 +107,7 @@ class functional(simulation):
|
|||
if addr in w_addrs:
|
||||
self.add_noop_one_port("0"*self.addr_size, "0"*self.word_size, port)
|
||||
else:
|
||||
debug_comment = self.cycle_comment("read", word, addr, port, self.t_current)
|
||||
self.add_read_one_port(debug_comment, addr, rw_read_data, port)
|
||||
self.add_read_one_port(addr, rw_read_din_data, word, port)
|
||||
self.write_check.append([word, "{0}{1}".format(self.dout_name,port), self.t_current+self.period, check])
|
||||
check += 1
|
||||
|
||||
|
|
@ -120,8 +115,7 @@ class functional(simulation):
|
|||
self.t_current += self.period
|
||||
|
||||
# Last cycle idle needed to correctly measure the value on the second to last clock edge
|
||||
debug_comment = self.cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, 0, self.t_current)
|
||||
self.add_noop_all_ports(debug_comment, "0"*self.addr_size, "0"*self.word_size)
|
||||
self.add_noop_all_ports("0"*self.addr_size, "0"*self.word_size)
|
||||
|
||||
def read_stim_results(self):
|
||||
# Extrat DOUT values from spice timing.lis
|
||||
|
|
@ -129,17 +123,17 @@ class functional(simulation):
|
|||
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:
|
||||
if value > 0.88 * self.vdd_voltage:
|
||||
sp_read_value = "1" + sp_read_value
|
||||
elif value < 0.1 * self.vdd_voltage:
|
||||
elif value < 0.12 * 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)
|
||||
0.12*self.vdd_voltage,
|
||||
0.88*self.vdd_voltage)
|
||||
return (0, error)
|
||||
|
||||
self.read_check.append([sp_read_value, dout_port, eo_period, check])
|
||||
|
|
@ -225,6 +219,11 @@ class functional(simulation):
|
|||
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))
|
||||
|
||||
# Write debug comments to stim file
|
||||
self.sf.write("\n\n * Sequence of operations\n")
|
||||
for comment in self.cycle_comments:
|
||||
self.sf.write("*{}\n".format(comment))
|
||||
|
||||
# Generate data input bits
|
||||
self.sf.write("\n* Generation of data and address signals\n")
|
||||
for port in range(self.total_write):
|
||||
|
|
|
|||
|
|
@ -107,14 +107,13 @@ class simulation():
|
|||
debug.error("Non-binary address string",1)
|
||||
bit -= 1
|
||||
|
||||
def add_write(self, comment, address, data, port):
|
||||
def add_write(self, address, data, port):
|
||||
""" Add the control values for a write cycle. """
|
||||
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.t_current,
|
||||
comment,
|
||||
port))
|
||||
comment = self.gen_cycle_comment("write", data, address, port, self.t_current)
|
||||
debug.info(1, comment)
|
||||
self.cycle_comments.append(comment)
|
||||
|
||||
self.cycle_times.append(self.t_current)
|
||||
self.t_current += self.period
|
||||
|
||||
|
|
@ -129,21 +128,20 @@ class simulation():
|
|||
if unselected_port != port:
|
||||
self.add_noop_one_port(address, noop_data, unselected_port)
|
||||
|
||||
def add_read(self, comment, address, data, port):
|
||||
def add_read(self, address, din_data, dout_data, port):
|
||||
""" Add the control values for a read cycle. """
|
||||
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.t_current,
|
||||
comment,
|
||||
port))
|
||||
comment = self.gen_cycle_comment("read", dout_data, address, port, self.t_current)
|
||||
debug.info(1, comment)
|
||||
self.cycle_comments.append(comment)
|
||||
|
||||
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_index:
|
||||
self.add_data(data,port)
|
||||
self.add_data(din_data,port)
|
||||
self.add_address(address, port)
|
||||
|
||||
#This value is hard coded here. Possibly change to member variable or set in add_noop_one_port
|
||||
|
|
@ -153,42 +151,40 @@ class simulation():
|
|||
if unselected_port != port:
|
||||
self.add_noop_one_port(address, noop_data, unselected_port)
|
||||
|
||||
def add_noop_all_ports(self, comment, address, data):
|
||||
def add_noop_all_ports(self, address, data):
|
||||
""" Add the control values for a noop to all ports. """
|
||||
comment = self.gen_cycle_comment("noop", "0"*self.word_size, "0"*self.addr_size, 0, self.t_current)
|
||||
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.t_current,
|
||||
comment))
|
||||
self.cycle_comments.append(comment)
|
||||
|
||||
self.cycle_times.append(self.t_current)
|
||||
self.t_current += self.period
|
||||
|
||||
for port in range(self.total_ports):
|
||||
self.add_noop_one_port(address, data, port)
|
||||
|
||||
def add_write_one_port(self, comment, address, data, port):
|
||||
def add_write_one_port(self, 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))
|
||||
comment = self.gen_cycle_comment("write", data, address, port, self.t_current)
|
||||
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.cycle_comments.append(comment)
|
||||
|
||||
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):
|
||||
def add_read_one_port(self, address, din_data, dout_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))
|
||||
comment = self.gen_cycle_comment("read", dout_data, address, port, self.t_current)
|
||||
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.cycle_comments.append(comment)
|
||||
|
||||
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_data(din_data,port)
|
||||
self.add_address(address, port)
|
||||
|
||||
def add_noop_one_port(self, address, data, port):
|
||||
|
|
@ -198,7 +194,7 @@ class simulation():
|
|||
self.add_data(data,port)
|
||||
self.add_address(address, port)
|
||||
|
||||
def cycle_comment(self, op, word, addr, port, t_current):
|
||||
def gen_cycle_comment(self, op, word, addr, port, t_current):
|
||||
if op == "noop":
|
||||
comment = "\tIdle during cycle {0} ({1}ns - {2}ns)".format(int(t_current/self.period),
|
||||
t_current,
|
||||
|
|
|
|||
|
|
@ -32,27 +32,90 @@ class psram_func_test(openram_test):
|
|||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
num_words=64,
|
||||
num_words=32,
|
||||
num_banks=1)
|
||||
c.words_per_row=2
|
||||
c.words_per_row=1
|
||||
|
||||
OPTS.num_rw_ports = 1
|
||||
OPTS.num_w_ports = 1
|
||||
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))
|
||||
# no column mux
|
||||
debug.info(1, "Functional test for multi-port ({0}RW {1}W {2}R) sram with {3}bit words, {4}words, {5}words per row, {6}banks".format(OPTS.num_rw_ports,
|
||||
OPTS.num_w_ports,
|
||||
OPTS.num_r_ports,
|
||||
c.word_size,
|
||||
c.num_words,
|
||||
c.words_per_row,
|
||||
c.num_banks))
|
||||
s = sram(c, name="sram1")
|
||||
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
f.num_cycles = 10
|
||||
(fail,error) = f.run()
|
||||
|
||||
self.assertTrue(fail,error)
|
||||
self.reset()
|
||||
|
||||
# 2-way column mux
|
||||
c.num_words = 64
|
||||
c.words_per_row = 2
|
||||
debug.info(1, "Functional test for multi-port ({0}RW {1}W {2}R) sram with {3}bit words, {4}words, {5}words per row, {6}banks".format(OPTS.num_rw_ports,
|
||||
OPTS.num_w_ports,
|
||||
OPTS.num_r_ports,
|
||||
c.word_size,
|
||||
c.num_words,
|
||||
c.words_per_row,
|
||||
c.num_banks))
|
||||
s = sram(c, name="sram2")
|
||||
s.sp_write(tempspice)
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
f.num_cycles = 10
|
||||
(fail,error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
self.reset()
|
||||
"""
|
||||
# 4-way column mux
|
||||
c.num_words = 256
|
||||
c.words_per_row = 4
|
||||
debug.info(1, "Functional test for multi-port ({0}RW {1}W {2}R) sram with {3}bit words, {4}words, {5}words per row, {6}banks".format(OPTS.num_rw_ports,
|
||||
OPTS.num_w_ports,
|
||||
OPTS.num_r_ports,
|
||||
c.word_size,
|
||||
c.num_words,
|
||||
c.words_per_row,
|
||||
c.num_banks))
|
||||
s = sram(c, name="sram1")
|
||||
s.sp_write(tempspice)
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
f.num_cycles = 10
|
||||
(fail,error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
self.reset()
|
||||
|
||||
# 8-way column mux
|
||||
c.num_words = 512
|
||||
c.words_per_row = 8
|
||||
debug.info(1, "Functional test for multi-port ({0}RW {1}W {2}R) sram with {3}bit words, {4}words, {5}words per row, {6}banks".format(OPTS.num_rw_ports,
|
||||
OPTS.num_w_ports,
|
||||
OPTS.num_r_ports,
|
||||
c.word_size,
|
||||
c.num_words,
|
||||
c.words_per_row,
|
||||
c.num_banks))
|
||||
s = sram(c, name="sram1")
|
||||
s.sp_write(tempspice)
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
f.num_cycles = 10
|
||||
(fail,error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
self.reset()
|
||||
"""
|
||||
globals.end_openram()
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
|
|
|
|||
|
|
@ -30,22 +30,74 @@ class sram_func_test(openram_test):
|
|||
from sram import sram
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
num_words=64,
|
||||
num_words=32,
|
||||
num_banks=1)
|
||||
c.words_per_row=2
|
||||
debug.info(1, "Functional test for 1bit, 16word SRAM, with 1 bank")
|
||||
c.words_per_row=1
|
||||
|
||||
# no column mux
|
||||
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
|
||||
c.num_words,
|
||||
c.words_per_row,
|
||||
c.num_banks))
|
||||
s = sram(c, name="sram1")
|
||||
|
||||
tempspice = OPTS.openram_temp + "temp.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
f.num_cycles = 10
|
||||
(fail, error) = f.run()
|
||||
|
||||
self.assertTrue(fail,error)
|
||||
self.reset()
|
||||
|
||||
# 2-way column mux
|
||||
c.num_words=64
|
||||
c.words_per_row=2
|
||||
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
|
||||
c.num_words,
|
||||
c.words_per_row,
|
||||
c.num_banks))
|
||||
s = sram(c, name="sram2")
|
||||
s.sp_write(tempspice)
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
f.num_cycles = 10
|
||||
(fail, error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
self.reset()
|
||||
"""
|
||||
# 4-way column mux
|
||||
c.num_words=256
|
||||
c.words_per_row=4
|
||||
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
|
||||
c.num_words,
|
||||
c.words_per_row,
|
||||
c.num_banks))
|
||||
s = sram(c, name="sram3")
|
||||
s.sp_write(tempspice)
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
f.num_cycles = 10
|
||||
(fail, error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
self.reset()
|
||||
|
||||
# 8-way column mux
|
||||
c.num_words=512
|
||||
c.words_per_row=8
|
||||
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
|
||||
c.num_words,
|
||||
c.words_per_row,
|
||||
c.num_banks))
|
||||
s = sram(c, name="sram4")
|
||||
s.sp_write(tempspice)
|
||||
|
||||
f = functional(s.s, tempspice, corner)
|
||||
f.num_cycles = 10
|
||||
(fail, error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
self.reset()
|
||||
"""
|
||||
globals.end_openram()
|
||||
|
||||
# instantiate a copdsay of the class to actually run the test
|
||||
|
|
|
|||
Loading…
Reference in New Issue