mirror of https://github.com/VLSIDA/OpenRAM.git
SRAM layout and functional tests with spare cols
This commit is contained in:
parent
c7d86b21ae
commit
eb0c595dbe
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ class bank(design.design):
|
|||
for bit in range(self.num_wmasks):
|
||||
self.add_pin("bank_wmask{0}_{1}".format(port, bit), "INPUT")
|
||||
for bit in range(self.num_spare_cols):
|
||||
self.add_pin("spare_wen{0}_{1}".format(port, bit), "INPUT")
|
||||
self.add_pin("bank_spare_wen{0}_{1}".format(port, bit), "INPUT")
|
||||
for port in self.all_ports:
|
||||
self.add_pin("wl_en{0}".format(port), "INPUT")
|
||||
self.add_pin("vdd", "POWER")
|
||||
|
|
@ -442,7 +442,7 @@ class bank(design.design):
|
|||
for bit in range(self.num_wmasks):
|
||||
temp.append("bank_wmask{0}_{1}".format(port, bit))
|
||||
for bit in range(self.num_spare_cols):
|
||||
temp.append("spare_wen{0}_{1}".format(port, bit))
|
||||
temp.append("bank_spare_wen{0}_{1}".format(port, bit))
|
||||
temp.extend(["vdd", "gnd"])
|
||||
|
||||
self.connect_inst(temp)
|
||||
|
|
@ -725,15 +725,15 @@ class bank(design.design):
|
|||
din_name = "din{0}_{1}".format(port, row)
|
||||
self.copy_layout_pin(self.port_data_inst[port], data_name, din_name)
|
||||
|
||||
if self.word_size:
|
||||
if self.write_size:
|
||||
for row in range(self.num_wmasks):
|
||||
wmask_name = "bank_wmask_{}".format(row)
|
||||
bank_wmask_name = "bank_wmask{0}_{1}".format(port, row)
|
||||
self.copy_layout_pin(self.port_data_inst[port], wmask_name, bank_wmask_name)
|
||||
|
||||
for col in range(self.num_spare_cols):
|
||||
sparecol_name = "spare_wen{}".format(col)
|
||||
bank_sparecol_name = "spare_wen{0}_{1}".format(port, col)
|
||||
sparecol_name = "bank_spare_wen{}".format(col)
|
||||
bank_sparecol_name = "bank_spare_wen{0}_{1}".format(port, col)
|
||||
self.copy_layout_pin(self.port_data_inst[port], sparecol_name, bank_sparecol_name)
|
||||
|
||||
def channel_route_bitlines(self, inst1, inst2, num_bits,
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ class control_logic(design.design):
|
|||
# clk_buf drives a flop for every address
|
||||
addr_flops = math.log(self.num_words, 2) + math.log(self.words_per_row, 2)
|
||||
# plus data flops and control flops
|
||||
num_flops = addr_flops + self.word_size + self.num_control_signals
|
||||
num_flops = addr_flops + self.word_size + self.num_spare_cols + self.num_control_signals
|
||||
# each flop internally has a FO 5 approximately
|
||||
# plus about 5 fanouts for the control logic
|
||||
clock_fanout = 5 * num_flops + 5
|
||||
|
|
@ -135,7 +135,7 @@ class control_logic(design.design):
|
|||
|
||||
# s_en drives every sense amp
|
||||
self.sen_and3 = factory.create(module_type="pand3",
|
||||
size=self.word_size,
|
||||
size=self.word_size + self.num_spare_cols,
|
||||
height=dff_height)
|
||||
self.add_mod(self.sen_and3)
|
||||
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ class port_data(design.design):
|
|||
for bit in range(self.num_wmasks):
|
||||
self.add_pin("bank_wmask_{}".format(bit), "INPUT")
|
||||
for bit in range(self.num_spare_cols):
|
||||
self.add_pin("spare_wen{}".format(bit), "INPUT")
|
||||
self.add_pin("bank_spare_wen{}".format(bit), "INPUT")
|
||||
self.add_pin("vdd", "POWER")
|
||||
self.add_pin("gnd", "GROUND")
|
||||
|
||||
|
|
@ -387,12 +387,12 @@ class port_data(design.design):
|
|||
for i in range(self.num_wmasks):
|
||||
temp.append("wdriver_sel_{}".format(i))
|
||||
for i in range(self.num_spare_cols):
|
||||
temp.append("spare_wen{}".format(i))
|
||||
temp.append("bank_spare_wen{}".format(i))
|
||||
|
||||
elif self.num_spare_cols and not self.write_size:
|
||||
temp.append("w_en")
|
||||
for i in range(self.num_spare_cols):
|
||||
temp.append("spare_wen{}".format(i))
|
||||
temp.append("bank_spare_wen{}".format(i))
|
||||
else:
|
||||
temp.append("w_en")
|
||||
temp.extend(["vdd", "gnd"])
|
||||
|
|
@ -627,9 +627,9 @@ class port_data(design.design):
|
|||
start_bit=0
|
||||
|
||||
if self.port==0:
|
||||
off=1
|
||||
off = 1
|
||||
else:
|
||||
off=0
|
||||
off = 0
|
||||
|
||||
|
||||
if self.num_spare_cols != 0 and self.col_addr_size>0:
|
||||
|
|
@ -722,11 +722,11 @@ class port_data(design.design):
|
|||
self.copy_layout_pin(self.write_driver_array_inst, "en_{}".format(bit), "wdriver_sel_{}".format(bit))
|
||||
for bit in range(self.num_spare_cols):
|
||||
# Add spare columns' en_{} pins
|
||||
self.copy_layout_pin(self.write_driver_array_inst, "en_{}".format(bit + self.num_wmasks), "spare_wen{}".format(bit))
|
||||
self.copy_layout_pin(self.write_driver_array_inst, "en_{}".format(bit + self.num_wmasks), "bank_spare_wen{}".format(bit))
|
||||
elif self.num_spare_cols and not self.write_mask_and_array_inst:
|
||||
self.copy_layout_pin(self.write_driver_array_inst, "en_0", "w_en")
|
||||
for bit in range(self.num_spare_cols):
|
||||
self.copy_layout_pin(self.write_driver_array_inst, "en_{}".format(bit + 1), "spare_wen{}".format(bit))
|
||||
self.copy_layout_pin(self.write_driver_array_inst, "en_{}".format(bit + 1), "bank_spare_wen{}".format(bit))
|
||||
else:
|
||||
self.copy_layout_pin(self.write_driver_array_inst, "en", "w_en")
|
||||
if self.write_mask_and_array_inst:
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ class write_driver_array(design.design):
|
|||
offset = self.num_wmasks
|
||||
else:
|
||||
offset = 1
|
||||
name = "write_driver{}".format(index)
|
||||
name = "write_driver{}".format(self.columns + i)
|
||||
self.driver_insts[index]=self.add_inst(name=name,
|
||||
mod=self.driver)
|
||||
|
||||
|
|
@ -234,27 +234,30 @@ class write_driver_array(design.design):
|
|||
|
||||
for i in range(self.num_spare_cols):
|
||||
inst = self.driver_insts[self.word_size + i]
|
||||
en_pin = inst.get_pin(inst.mod.en_name)
|
||||
self.add_layout_pin(text=self.en_name + "_{0}".format(i + self.num_wmasks),
|
||||
layer="m1",
|
||||
offset=inst.get_pin(inst.mod.en_name).ll(),
|
||||
width=self.single_col_width - inst.get_pin(inst.mod.en_name).width())
|
||||
offset=en_pin.ll(),
|
||||
width=self.driver.width - en_pin.width())
|
||||
|
||||
|
||||
elif self.num_spare_cols and not self.write_size:
|
||||
# shorten enable rail to accomodate those for spare write drivers
|
||||
inst = self.driver_insts[0]
|
||||
en_pin = inst.get_pin(inst.mod.en_name)
|
||||
self.add_layout_pin(text=self.en_name + "_{0}".format(0),
|
||||
layer="m1",
|
||||
offset=inst.get_pin(inst.mod.en_name).ll(),
|
||||
width=self.width_regular_cols - (self.words_per_row * inst.get_pin(inst.mod.en_name).width()))
|
||||
offset=en_pin.ll(),
|
||||
width=self.width_regular_cols - self.words_per_row * en_pin.width())
|
||||
|
||||
# individual enables for every spare write driver
|
||||
for i in range(self.num_spare_cols):
|
||||
inst = self.driver_insts[self.word_size + i]
|
||||
en_pin = inst.get_pin(inst.mod.en_name)
|
||||
self.add_layout_pin(text=self.en_name + "_{0}".format(i + 1),
|
||||
layer="m1",
|
||||
offset=inst.get_pin(inst.mod.en_name).ll(),
|
||||
width=self.single_col_width - inst.get_pin(inst.mod.en_name).width())
|
||||
offset=en_pin.ll(),
|
||||
width=self.driver.width - en_pin.width())
|
||||
|
||||
else:
|
||||
inst = self.driver_insts[0]
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ class sram_1bank(sram_base):
|
|||
else:
|
||||
self.data_dff_insts = self.create_data_dff()
|
||||
|
||||
if self.num_spare_cols:
|
||||
self.spare_wen_dff_insts = self.create_spare_wen_dff()
|
||||
else:
|
||||
self.num_spare_cols = 0
|
||||
|
||||
def place_instances(self):
|
||||
"""
|
||||
This places the instances for a single bank SRAM with control
|
||||
|
|
@ -57,6 +62,7 @@ class sram_1bank(sram_base):
|
|||
row_addr_pos = [None] * len(self.all_ports)
|
||||
col_addr_pos = [None] * len(self.all_ports)
|
||||
wmask_pos = [None] * len(self.all_ports)
|
||||
spare_wen_pos = [None] * len(self.all_ports)
|
||||
data_pos = [None] * len(self.all_ports)
|
||||
|
||||
# These positions utilize the channel route sizes.
|
||||
|
|
@ -69,9 +75,21 @@ class sram_1bank(sram_base):
|
|||
self.data_bus_size = self.m4_nonpref_pitch * (self.word_size + self.num_spare_cols) + self.data_bus_gap
|
||||
self.wmask_bus_gap = self.m2_nonpref_pitch * 2
|
||||
self.wmask_bus_size = self.m2_nonpref_pitch * (max(self.num_wmasks + 1, self.col_addr_size + 1)) + self.wmask_bus_gap
|
||||
if self.num_spare_cols:
|
||||
self.spare_wen_bus_gap = self.m2_nonpref_pitch * 2
|
||||
self.spare_wen_bus_size = self.m2_nonpref_pitch * (max(self.num_spare_cols + 1, self.col_addr_size + 1)) + self.spare_wen_bus_gap
|
||||
else:
|
||||
self.spare_wen_bus_size = 0
|
||||
|
||||
elif self.num_spare_cols and not self.write_size:
|
||||
self.data_bus_gap = self.m4_nonpref_pitch * 2
|
||||
self.data_bus_size = self.m4_nonpref_pitch * (self.word_size + self.num_spare_cols) + self.data_bus_gap
|
||||
self.spare_wen_bus_gap = self.m2_nonpref_pitch * 2
|
||||
self.spare_wen_bus_size = self.m2_nonpref_pitch * (max(self.num_spare_cols + 1, self.col_addr_size + 1)) + self.spare_wen_bus_gap
|
||||
|
||||
else:
|
||||
self.data_bus_gap = self.m3_nonpref_pitch * 2
|
||||
self.data_bus_size = self.m3_nonpref_pitch * (max(self.word_size + self.num_spare_cols + 1, self.col_addr_size + 1)) + self.data_bus_gap
|
||||
self.data_bus_size = self.m3_nonpref_pitch * (max(self.word_size + 1, self.col_addr_size + 1)) + self.data_bus_gap
|
||||
|
||||
self.col_addr_bus_gap = self.m2_nonpref_pitch * 2
|
||||
self.col_addr_bus_size = self.m2_nonpref_pitch * (self.col_addr_size) + self.col_addr_bus_gap
|
||||
|
|
@ -81,34 +99,57 @@ class sram_1bank(sram_base):
|
|||
|
||||
if port in self.write_ports:
|
||||
if self.write_size:
|
||||
bus_size = max(self.wmask_bus_size, self.spare_wen_bus_size)
|
||||
# Add the write mask flops below the write mask AND array.
|
||||
wmask_pos[port] = vector(self.bank.bank_array_ll.x,
|
||||
- self.wmask_bus_size - self.dff.height)
|
||||
- bus_size - self.dff.height)
|
||||
self.wmask_dff_insts[port].place(wmask_pos[port])
|
||||
|
||||
# Add the data flops below the write mask flops.
|
||||
data_pos[port] = vector(self.bank.bank_array_ll.x,
|
||||
- self.data_bus_size - self.wmask_bus_size - 2 * self.dff.height)
|
||||
- self.data_bus_size - bus_size - 2 * self.dff.height)
|
||||
self.data_dff_insts[port].place(data_pos[port])
|
||||
|
||||
#Add spare write enable flops to the right of write mask flops
|
||||
if self.num_spare_cols:
|
||||
spare_wen_pos[port] = vector(self.bank.bank_array_ll.x + self.wmask_dff_insts[port].width + self.bank.m2_gap,
|
||||
- bus_size - self.dff.height)
|
||||
self.spare_wen_dff_insts[port].place(spare_wen_pos[port])
|
||||
|
||||
elif self.num_spare_cols and not self.write_size:
|
||||
# Add spare write enable flops below bank (lower right)
|
||||
spare_wen_pos[port] = vector(self.bank.bank_array_ll.x,
|
||||
- self.spare_wen_bus_size - self.dff.height)
|
||||
self.spare_wen_dff_insts[port].place(spare_wen_pos[port])
|
||||
|
||||
# Add the data flops below the spare write enable flops.
|
||||
data_pos[port] = vector(self.bank.bank_array_ll.x,
|
||||
- self.data_bus_size - self.spare_wen_bus_size - 2 * self.dff.height)
|
||||
self.data_dff_insts[port].place(data_pos[port])
|
||||
|
||||
else:
|
||||
# Add the data flops below the bank to the right of the lower-left of bank array
|
||||
# This relies on the lower-left of the array of the bank
|
||||
# decoder in upper left, bank in upper right, sensing in lower right.
|
||||
# These flops go below the sensing and leave a gap to channel route to the
|
||||
# sense amps.
|
||||
if port in self.write_ports:
|
||||
data_pos[port] = vector(self.bank.bank_array_ll.x,
|
||||
-self.data_bus_size - self.dff.height)
|
||||
self.data_dff_insts[port].place(data_pos[port])
|
||||
data_pos[port] = vector(self.bank.bank_array_ll.x,
|
||||
-self.data_bus_size - self.dff.height)
|
||||
self.data_dff_insts[port].place(data_pos[port])
|
||||
|
||||
else:
|
||||
wmask_pos[port] = vector(self.bank.bank_array_ll.x, 0)
|
||||
data_pos[port] = vector(self.bank.bank_array_ll.x, 0)
|
||||
spare_wen_pos[port] = vector(self.bank.bank_array_ll.x, 0)
|
||||
|
||||
# Add the col address flops below the bank to the left of the lower-left of bank array
|
||||
if self.col_addr_dff:
|
||||
if self.write_size:
|
||||
col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap,
|
||||
-self.wmask_bus_size - self.col_addr_dff_insts[port].height)
|
||||
-bus_size - self.col_addr_dff_insts[port].height)
|
||||
elif self.num_spare_cols and not self.write_size:
|
||||
col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap,
|
||||
-self.spare_wen_bus_size - self.col_addr_dff_insts[port].height)
|
||||
else:
|
||||
col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap,
|
||||
-self.data_bus_size - self.col_addr_dff_insts[port].height)
|
||||
|
|
@ -134,15 +175,34 @@ class sram_1bank(sram_base):
|
|||
|
||||
if port in self.write_ports:
|
||||
if self.write_size:
|
||||
# Add the write mask flops below the write mask AND array.
|
||||
bus_size = max(self.wmask_bus_size, self.spare_wen_bus_size)
|
||||
# Add the write mask flops above the write mask AND array.
|
||||
wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.wmask_dff_insts[port].width,
|
||||
self.bank.height + self.wmask_bus_size + self.dff.height)
|
||||
self.bank.height + bus_size + self.dff.height)
|
||||
self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX")
|
||||
|
||||
# Add the data flops below the write mask flops
|
||||
# Add the data flops above the write mask flops
|
||||
data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
|
||||
self.bank.height + self.wmask_bus_size + self.data_bus_size + 2 * self.dff.height)
|
||||
self.bank.height + bus_size + self.data_bus_size + 2 * self.dff.height)
|
||||
self.data_dff_insts[port].place(data_pos[port], mirror="MX")
|
||||
|
||||
if self.num_spare_cols:
|
||||
spare_wen_pos[port] = vector(self.bank.bank_array_ur.x - self.wmask_dff_insts[port].width
|
||||
- self.spare_wen_dff_insts[port].width - self.bank.m2_gap,
|
||||
self.bank.height + bus_size + self.dff.height))
|
||||
self.spare_wen_dff_insts[port].place(spare_wen_pos[port], mirror="MX")
|
||||
|
||||
# Place dffs when spare cols is enabled
|
||||
elif self.num_spare_cols and not self.write_size:
|
||||
# Spare wen flops on the upper right, below data flops
|
||||
spare_wen_pos[port] = vector(self.bank.bank_array_ur.x - self.spare_wen_dff_insts[port].width,
|
||||
self.bank.height + self.spare_wen_bus_size + self.dff.height)
|
||||
self.spare_wen_dff_insts[port].place(spare_wen_pos[port], mirror="MX")
|
||||
# Add the data flops above the spare write enable flops
|
||||
data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width,
|
||||
self.bank.height + self.spare_wen_bus_size + self.data_bus_size + 2 * self.dff.height)
|
||||
self.data_dff_insts[port].place(data_pos[port], mirror="MX")
|
||||
|
||||
else:
|
||||
# Add the data flops above the bank to the left of the upper-right of bank array
|
||||
# This relies on the upper-right of the array of the bank
|
||||
|
|
@ -157,7 +217,10 @@ class sram_1bank(sram_base):
|
|||
if self.col_addr_dff:
|
||||
if self.write_size:
|
||||
col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap,
|
||||
self.bank.height + self.wmask_bus_size + self.dff.height)
|
||||
self.bank.height + bus_size + self.dff.height)
|
||||
elif self.num_spare_cols and not self.write_size:
|
||||
col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap,
|
||||
self.bank.height + self.spare_wen_bus_size + self.dff.height)
|
||||
else:
|
||||
col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap,
|
||||
self.bank.height + self.data_bus_size + self.dff.height)
|
||||
|
|
@ -218,9 +281,10 @@ class sram_1bank(sram_base):
|
|||
self.copy_layout_pin(self.wmask_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"wmask{0}[{1}]".format(port, bit))
|
||||
|
||||
for bit in range(self.num_spare_cols):
|
||||
self.copy_layout_pin(self.bank_inst,
|
||||
"spare_wen{0}_{1}".format(port, bit),
|
||||
self.copy_layout_pin(self.spare_wen_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"spare_wen{0}[{1}]".format(port, bit))
|
||||
|
||||
def route_layout(self):
|
||||
|
|
@ -242,6 +306,9 @@ class sram_1bank(sram_base):
|
|||
if self.write_size:
|
||||
self.route_wmask_dff()
|
||||
|
||||
if self.num_spare_cols:
|
||||
self.route_spare_wen_dff()
|
||||
|
||||
def route_clk(self):
|
||||
""" Route the clock network """
|
||||
|
||||
|
|
@ -308,6 +375,15 @@ class sram_1bank(sram_base):
|
|||
self.add_path("m2", [mid_pos, clk_steiner_pos], width=max(m2_via.width, m2_via.height))
|
||||
self.add_wire(self.m2_stack[::-1], [wmask_dff_clk_pos, mid_pos, clk_steiner_pos])
|
||||
|
||||
if self.num_spare_cols:
|
||||
spare_wen_dff_clk_pin = self.spare_wen_dff_insts[port].get_pin("clk")
|
||||
spare_wen_dff_clk_pos = spare_wen_dff_clk_pin.center()
|
||||
mid_pos = vector(clk_steiner_pos.x, spare_wen_dff_clk_pos.y)
|
||||
# In some designs, the steiner via will be too close to the mid_pos via
|
||||
# so make the wire as wide as the contacts
|
||||
self.add_path("m2", [mid_pos, clk_steiner_pos], width=max(m2_via.width, m2_via.height))
|
||||
self.add_wire(self.m2_stack[::-1], [spare_wen_dff_clk_pos, mid_pos, clk_steiner_pos])
|
||||
|
||||
def route_control_logic(self):
|
||||
""" Route the control logic pins that are not inputs """
|
||||
|
||||
|
|
@ -373,20 +449,14 @@ class sram_1bank(sram_base):
|
|||
""" Connect the output of the data flops to the write driver """
|
||||
# This is where the channel will start (y-dimension at least)
|
||||
for port in self.write_ports:
|
||||
if self.write_size:
|
||||
if port % 2:
|
||||
offset = self.data_dff_insts[port].ll() - vector(0, self.data_bus_size)
|
||||
else:
|
||||
offset = self.data_dff_insts[port].ul() + vector(0, self.data_bus_gap)
|
||||
if port % 2:
|
||||
offset = self.data_dff_insts[port].ll() - vector(0, self.data_bus_size)
|
||||
else:
|
||||
if port % 2:
|
||||
offset = self.data_dff_insts[port].ll() - vector(0, self.data_bus_size)
|
||||
else:
|
||||
offset = self.data_dff_insts[port].ul() + vector(0, self.data_bus_gap)
|
||||
offset = self.data_dff_insts[port].ul() + vector(0, self.data_bus_gap)
|
||||
|
||||
dff_names = ["dout_{}".format(x) for x in range(self.word_size + self.num_spare_cols)]
|
||||
dff_pins = [self.data_dff_insts[port].get_pin(x) for x in dff_names]
|
||||
if self.write_size:
|
||||
if self.write_size or self.num_spare_cols:
|
||||
for x in dff_names:
|
||||
pin = self.data_dff_insts[port].get_pin(x)
|
||||
pin_offset = pin.center()
|
||||
|
|
@ -399,7 +469,7 @@ class sram_1bank(sram_base):
|
|||
|
||||
bank_names = ["din{0}_{1}".format(port, x) for x in range(self.word_size + self.num_spare_cols)]
|
||||
bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
|
||||
if self.write_size:
|
||||
if self.write_size or self.num_spare_cols:
|
||||
for x in bank_names:
|
||||
pin = self.bank_inst.get_pin(x)
|
||||
if port % 2:
|
||||
|
|
@ -411,7 +481,7 @@ class sram_1bank(sram_base):
|
|||
offset=pin_offset)
|
||||
|
||||
route_map = list(zip(bank_pins, dff_pins))
|
||||
if self.write_size:
|
||||
if self.write_size or self.num_spare_cols:
|
||||
layer_stack = self.m3_stack
|
||||
else:
|
||||
layer_stack = self.m1_stack
|
||||
|
|
@ -448,6 +518,36 @@ class sram_1bank(sram_base):
|
|||
self.create_horizontal_channel_route(netlist=route_map,
|
||||
offset=offset,
|
||||
layer_stack=self.m1_stack)
|
||||
def route_spare_wen_dff(self):
|
||||
""" Connect the output of the spare write enable flops to the spare write drivers """
|
||||
# This is where the channel will start (y-dimension at least)
|
||||
for port in self.write_ports:
|
||||
if port % 2:
|
||||
# for port 0
|
||||
offset = self.spare_wen_dff_insts[port].ll() - vector(0, self.spare_wen_bus_size)
|
||||
else:
|
||||
offset = self.spare_wen_dff_insts[port].ul() + vector(0, self.spare_wen_bus_gap)
|
||||
|
||||
dff_names = ["dout_{}".format(x) for x in range(self.num_spare_cols)]
|
||||
dff_pins = [self.spare_wen_dff_insts[port].get_pin(x) for x in dff_names]
|
||||
for x in dff_names:
|
||||
offset_pin = self.spare_wen_dff_insts[port].get_pin(x).center()
|
||||
self.add_via_center(layers=self.m1_stack,
|
||||
offset=offset_pin,
|
||||
directions=("V", "V"))
|
||||
|
||||
bank_names = ["bank_spare_wen{0}_{1}".format(port, x) for x in range(self.num_spare_cols)]
|
||||
bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
|
||||
for x in bank_names:
|
||||
offset_pin = self.bank_inst.get_pin(x).center()
|
||||
self.add_via_center(layers=self.m1_stack,
|
||||
offset=offset_pin)
|
||||
|
||||
route_map = list(zip(bank_pins, dff_pins))
|
||||
self.create_horizontal_channel_route(netlist=route_map,
|
||||
offset=offset,
|
||||
layer_stack=self.m1_stack)
|
||||
|
||||
|
||||
def add_lvs_correspondence_points(self):
|
||||
"""
|
||||
|
|
@ -470,6 +570,9 @@ class sram_1bank(sram_base):
|
|||
if self.write_size:
|
||||
for inst in self.wmask_dff_insts:
|
||||
self.graph_inst_exclude.add(inst)
|
||||
if self.num_spare_cols:
|
||||
for inst in self.spare_wen_dff_insts:
|
||||
self.graph_inst_exclude.add(inst)
|
||||
|
||||
def graph_exclude_addr_dff(self):
|
||||
"""Removes data dff from search graph. """
|
||||
|
|
|
|||
|
|
@ -285,6 +285,10 @@ class sram_base(design, verilog, lef):
|
|||
if self.write_size:
|
||||
self.wmask_dff = factory.create("dff_array", module_name="wmask_dff", rows=1, columns=self.num_wmasks)
|
||||
self.add_mod(self.wmask_dff)
|
||||
|
||||
if self.num_spare_cols:
|
||||
self.spare_wen_dff = factory.create("dff_array", module_name="spare_wen_dff", rows=1, columns=self.num_spare_cols)
|
||||
self.add_mod(self.spare_wen_dff)
|
||||
|
||||
# Create the bank module (up to four are instantiated)
|
||||
self.bank = factory.create("bank", sram_config=self.sram_config, module_name="bank")
|
||||
|
|
@ -358,7 +362,7 @@ class sram_base(design, verilog, lef):
|
|||
for bit in range(self.num_wmasks):
|
||||
temp.append("bank_wmask{}[{}]".format(port, bit))
|
||||
for bit in range(self.num_spare_cols):
|
||||
temp.append("spare_wen{0}[{1}]".format(port, bit))
|
||||
temp.append("bank_spare_wen{0}[{1}]".format(port, bit))
|
||||
for port in self.all_ports:
|
||||
temp.append("wl_en{0}".format(port))
|
||||
temp.extend(["vdd", "gnd"])
|
||||
|
|
@ -475,7 +479,29 @@ class sram_base(design, verilog, lef):
|
|||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
|
||||
|
||||
return insts
|
||||
|
||||
def create_spare_wen_dff(self):
|
||||
""" Add all spare write enable flops """
|
||||
insts = []
|
||||
for port in self.all_ports:
|
||||
if port in self.write_ports:
|
||||
insts.append(self.add_inst(name="spare_wen_dff{}".format(port),
|
||||
mod=self.spare_wen_dff))
|
||||
else:
|
||||
insts.append(None)
|
||||
continue
|
||||
|
||||
# inputs, outputs/output/bar
|
||||
inputs = []
|
||||
outputs = []
|
||||
for bit in range(self.num_spare_cols):
|
||||
inputs.append("spare_wen{}[{}]".format(port, bit))
|
||||
outputs.append("bank_spare_wen{}[{}]".format(port, bit))
|
||||
|
||||
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
|
||||
|
||||
return insts
|
||||
|
||||
def create_control_logic(self):
|
||||
""" Add control logic instances """
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ from globals import OPTS
|
|||
from sram_factory import factory
|
||||
import debug
|
||||
|
||||
class sram_1bank_nomux_1rw_1r_test(openram_test):
|
||||
class sram_1bank_nomux_1rw_1r_spare_cols_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||
|
|
|
|||
|
|
@ -18,14 +18,13 @@ import debug
|
|||
|
||||
|
||||
# @unittest.skip("SKIPPING 20_sram_1bank_nomux_wmask_test")
|
||||
class sram_1bank_nomux_wmask_test(openram_test):
|
||||
class sram_1bank_nomux_spare_cols_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||
globals.init_openram(config_file)
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=8,
|
||||
write_size=4,
|
||||
num_spare_cols=3,
|
||||
num_words=16,
|
||||
num_banks=1)
|
||||
|
|
@ -33,13 +32,13 @@ class sram_1bank_nomux_wmask_test(openram_test):
|
|||
c.words_per_row = 1
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Layout test for {}rw,{}r,{}w sram "
|
||||
"with {} bit words, {} words, {} bit writes, {} words per "
|
||||
"with {} bit words, {} words, {} spare cols, {} words per "
|
||||
"row, {} banks".format(OPTS.num_rw_ports,
|
||||
OPTS.num_r_ports,
|
||||
OPTS.num_w_ports,
|
||||
c.word_size,
|
||||
c.num_words,
|
||||
c.write_size,
|
||||
c.num_spare_cols,
|
||||
c.words_per_row,
|
||||
c.num_banks))
|
||||
a = factory.create(module_type="sram", sram_config=c)
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env python3
|
||||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2019 Regents of the University of California and The Board
|
||||
# of Regents for the Oklahoma Agricultural and Mechanical College
|
||||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import unittest
|
||||
from testutils import *
|
||||
import sys,os
|
||||
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
import debug
|
||||
|
||||
#@unittest.skip("SKIPPING 22_sram_1bank_2mux_sparecols_func_test")
|
||||
class sram_1bank_2mux_sparecols_func_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||
globals.init_openram(config_file)
|
||||
OPTS.analytical_delay = False
|
||||
OPTS.netlist_only = True
|
||||
OPTS.trim_netlist = False
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
from importlib import reload
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import functional, delay
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
num_words=32,
|
||||
num_spare_cols=3,
|
||||
num_banks=1)
|
||||
c.words_per_row=2
|
||||
c.recompute_sizes()
|
||||
debug.info(1, "Functional test for sram with "
|
||||
"{} bit words, {} words, {} words per row, {} spare columns, {} banks".format(c.word_size,
|
||||
c.num_words,
|
||||
c.words_per_row,
|
||||
c.num_spare_cols,
|
||||
c.num_banks))
|
||||
s = factory.create(module_type="sram", sram_config=c)
|
||||
tempspice = OPTS.openram_temp + "sram.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
f = functional(s.s, tempspice, corner)
|
||||
(fail, error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
# run the test from the command line
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
del sys.argv[1:]
|
||||
header(__file__, OPTS.tech_name)
|
||||
unittest.main(testRunner=debugTestRunner())
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/env python3
|
||||
# See LICENSE for licensing information.
|
||||
#
|
||||
# Copyright (c) 2016-2019 Regents of the University of California and The Board
|
||||
# of Regents for the Oklahoma Agricultural and Mechanical College
|
||||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import unittest
|
||||
from testutils import *
|
||||
import sys,os
|
||||
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
import debug
|
||||
|
||||
#@unittest.skip("SKIPPING 22_sram_func_test")
|
||||
class sram_1bank_nomux_sparecols_func_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||
globals.init_openram(config_file)
|
||||
OPTS.analytical_delay = False
|
||||
OPTS.netlist_only = True
|
||||
|
||||
# This is a hack to reload the characterizer __init__ with the spice version
|
||||
from importlib import reload
|
||||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import functional
|
||||
from sram_config import sram_config
|
||||
c = sram_config(word_size=4,
|
||||
num_words=16,
|
||||
num_spare_cols=3,
|
||||
num_banks=1)
|
||||
c.words_per_row=1
|
||||
c.recompute_sizes()
|
||||
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 = factory.create(module_type="sram", sram_config=c)
|
||||
tempspice = OPTS.openram_temp + "sram.sp"
|
||||
s.sp_write(tempspice)
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
f = functional(s.s, tempspice, corner)
|
||||
(fail, error) = f.run()
|
||||
self.assertTrue(fail,error)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
# run the test from the command line
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
del sys.argv[1:]
|
||||
header(__file__, OPTS.tech_name)
|
||||
unittest.main(testRunner=debugTestRunner())
|
||||
Loading…
Reference in New Issue