changes to support spare columns

This commit is contained in:
Aditi Sinha 2020-04-14 03:09:10 +00:00
parent b75eeb7688
commit 2661a42726
8 changed files with 439 additions and 51 deletions

View File

@ -27,6 +27,10 @@ class port_data(design.design):
else:
self.num_wmasks = 0
if self.num_spare_cols is None:
self.num_spare_cols = 0
if name == "":
name = "port_data_{0}".format(self.port)
design.design.__init__(self, name)
@ -102,7 +106,7 @@ class port_data(design.design):
self.DRC_LVS()
def add_pins(self):
""" Adding pins for port address module"""
""" Adding pins for port data module"""
self.add_pin("rbl_bl", "INOUT")
self.add_pin("rbl_br", "INOUT")
@ -111,11 +115,18 @@ class port_data(design.design):
br_name = self.get_br_name(self.port)
self.add_pin("{0}_{1}".format(bl_name, bit), "INOUT")
self.add_pin("{0}_{1}".format(br_name, bit), "INOUT")
for bit in range(self.num_spare_cols):
bl_name = self.get_bl_name(self.port)
br_name = self.get_br_name(self.port)
self.add_pin("spare{0}_{1}".format(bl_name, bit), "INOUT")
self.add_pin("spare{0}_{1}".format(br_name, bit), "INOUT")
if self.port in self.read_ports:
for bit in range(self.word_size):
for bit in range(self.word_size + self.num_spare_cols):
self.add_pin("dout_{}".format(bit), "OUTPUT")
if self.port in self.write_ports:
for bit in range(self.word_size):
for bit in range(self.word_size + self.num_spare_cols):
self.add_pin("din_{}".format(bit), "INPUT")
# Will be empty if no col addr lines
sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)]
@ -128,6 +139,8 @@ class port_data(design.design):
self.add_pin("w_en", "INPUT")
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("vdd", "POWER")
self.add_pin("gnd", "GROUND")
@ -179,7 +192,7 @@ class port_data(design.design):
# Extra column +1 is for RBL
# Precharge will be shifted left if needed
self.precharge_array = factory.create(module_type="precharge_array",
columns=self.num_cols + 1,
columns=self.num_cols + self.num_spare_cols + 1,
bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port])
self.add_mod(self.precharge_array)
@ -187,7 +200,8 @@ class port_data(design.design):
if self.port in self.read_ports:
self.sense_amp_array = factory.create(module_type="sense_amp_array",
word_size=self.word_size,
words_per_row=self.words_per_row)
words_per_row=self.words_per_row,
num_spare_cols=self.num_spare_cols)
self.add_mod(self.sense_amp_array)
else:
self.sense_amp_array = None
@ -206,7 +220,8 @@ class port_data(design.design):
self.write_driver_array = factory.create(module_type="write_driver_array",
columns=self.num_cols,
word_size=self.word_size,
write_size=self.write_size)
write_size=self.write_size,
num_spare_cols=self.num_spare_cols)
self.add_mod(self.write_driver_array)
if self.write_size is not None:
self.write_mask_and_array = factory.create(module_type="write_mask_and_array",
@ -249,7 +264,7 @@ class port_data(design.design):
# We create a dummy here to get bl/br names to add those pins to this
# module, which happens before we create the real precharge_array
self.precharge_array = factory.create(module_type="precharge_array",
columns=self.num_cols + 1,
columns=self.num_cols + self.num_spare_cols + 1,
bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port])
@ -272,6 +287,10 @@ class port_data(design.design):
for bit in range(self.num_cols):
temp.append("{0}_{1}".format(bl_name, bit))
temp.append("{0}_{1}".format(br_name, bit))
for bit in range(self.num_spare_cols):
temp.append("sparebl{0}_{1}".format(self.port, bit))
temp.append("sparebr{0}_{1}".format(self.port, bit))
# Use right BLs for RBL
if self.port==1:
@ -297,7 +316,6 @@ class port_data(design.design):
for col in range(self.num_cols):
temp.append("{0}_{1}".format(bl_name, col))
temp.append("{0}_{1}".format(br_name, col))
for word in range(self.words_per_row):
temp.append("sel_{}".format(word))
for bit in range(self.word_size):
@ -330,8 +348,14 @@ class port_data(design.design):
else:
temp.append("{0}_out_{1}".format(bl_name, bit))
temp.append("{0}_out_{1}".format(br_name, bit))
temp.extend(["s_en", "vdd", "gnd"])
for bit in range(self.num_spare_cols):
temp.append("dout_{}".format(self.word_size + bit))
temp.append("sparebl{0}_{1}".format(self.port, bit))
temp.append("sparebr{0}_{1}".format(self.port, bit))
temp.append("s_en")
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
def place_sense_amp_array(self, offset):
@ -346,7 +370,7 @@ class port_data(design.design):
br_name = self.get_br_name(self.port)
temp = []
for bit in range(self.word_size):
for bit in range(self.word_size + self.num_spare_cols):
temp.append("din_{}".format(bit))
for bit in range(self.word_size):
@ -355,11 +379,20 @@ class port_data(design.design):
temp.append("{0}_{1}".format(br_name, bit))
else:
temp.append("{0}_out_{1}".format(bl_name, bit))
temp.append("{0}_out_{1}".format(br_name, bit))
temp.append("{0}_out_{1}".format(br_name, bit))
for bit in range(self.num_spare_cols):
temp.append("sparebl{0}_{1}".format(self.port, bit))
temp.append("sparebr{0}_{1}".format(self.port, bit))
if self.write_size is not None:
for i in range(self.num_wmasks):
temp.append("wdriver_sel_{}".format(i))
elif self.num_spare_cols:
temp.append("w_en")
for i in range(self.num_spare_cols):
temp.append("spare_wen{}".format(i))
else:
temp.append("w_en")
temp.extend(["vdd", "gnd"])
@ -445,7 +478,7 @@ class port_data(design.design):
def route_sense_amp_out(self, port):
""" Add pins for the sense amp output """
for bit in range(self.word_size):
for bit in range(self.word_size + self.num_spare_cols):
data_pin = self.sense_amp_array_inst.get_pin("data_{}".format(bit))
self.add_layout_pin_rect_center(text="dout_{0}".format(bit),
layer=data_pin.layer,
@ -456,7 +489,7 @@ class port_data(design.design):
def route_write_driver_in(self, port):
""" Connecting write driver """
for row in range(self.word_size):
for row in range(self.word_size + self.num_spare_cols):
data_name = "data_{}".format(row)
din_name = "din_{}".format(row)
self.copy_layout_pin(self.write_driver_array_inst, data_name, din_name)
@ -545,12 +578,36 @@ class port_data(design.design):
else:
start_bit=0
self.channel_route_bitlines(inst1=inst1,
inst1_bls_template=inst1_bls_templ,
inst2=inst2,
num_bits=self.word_size,
inst1_start_bit=start_bit)
if self.port==0:
off = 1
else:
off = 0
if self.num_spare_cols != 0 and self.col_addr_size>0:
self.channel_route_bitlines(inst1=self.column_mux_array_inst,
inst1_bls_template="{inst}_out_{bit}",
inst2=inst2,
num_bits=self.word_size,
inst1_start_bit=start_bit)
self.channel_route_bitlines(inst1=self.precharge_array_inst,
inst1_bls_template="{inst}_{bit}",
inst2=inst2,
num_bits=self.num_spare_cols,
inst1_start_bit=self.num_cols + off,
inst2_start_bit=self.word_size)
else:
self.channel_route_bitlines(inst1=inst1,
inst1_bls_template=inst1_bls_templ,
inst2=inst2,
num_bits=self.word_size + self.num_spare_cols,
inst1_start_bit=start_bit)
# spare cols connected to precharge array since they are read independently
def route_write_driver_to_column_mux_or_precharge_array(self, port):
""" Routing of BL and BR between sense_amp and column mux or precharge array """
inst2 = self.write_driver_array_inst
@ -569,10 +626,33 @@ class port_data(design.design):
else:
start_bit=0
self.channel_route_bitlines(inst1=inst1, inst2=inst2,
num_bits=self.word_size,
inst1_bls_template=inst1_bls_templ,
inst1_start_bit=start_bit)
if self.port==0:
off=1
else:
off=0
if self.num_spare_cols != 0 and self.col_addr_size>0:
self.channel_route_bitlines(inst1=self.column_mux_array_inst,
inst1_bls_template="{inst}_out_{bit}",
inst2=inst2,
num_bits=self.word_size,
inst1_start_bit=start_bit)
self.channel_route_bitlines(inst1=self.precharge_array_inst,
inst1_bls_template="{inst}_{bit}",
inst2=inst2,
num_bits=self.num_spare_cols,
inst1_start_bit=self.num_cols + off,
inst2_start_bit=self.word_size)
else:
self.channel_route_bitlines(inst1=inst1,
inst1_bls_template=inst1_bls_templ,
inst2=inst2,
num_bits=self.word_size + self.num_spare_cols,
inst1_start_bit=start_bit)
def route_write_driver_to_sense_amp(self, port):
""" Routing of BL and BR between write driver and sense amp """
@ -584,7 +664,7 @@ class port_data(design.design):
# but just in case, do a channel route.
self.channel_route_bitlines(inst1=inst1,
inst2=inst2,
num_bits=self.word_size)
num_bits=self.word_size + self.num_spare_cols)
def route_bitline_pins(self):
""" Add the bitline pins for the given port """
@ -595,13 +675,13 @@ class port_data(design.design):
self.copy_layout_pin(self.precharge_array_inst, "br_0", "rbl_br")
bit_offset=1
elif self.port==1:
self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(self.num_cols), "rbl_bl")
self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(self.num_cols), "rbl_br")
self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(self.num_cols + self.num_spare_cols), "rbl_bl")
self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(self.num_cols + self.num_spare_cols), "rbl_br")
bit_offset=0
else:
bit_offset=0
for bit in range(self.num_cols):
for bit in range(self.num_cols + self.num_spare_cols):
if self.precharge_array_inst:
self.copy_layout_pin(self.precharge_array_inst,
"bl_{}".format(bit + bit_offset),
@ -621,12 +701,16 @@ class port_data(design.design):
for pin_name in sel_names:
self.copy_layout_pin(self.column_mux_array_inst, pin_name)
if self.sense_amp_array_inst:
self.copy_layout_pin(self.sense_amp_array_inst, "en", "s_en")
self.copy_layout_pin(self.sense_amp_array_inst, "en", "s_en")
if self.write_driver_array_inst:
if self.write_mask_and_array_inst:
for bit in range(self.num_wmasks):
# Add write driver's en_{} pins
self.copy_layout_pin(self.write_driver_array_inst, "en_{}".format(bit), "wdriver_sel_{}".format(bit))
elif self.num_spare_cols:
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))
else:
self.copy_layout_pin(self.write_driver_array_inst, "en", "w_en")
if self.write_mask_and_array_inst:

