mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-09-02 11:08:01 +02:00
SRAM layout and functional tests with spare cols
This commit is contained in:
@@ -18,7 +18,7 @@ from .charutils import *
|
||||
import utils
|
||||
from globals import OPTS
|
||||
from .simulation import simulation
|
||||
from .delay import delay
|
||||
# from .delay import delay
|
||||
import graph_util
|
||||
from sram_factory import factory
|
||||
|
||||
@@ -40,6 +40,9 @@ class functional(simulation):
|
||||
else:
|
||||
self.num_wmasks = 0
|
||||
|
||||
if not self.num_spare_cols:
|
||||
self.num_spare_cols = 0
|
||||
|
||||
self.set_corner(corner)
|
||||
self.set_spice_constants()
|
||||
self.set_stimulus_variables()
|
||||
@@ -86,6 +89,7 @@ class functional(simulation):
|
||||
if port in self.write_ports:
|
||||
checks.append((self.data_value[port],"data"))
|
||||
checks.append((self.wmask_value[port],"wmask"))
|
||||
checks.append((self.spare_wen_value[port],"spare_wen"))
|
||||
|
||||
for (val, name) in checks:
|
||||
debug.check(len(self.cycle_times)==len(val),
|
||||
@@ -226,7 +230,7 @@ class functional(simulation):
|
||||
# Extract dout values from spice timing.lis
|
||||
for (word, dout_port, eo_period, check) in self.read_check:
|
||||
sp_read_value = ""
|
||||
for bit in range(self.word_size):
|
||||
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))
|
||||
if value > self.v_high:
|
||||
sp_read_value = "1" + sp_read_value
|
||||
@@ -281,13 +285,18 @@ class functional(simulation):
|
||||
|
||||
def gen_data(self):
|
||||
""" Generates a random word to write. """
|
||||
random_value = random.randint(0,(2**self.word_size)-1)
|
||||
if not self.num_spare_cols:
|
||||
random_value = random.randint(0,(2**(self.word_size))-1)
|
||||
else:
|
||||
random_value1 = random.randint(0,(2**(self.word_size))-1)
|
||||
random_value2 = random.randint(0,(2**(self.num_spare_cols))-1)
|
||||
random_value = random_value1 + random_value2
|
||||
data_bits = self.convert_to_bin(random_value,False)
|
||||
return data_bits
|
||||
|
||||
def gen_addr(self):
|
||||
""" Generates a random address value to write to. """
|
||||
if (self.num_spare_rows == 0):
|
||||
if self.num_spare_rows==0:
|
||||
random_value = random.randint(0,(2**self.addr_size)-1)
|
||||
else:
|
||||
random_value = random.randint(0,((2**(self.addr_size-1)-1))+(self.num_spare_rows * self.words_per_row))
|
||||
@@ -307,8 +316,7 @@ class functional(simulation):
|
||||
if(is_addr):
|
||||
expected_value = self.addr_size
|
||||
else:
|
||||
|
||||
expected_value = self.word_size
|
||||
expected_value = self.word_size + self.num_spare_cols
|
||||
for i in range (expected_value - len(new_value)):
|
||||
new_value = "0" + new_value
|
||||
|
||||
@@ -337,7 +345,7 @@ class functional(simulation):
|
||||
# Add load capacitance to each of the read ports
|
||||
self.sf.write("\n* SRAM output loads\n")
|
||||
for port in self.read_ports:
|
||||
for bit in range(self.word_size):
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
sig_name="{0}{1}_{2} ".format(self.dout_name, port, bit)
|
||||
self.sf.write("CD{0}{1} {2} 0 {3}f\n".format(port, bit, sig_name, self.load))
|
||||
|
||||
@@ -357,7 +365,7 @@ class functional(simulation):
|
||||
# Generate data input bits
|
||||
self.sf.write("\n* Generation of data and address signals\n")
|
||||
for port in self.write_ports:
|
||||
for bit in range(self.word_size):
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
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)
|
||||
|
||||
@@ -386,6 +394,15 @@ class functional(simulation):
|
||||
self.stim.gen_pwl(sig_name, self.cycle_times, self.wmask_values[port][bit], self.period,
|
||||
self.slew, 0.05)
|
||||
|
||||
# Generate spare enable bits (for spare cols)
|
||||
for port in self.write_ports:
|
||||
if self.num_spare_cols:
|
||||
self.sf.write("\n* Generation of spare enable signals\n")
|
||||
for bit in range(self.num_spare_cols):
|
||||
sig_name = "SPARE_WEN{0}_{1} ".format(port, bit)
|
||||
self.stim.gen_pwl(sig_name, self.cycle_times, self.spare_wen_values[port][bit], self.period,
|
||||
self.slew, 0.05)
|
||||
|
||||
# Generate CLK signals
|
||||
for port in self.all_ports:
|
||||
self.stim.gen_pulse(sig_name="{0}{1}".format("clk", port),
|
||||
@@ -401,7 +418,7 @@ class functional(simulation):
|
||||
for (word, dout_port, eo_period, check) in self.read_check:
|
||||
t_intital = eo_period - 0.01*self.period
|
||||
t_final = eo_period + 0.01*self.period
|
||||
for bit in range(self.word_size):
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
self.stim.gen_meas_value(meas_name="V{0}_{1}ck{2}".format(dout_port,bit,check),
|
||||
dout="{0}_{1}".format(dout_port,bit),
|
||||
t_intital=t_intital,
|
||||
|
||||
@@ -26,6 +26,10 @@ class simulation():
|
||||
self.addr_size = self.sram.addr_size
|
||||
self.write_size = self.sram.write_size
|
||||
self.num_spare_rows = self.sram.num_spare_rows
|
||||
if not self.sram.num_spare_cols:
|
||||
self.num_spare_cols = 0
|
||||
else:
|
||||
self.num_spare_cols = self.sram.num_spare_cols
|
||||
self.sp_file = spfile
|
||||
|
||||
self.all_ports = self.sram.all_ports
|
||||
@@ -38,7 +42,6 @@ class simulation():
|
||||
else:
|
||||
self.num_wmasks = 0
|
||||
|
||||
|
||||
def set_corner(self,corner):
|
||||
""" Set the corner values """
|
||||
self.corner = corner
|
||||
@@ -61,10 +64,10 @@ class simulation():
|
||||
self.pins = self.gen_pin_names(port_signal_names=(self.addr_name,self.din_name,self.dout_name),
|
||||
port_info=(len(self.all_ports),self.write_ports,self.read_ports),
|
||||
abits=self.addr_size,
|
||||
dbits=self.word_size)
|
||||
dbits=self.word_size + self.num_spare_cols)
|
||||
debug.check(len(self.sram.pins) == len(self.pins),
|
||||
"Number of pins generated for characterization \
|
||||
do match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(self.sram.pins,
|
||||
do not match pins of SRAM\nsram.pins = {0}\npin_names = {1}".format(self.sram.pins,
|
||||
self.pins))
|
||||
#This is TODO once multiport control has been finalized.
|
||||
#self.control_name = "CSB"
|
||||
@@ -82,11 +85,13 @@ class simulation():
|
||||
self.addr_value = {port:[] for port in self.all_ports}
|
||||
self.data_value = {port:[] for port in self.write_ports}
|
||||
self.wmask_value = {port:[] for port in self.write_ports}
|
||||
self.spare_wen_value = {port:[] for port in self.write_ports}
|
||||
|
||||
# Three dimensional list to handle each addr and data bits for each port over the number of checks
|
||||
self.addr_values = {port:[[] for bit in range(self.addr_size)] for port in self.all_ports}
|
||||
self.data_values = {port:[[] for bit in range(self.word_size)] for port in self.write_ports}
|
||||
self.data_values = {port:[[] for bit in range(self.word_size + self.num_spare_cols)] for port in self.write_ports}
|
||||
self.wmask_values = {port:[[] for bit in range(self.num_wmasks)] for port in self.write_ports}
|
||||
self.spare_wen_values = {port:[[] for bit in range(self.num_spare_cols)] for port in self.write_ports}
|
||||
|
||||
# For generating comments in SPICE stimulus
|
||||
self.cycle_comments = []
|
||||
@@ -113,10 +118,10 @@ class simulation():
|
||||
|
||||
def add_data(self, data, port):
|
||||
""" Add the array of data values """
|
||||
debug.check(len(data)==self.word_size, "Invalid data word size.")
|
||||
debug.check(len(data)==(self.word_size + self.num_spare_cols), "Invalid data word size.")
|
||||
|
||||
self.data_value[port].append(data)
|
||||
bit = self.word_size - 1
|
||||
bit = self.word_size + self.num_spare_cols - 1
|
||||
for c in data:
|
||||
if c=="0":
|
||||
self.data_values[port][bit].append(0)
|
||||
@@ -137,10 +142,7 @@ class simulation():
|
||||
if c=="0":
|
||||
self.addr_values[port][bit].append(0)
|
||||
elif c=="1":
|
||||
if((self.num_spare_rows != 0) and (bit == (self.addr_size - 1))):
|
||||
self.addr_values[port][bit].append(0)
|
||||
else:
|
||||
self.addr_values[port][bit].append(1)
|
||||
self.addr_values[port][bit].append(1)
|
||||
else:
|
||||
debug.error("Non-binary address string",1)
|
||||
bit -= 1
|
||||
@@ -161,7 +163,21 @@ class simulation():
|
||||
debug.error("Non-binary wmask string", 1)
|
||||
bit -= 1
|
||||
|
||||
|
||||
def add_spare_wen(self, spare_wen, port):
|
||||
""" Add the array of spare write enable values (for spare cols) """
|
||||
debug.check(len(spare_wen) == self.num_spare_cols, "Invalid spare enable size.")
|
||||
|
||||
self.spare_wen_value[port].append(spare_wen)
|
||||
bit = self.num_spare_cols - 1
|
||||
for c in spare_wen:
|
||||
if c == "0":
|
||||
self.spare_wen_values[port][bit].append(0)
|
||||
elif c == "1":
|
||||
self.spare_wen_values[port][bit].append(1)
|
||||
else:
|
||||
debug.error("Non-binary spare enable signal string", 1)
|
||||
bit -= 1
|
||||
|
||||
def add_write(self, comment, address, data, wmask, port):
|
||||
""" Add the control values for a write cycle. """
|
||||
debug.check(port in self.write_ports,
|
||||
@@ -178,6 +194,7 @@ class simulation():
|
||||
self.add_data(data,port)
|
||||
self.add_address(address,port)
|
||||
self.add_wmask(wmask,port)
|
||||
self.add_spare_wen("1" * self.num_spare_cols, port)
|
||||
|
||||
#Add noops to all other ports.
|
||||
for unselected_port in self.all_ports:
|
||||
@@ -197,6 +214,7 @@ class simulation():
|
||||
self.t_current += self.period
|
||||
self.add_control_one_port(port, "read")
|
||||
self.add_address(address, port)
|
||||
self.add_spare_wen("0" * self.num_spare_cols, port)
|
||||
|
||||
# If the port is also a readwrite then add
|
||||
# the same value as previous cycle
|
||||
@@ -204,7 +222,7 @@ class simulation():
|
||||
try:
|
||||
self.add_data(self.data_value[port][-1], port)
|
||||
except:
|
||||
self.add_data("0"*self.word_size, port)
|
||||
self.add_data("0"*(self.word_size + self.num_spare_cols), port)
|
||||
try:
|
||||
self.add_wmask(self.wmask_value[port][-1], port)
|
||||
except:
|
||||
@@ -239,6 +257,7 @@ class simulation():
|
||||
self.add_data(data, port)
|
||||
self.add_address(address, port)
|
||||
self.add_wmask(wmask, port)
|
||||
self.add_spare_wen("1" * self.num_spare_cols, port)
|
||||
|
||||
def add_read_one_port(self, comment, address, port):
|
||||
""" Add the control values for a read cycle. Does not increment the period. """
|
||||
@@ -250,13 +269,14 @@ class simulation():
|
||||
|
||||
self.add_control_one_port(port, "read")
|
||||
self.add_address(address, port)
|
||||
self.add_spare_wen("0" * self.num_spare_cols, port)
|
||||
# If the port is also a readwrite then add
|
||||
# the same value as previous cycle
|
||||
if port in self.write_ports:
|
||||
try:
|
||||
self.add_data(self.data_value[port][-1], port)
|
||||
except:
|
||||
self.add_data("0"*self.word_size, port)
|
||||
self.add_data("0"*(self.word_size + self.num_spare_cols), port)
|
||||
try:
|
||||
self.add_wmask(self.wmask_value[port][-1], port)
|
||||
except:
|
||||
@@ -266,6 +286,7 @@ class simulation():
|
||||
def add_noop_one_port(self, port):
|
||||
""" Add the control values for a noop to a single port. Does not increment the period. """
|
||||
self.add_control_one_port(port, "noop")
|
||||
self.add_spare_wen("0" * self.num_spare_cols, port)
|
||||
|
||||
try:
|
||||
self.add_address(self.addr_value[port][-1], port)
|
||||
@@ -278,7 +299,7 @@ class simulation():
|
||||
try:
|
||||
self.add_data(self.data_value[port][-1], port)
|
||||
except:
|
||||
self.add_data("0"*self.word_size, port)
|
||||
self.add_data("0"*(self.word_size + self.num_spare_cols), port)
|
||||
try:
|
||||
self.add_wmask(self.wmask_value[port][-1], port)
|
||||
except:
|
||||
@@ -374,6 +395,11 @@ class simulation():
|
||||
for port in write_index:
|
||||
for bit in range(self.num_wmasks):
|
||||
pin_names.append("WMASK{0}_{1}".format(port,bit))
|
||||
|
||||
if self.num_spare_cols:
|
||||
for port in write_index:
|
||||
for bit in range(self.num_spare_cols):
|
||||
pin_names.append("SPARE_WEN{0}_{1}".format(port,bit))
|
||||
|
||||
for read_output in read_index:
|
||||
for i in range(dbits):
|
||||
|
||||
Reference in New Issue
Block a user