View File

@ -19,7 +19,7 @@ class sense_amp_array(design.design):
Dynamically generated sense amp array for all bitlines.
"""
def __init__(self, name, word_size, words_per_row):
def __init__(self, name, word_size, words_per_row, num_spare_cols=None):
design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("word_size {0}".format(word_size))
@ -27,8 +27,12 @@ class sense_amp_array(design.design):
self.word_size = word_size
self.words_per_row = words_per_row
self.row_size = self.word_size * self.words_per_row
if not num_spare_cols:
self.num_spare_cols = 0
else:
self.num_spare_cols = num_spare_cols
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@ -58,9 +62,9 @@ class sense_amp_array(design.design):
self.height = self.amp.height
if self.bitcell.width > self.amp.width:
self.width = self.bitcell.width * self.word_size * self.words_per_row
self.width = self.bitcell.width * (self.word_size * self.words_per_row + self.num_spare_cols)
else:
self.width = self.amp.width * self.word_size * self.words_per_row
self.width = self.amp.width * (self.word_size * self.words_per_row + self.num_spare_cols)
self.place_sense_amp_array()
self.add_layout_pins()
@ -69,7 +73,7 @@ class sense_amp_array(design.design):
self.DRC_LVS()
def add_pins(self):
for i in range(0,self.word_size):
for i in range(0,self.word_size + self.num_spare_cols):
self.add_pin(self.data_name + "_{0}".format(i), "OUTPUT")
self.add_pin(self.get_bl_name() + "_{0}".format(i), "INPUT")
self.add_pin(self.get_br_name() + "_{0}".format(i), "INPUT")
@ -88,8 +92,7 @@ class sense_amp_array(design.design):
def create_sense_amp_array(self):
self.local_insts = []
for i in range(0,self.word_size):
for i in range(0,self.word_size + self.num_spare_cols):
name = "sa_d{0}".format(i)
self.local_insts.append(self.add_inst(name=name,
mod=self.amp))
@ -102,13 +105,14 @@ class sense_amp_array(design.design):
from tech import cell_properties
if self.bitcell.width > self.amp.width:
amp_spacing = self.bitcell.width * self.words_per_row
spare_cols_spacing = self.bitcell.width
else:
amp_spacing = self.amp.width * self.words_per_row
spare_cols_spacing = self.amp.width
for i in range(0,self.word_size):
xoffset = amp_spacing * i
# align the xoffset to the grid of bitcells. This way we
# align the xoffset to the grid of bitcells. This way we
# know when to do the mirroring.
grid_x = int(xoffset / self.amp.width)
@ -120,6 +124,23 @@ class sense_amp_array(design.design):
amp_position = vector(xoffset, 0)
self.local_insts[i].place(offset=amp_position,mirror=mirror)
# place spare sense amps (will share the same enable as regular sense amps)
for i in range(0,self.num_spare_cols):
index = self.word_size + i
xoffset = ((self.word_size * self.words_per_row) + i) * spare_cols_spacing
# align the xoffset to the grid of bitcells. This way we
# know when to do the mirroring.
grid_x = int(xoffset / self.amp.width)
if cell_properties.bitcell.mirror.y and grid_x % 2:
mirror = "MY"
xoffset = xoffset + self.amp.width
else:
mirror = ""
amp_position = vector(xoffset, 0)
self.local_insts[index].place(offset=amp_position,mirror=mirror)
def add_layout_pins(self):
@ -173,7 +194,7 @@ class sense_amp_array(design.design):
def get_en_cin(self):
"""Get the relative capacitance of all the sense amp enable connections in the array"""
sense_amp_en_cin = self.amp.get_en_cin()
return sense_amp_en_cin * self.word_size
return sense_amp_en_cin * (self.word_size + self.num_spare_cols)
def get_drain_cin(self):
"""Get the relative capacitance of the drain of the PMOS isolation TX"""

View File

@ -19,7 +19,7 @@ class write_driver_array(design.design):
Dynamically generated write driver array of all bitlines.
"""
def __init__(self, name, columns, word_size,write_size=None):
def __init__(self, name, columns, word_size, num_spare_cols=None, write_size=None):
design.design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("columns: {0}".format(columns))
@ -29,6 +29,10 @@ class write_driver_array(design.design):
self.word_size = word_size
self.write_size = write_size
self.words_per_row = int(columns / word_size)
if not num_spare_cols:
self.num_spare_cols = 0
else:
self.num_spare_cols = num_spare_cols
if self.write_size:
self.num_wmasks = int(self.word_size/self.write_size)
@ -61,9 +65,13 @@ class write_driver_array(design.design):
def create_layout(self):
if self.bitcell.width > self.driver.width:
self.width = self.columns * self.bitcell.width
self.width = (self.columns + self.num_spare_cols) * self.bitcell.width
self.width_regular_cols = self.columns * self.bitcell.width
self.single_col_width = self.bitcell.width
else:
self.width = self.columns * self.driver.width
self.width = (self.columns + self.num_spare_cols) * self.driver.width
self.width_regular_cols = self.columns * self.driver.width
self.single_col_width = self.driver.width
self.height = self.driver.height
self.place_write_array()
@ -72,14 +80,17 @@ class write_driver_array(design.design):
self.DRC_LVS()
def add_pins(self):
for i in range(self.word_size):
for i in range(self.word_size + self.num_spare_cols):
self.add_pin(self.data_name + "_{0}".format(i), "INPUT")
for i in range(self.word_size):
for i in range(self.word_size + self.num_spare_cols):
self.add_pin(self.get_bl_name() + "_{0}".format(i), "OUTPUT")
self.add_pin(self.get_br_name() + "_{0}".format(i), "OUTPUT")
if self.write_size:
for i in range(self.num_wmasks):
self.add_pin(self.en_name + "_{0}".format(i), "INPUT")
elif self.num_spare_cols:
for i in range(self.num_spare_cols + 1):
self.add_pin(self.en_name + "_{0}".format(i), "INPUT")
else:
self.add_pin(self.en_name, "INPUT")
self.add_pin("vdd", "POWER")
@ -113,12 +124,30 @@ class write_driver_array(design.design):
if w == self.write_size:
w = 0
windex+=1
elif self.num_spare_cols:
self.connect_inst([self.data_name + "_{0}".format(index),
self.get_bl_name() + "_{0}".format(index),
self.get_br_name() + "_{0}".format(index),
self.en_name + "_{0}".format(0), "vdd", "gnd"])
else:
self.connect_inst([self.data_name + "_{0}".format(index),
self.get_bl_name() + "_{0}".format(index),
self.get_br_name() + "_{0}".format(index),
self.en_name, "vdd", "gnd"])
for i in range(self.num_spare_cols):
index = self.word_size + i
name = "write_driver{}".format(index)
self.driver_insts[index]=self.add_inst(name=name,
mod=self.driver)
self.connect_inst([self.data_name + "_{0}".format(index),
self.get_bl_name() + "_{0}".format(index),
self.get_br_name() + "_{0}".format(index),
self.en_name + "_{0}".format(i + 1), "vdd", "gnd"])
def place_write_array(self):
from tech import cell_properties
@ -139,9 +168,23 @@ class write_driver_array(design.design):
base = vector(xoffset, 0)
self.driver_insts[index].place(offset=base, mirror=mirror)
# place spare write drivers (if spare columns are specified)
for i in range(self.num_spare_cols):
index = self.word_size + i
xoffset = (self.columns + i) * self.driver_spacing
if cell_properties.bitcell.mirror.y and i % 2:
mirror = "MY"
xoffset = xoffset + self.driver.width
else:
mirror = ""
base = vector(xoffset, 0)
self.driver_insts[index].place(offset=base, mirror=mirror)
def add_layout_pins(self):
for i in range(self.word_size):
for i in range(self.word_size + self.num_spare_cols):
inst = self.driver_insts[i]
din_pin = inst.get_pin(inst.mod.din_name)
self.add_layout_pin(text=self.data_name + "_{0}".format(i),
@ -186,14 +229,29 @@ class write_driver_array(design.design):
offset=en_pin.ll(),
width=wmask_en_len-en_gap,
height=en_pin.height())
elif self.num_spare_cols:
# shorten enable rail to accomodate those for spare write drivers
inst = self.driver_insts[0]
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()))
# individual enables for every spare write driver
for i in range(self.num_spare_cols):
inst = self.driver_insts[self.word_size + i]
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())
else:
inst = self.driver_insts[0]
self.add_layout_pin(text=self.en_name,
layer="m1",
offset=inst.get_pin(inst.mod.en_name).ll().scale(0,1),
width=self.width)
def get_w_en_cin(self):

View File

@ -45,6 +45,7 @@ class options(optparse.Values):
# You can manually specify banks, but it is better to auto-detect it.
num_banks = 1
num_spare_rows = 0
# num_spare_cols = 0
###################
# Optimization options

View File

@ -14,19 +14,18 @@ from sram_factory import factory
class sram_config:
""" This is a structure that is used to hold the SRAM configuration options. """
def __init__(self, word_size, num_words, write_size = None, num_banks=1, words_per_row=None, num_spare_rows=0):
def __init__(self, word_size, num_words, write_size = None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=None):
self.word_size = word_size
self.num_words = num_words
self.write_size = write_size
self.num_banks = num_banks
self.num_spare_rows = num_spare_rows
self.num_spare_cols = num_spare_cols
# This will get over-written when we determine the organization
self.words_per_row = words_per_row
self.compute_sizes()
self.compute_sizes()
def set_local_config(self, module):
""" Copy all of the member variables to the given module for convenience """

View File

@ -0,0 +1,55 @@
#!/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
class sense_amp_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check sense amp array for single port
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2")
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=1, num_spare_cols=3)
self.local_check(a)
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4")
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=4, num_spare_cols=2)
self.local_check(a)
# check sense amp array for multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
factory.reset()
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)")
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=2, num_spare_cols=2)
self.local_check(a)
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)")
a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=4, num_spare_cols=3)
self.local_check(a)
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())

View File

@ -0,0 +1,55 @@
#!/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
class write_driver_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
# check write driver array for single port
debug.info(2, "Testing write_driver_array for columns=8, word_size=8")
a = factory.create(module_type="write_driver_array", columns=8, word_size=8, num_spare_cols=3)
self.local_check(a)
debug.info(2, "Testing write_driver_array for columns=16, word_size=8")
a = factory.create(module_type="write_driver_array", columns=16, word_size=8, num_spare_cols=3)
self.local_check(a)
# check write driver array for multi-port
OPTS.bitcell = "pbitcell"
OPTS.num_rw_ports = 1
OPTS.num_w_ports = 0
OPTS.num_r_ports = 0
factory.reset()
debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)")
a = factory.create(module_type="write_driver_array", columns=8, word_size=8, num_spare_cols=3)
self.local_check(a)
debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)")
a = factory.create(module_type="write_driver_array", columns=16, word_size=8, num_spare_cols=3)
self.local_check(a)
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())

View File

@ -0,0 +1,115 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California
# 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
class port_data_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,
num_words=16,
num_spare_rows=1,
num_spare_cols=1)
c.words_per_row=1
factory.reset()
c.recompute_sizes()
debug.info(1, "No column mux")
a = factory.create("port_data", sram_config=c, port=0)
self.local_check(a)
c.num_words=32
c.words_per_row=2
factory.reset()
c.recompute_sizes()
debug.info(1, "Two way column mux")
a = factory.create("port_data", sram_config=c, port=0)
self.local_check(a)
c.num_words=64
c.words_per_row=4
c.num_spare_cols=3
factory.reset()
c.recompute_sizes()
debug.info(1, "Four way column mux")
a = factory.create("port_data", sram_config=c, port=0)
self.local_check(a)
c.word_size=2
c.num_words=128
c.words_per_row=8
c.num_spare_cols=4
factory.reset()
c.recompute_sizes()
debug.info(1, "Eight way column mux")
a = factory.create("port_data", sram_config=c, port=0)
self.local_check(a)
OPTS.bitcell = "bitcell_1w_1r"
OPTS.num_rw_ports = 0
OPTS.num_r_ports = 1
OPTS.num_w_ports = 1
c.num_words=16
c.words_per_row=1
factory.reset()
c.recompute_sizes()
debug.info(1, "No column mux")
a = factory.create("port_data", sram_config=c, port=0)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
self.local_check(a)
c.num_words=32
c.words_per_row=2
factory.reset()
c.recompute_sizes()
debug.info(1, "Two way column mux")
a = factory.create("port_data", sram_config=c, port=0)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
self.local_check(a)
c.num_words=64
c.words_per_row=4
factory.reset()
c.recompute_sizes()
debug.info(1, "Four way column mux")
a = factory.create("port_data", sram_config=c, port=0)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
self.local_check(a)
c.word_size=2
c.num_words=128
c.words_per_row=8
factory.reset()
c.recompute_sizes()
debug.info(1, "Eight way column mux")
a = factory.create("port_data", sram_config=c, port=0)
self.local_check(a)
a = factory.create("port_data", sram_config=c, port=1)
self.local_check(a)
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())