Merge branch 'dev' into s8_single_port

This commit is contained in:
jcirimel 2020-09-01 15:37:10 -07:00
commit 73443c8c95
19 changed files with 757 additions and 495 deletions

View File

@ -161,14 +161,23 @@ class spice():
there is a problem. The check option can be set to false
where we dynamically generate groups of connections after a
group of modules are generated."""
if (check and (len(self.insts[-1].mod.pins) != len(args))):
num_pins = len(self.insts[-1].mod.pins)
num_args = len(args)
if (check and num_pins != num_args):
from pprint import pformat
modpins_string=pformat(self.insts[-1].mod.pins)
argpins_string=pformat(args)
debug.error("Mod connections: {}".format(modpins_string))
debug.error("Inst connections: {}".format(argpins_string))
debug.error("Number of net connections ({0}) does not match last instance ({1})".format(len(self.insts[-1].mod.pins),
len(args)), 1)
if num_pins < num_args:
mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins)
arg_pins = args
else:
arg_pins = args + [""] * (num_pins - num_args)
mod_pins = self.insts[-1].mod.pins
modpins_string = "\n".join(["{0} -> {1}".format(arg, mod) for (arg, mod) in zip(arg_pins, mod_pins)])
debug.error("Connection mismatch:\nInst ({0}) -> Mod ({1})\n{2}".format(num_args,
num_pins,
modpins_string),
1)
self.conns.append(args)
if check and (len(self.insts)!=len(self.conns)):

View File

@ -82,7 +82,7 @@ class bank(design.design):
for bit in range(self.word_size + self.num_spare_cols):
self.add_pin("dout{0}_{1}".format(port, bit), "OUTPUT")
for port in self.all_ports:
self.add_pin_list(self.bitcell_array.get_rbl_bitline_names(port), "OUTPUT")
self.add_pin("rbl_bl_{0}_{0}".format(port), "OUTPUT")
for port in self.write_ports:
for bit in range(self.word_size + self.num_spare_cols):
self.add_pin("din{0}_{1}".format(port, bit), "INPUT")
@ -144,7 +144,7 @@ class bank(design.design):
to_layer="m3",
offset=pin_offset)
self.add_path(bl_pin.layer, [pin_offset, pin_pos])
self.add_layout_pin_segment_center(text="rbl_bl{0}".format(port),
self.add_layout_pin_segment_center(text="rbl_bl_{0}_{0}".format(port),
layer="m3",
start=left_right_offset,
end=pin_offset)
@ -356,13 +356,6 @@ class bank(design.design):
def add_modules(self):
""" Add all the modules using the class loader """
# create arrays of bitline and bitline_bar names for read, write, or all ports
self.bitcell = factory.create(module_type="bitcell")
self.bl_names = self.bitcell.get_all_bl_names()
self.br_names = self.bitcell.get_all_br_names()
self.wl_names = self.bitcell.get_all_wl_names()
self.bitline_names = self.bitcell.get_all_bitline_names()
self.port_data = []
for port in self.all_ports:
temp_pre = factory.create(module_type="port_data",
@ -381,9 +374,8 @@ class bank(design.design):
self.bitcell_array = factory.create(module_type="replica_bitcell_array",
cols=self.num_cols + self.num_spare_cols,
rows=self.num_rows,
left_rbl=1,
right_rbl=1 if len(self.all_ports)>1 else 0,
bitcell_ports=self.all_ports)
rbl=[1, 1 if len(self.all_ports)>1 else 0])
self.add_mod(self.bitcell_array)
if(self.num_banks > 1):
@ -394,28 +386,29 @@ class bank(design.design):
""" Creating Bitcell Array """
self.bitcell_array_inst=self.add_inst(name="replica_bitcell_array",
mod=self.bitcell_array)
temp = []
rbl_names = self.bitcell_array.get_rbl_bitline_names()
temp.extend(rbl_names)
bitline_names = self.bitcell_array.get_bitline_names()
temp.extend(bitline_names)
# Replace RBL wordline with wl_en#
wordline_names = self.bitcell_array.get_wordline_names()
# Arrays are always:
# word lines (bottom to top)
# bit lines (left to right)
# vdd
# gnd
rbl_wl_names = []
for port in self.all_ports:
rbl_wl_names.append(self.bitcell_array.get_rbl_wordline_names(port))
temp = self.bitcell_array.get_all_bitline_names()
wordline_names = self.bitcell_array.get_all_wordline_names()
# Rename the RBL WL to the enable name
for port in self.all_ports:
wordline_names = [x.replace(rbl_wl_names[port], "wl_en{0}".format(port)) for x in wordline_names]
rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)
wordline_names = [x.replace(rbl_wl_name[port], "wl_en{0}".format(port)) for x in wordline_names]
# Connect the other RBL WL to gnd
wordline_names = ["gnd" if x.startswith("rbl_wl") else x for x in wordline_names]
# Connect the dummy WL to gnd
wordline_names = ["gnd" if x.startswith("dummy") else x for x in wordline_names]
temp.extend(wordline_names)
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
def place_bitcell_array(self, offset):
@ -424,17 +417,15 @@ class bank(design.design):
def create_port_data(self):
""" Creating Port Data """
self.port_data_inst = [None] * len(self.all_ports)
for port in self.all_ports:
self.port_data_inst[port]=self.add_inst(name="port_data{}".format(port),
mod=self.port_data[port])
temp = []
rbl_bl_names = self.bitcell_array.get_rbl_bitline_names(port)
temp.extend(rbl_bl_names)
for col in range(self.num_cols + self.num_spare_cols):
temp.append("{0}_{1}".format(self.bl_names[port], col))
temp.append("{0}_{1}".format(self.br_names[port], col))
temp.extend(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)])
temp.extend(self.bitcell_array.get_bitline_names(port))
if port in self.read_ports:
for bit in range(self.word_size + self.num_spare_cols):
temp.append("dout{0}_{1}".format(port, bit))
@ -479,8 +470,7 @@ class bank(design.design):
for bit in range(self.row_addr_size):
temp.append("addr{0}_{1}".format(port, bit + self.col_addr_size))
temp.append("wl_en{}".format(port))
for row in range(self.num_rows):
temp.append("{0}_{1}".format(self.wl_names[port], row))
temp.extend(self.bitcell_array.get_wordline_names(port))
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
@ -698,27 +688,28 @@ class bank(design.design):
# Connect the regular bitlines
inst2 = self.port_data_inst[port]
inst1 = self.bitcell_array_inst
inst1_bl_name = self.bl_names[port] + "_{}"
inst1_br_name = self.br_names[port] + "_{}"
inst1_bl_name = [x for x in self.bitcell_array.get_bitline_names(port) if "bl" in x]
inst1_br_name = [x for x in self.bitcell_array.get_bitline_names(port) if "br" in x]
inst2_bl_name = []
inst2_br_name = []
for col in range(self.num_cols):
inst2_bl_name.append(inst2.mod.get_bl_names() + "_{}".format(col))
inst2_br_name.append(inst2.mod.get_br_names() + "_{}".format(col))
for col in range(self.num_spare_cols):
inst2_bl_name.append("spare" + inst2.mod.get_bl_names() + "_{}".format(col))
inst2_br_name.append("spare" + inst2.mod.get_br_names() + "_{}".format(col))
inst2_bl_name = inst2.mod.get_bl_names() + "_{}"
inst2_br_name = inst2.mod.get_br_names() + "_{}"
self.connect_bitlines(inst1=inst1,
inst2=inst2,
num_bits=self.num_cols,
inst1_bl_name=inst1_bl_name,
inst1_br_name=inst1_br_name,
inst2_bl_name=inst2_bl_name,
inst2_br_name=inst2_br_name)
# connect spare bitlines
for i in range(self.num_spare_cols):
self.connect_bitline(inst1, inst2, inst1_bl_name.format(self.num_cols + i), "spare" + inst2_bl_name.format(i))
self.connect_bitline(inst1, inst2, inst1_br_name.format(self.num_cols + i), "spare" + inst2_br_name.format(i))
# Connect the replica bitlines
rbl_bl_names = self.bitcell_array.get_rbl_bitline_names(port)
rbl_bl_names = self.bitcell_array.get_rbl_bitline_names(port)[2 * port: 2 * port + 2]
for (array_name, data_name) in zip(rbl_bl_names, ["rbl_bl", "rbl_br"]):
self.connect_bitline(inst1, inst2, array_name, data_name)
@ -817,16 +808,16 @@ class bank(design.design):
vector(top_loc.x, yoffset),
top_loc])
def connect_bitlines(self, inst1, inst2, num_bits,
def connect_bitlines(self, inst1, inst2,
inst1_bl_name, inst1_br_name,
inst2_bl_name, inst2_br_name):
"""
Connect the bl and br of two modules.
"""
for col in range(num_bits):
self.connect_bitline(inst1, inst2, inst1_bl_name.format(col), inst2_bl_name.format(col))
self.connect_bitline(inst1, inst2, inst1_br_name.format(col), inst2_br_name.format(col))
for (name1, name2) in zip(inst1_bl_name, inst2_bl_name):
self.connect_bitline(inst1, inst2, name1, name2)
for (name1, name2) in zip(inst1_br_name, inst2_br_name):
self.connect_bitline(inst1, inst2, name1, name2)
def route_port_address(self, port):
""" Connect Wordline driver to bitcell array wordline """
@ -841,11 +832,12 @@ class bank(design.design):
def route_port_address_left(self, port):
""" Connecting Wordline driver output to Bitcell WL connection """
for row in range(self.num_rows):
driver_names = ["wl_{}".format(x) for x in range(self.num_rows)]
for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port)):
# The mid guarantees we exit the input cell to the right.
driver_wl_pin = self.port_address_inst[port].get_pin("wl_{}".format(row))
driver_wl_pin = self.port_address_inst[port].get_pin(driver_name)
driver_wl_pos = driver_wl_pin.rc()
bitcell_wl_pin = self.bitcell_array_inst.get_pin(self.wl_names[port] + "_{}".format(row))
bitcell_wl_pin = self.bitcell_array_inst.get_pin(array_name)
bitcell_wl_pos = bitcell_wl_pin.lc()
mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * self.port_address_inst[port].rx() + 0.5 * self.bitcell_array_inst.lx(), 0)
mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0.5, 1)
@ -858,11 +850,12 @@ class bank(design.design):
def route_port_address_right(self, port):
""" Connecting Wordline driver output to Bitcell WL connection """
for row in range(self.num_rows):
driver_names = ["wl_{}".format(x) for x in range(self.num_rows)]
for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port)):
# The mid guarantees we exit the input cell to the right.
driver_wl_pin = self.port_address_inst[port].get_pin("wl_{}".format(row))
driver_wl_pin = self.port_address_inst[port].get_pin(driver_name)
driver_wl_pos = driver_wl_pin.lc()
bitcell_wl_pin = self.bitcell_array_inst.get_pin(self.wl_names[port] + "_{}".format(row))
bitcell_wl_pin = self.bitcell_array_inst.get_pin(array_name)
bitcell_wl_pos = bitcell_wl_pin.rc()
mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * self.port_address_inst[port].lx() + 0.5 * self.bitcell_array_inst.rx(), 0)
mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0, 1)
@ -923,26 +916,29 @@ class bank(design.design):
These should probably be turned off by default though, since extraction
will show these as ports in the extracted netlist.
"""
for pin_name in self.bitcell_array.get_all_bitline_names():
self.copy_layout_pin(self.bitcell_array, pin_name)
# Add the wordline names
for i in range(self.num_rows):
wl_name = "wl_{}".format(i)
wl_pin = self.bitcell_array_inst.get_pin(wl_name)
self.add_label(text=wl_name,
layer="m1",
offset=wl_pin.center())
# for i in range(self.num_rows):
# wl_name = "wl_{}".format(i)
# wl_pin = self.bitcell_array_inst.get_pin(wl_name)
# self.add_label(text=wl_name,
# layer="m1",
# offset=wl_pin.center())
# Add the bitline names
for i in range(self.num_cols):
bl_name = "bl_{}".format(i)
br_name = "br_{}".format(i)
bl_pin = self.bitcell_array_inst.get_pin(bl_name)
br_pin = self.bitcell_array_inst.get_pin(br_name)
self.add_label(text=bl_name,
layer="m2",
offset=bl_pin.center())
self.add_label(text=br_name,
layer="m2",
offset=br_pin.center())
# # Add the bitline names
# for i in range(self.num_cols):
# bl_name = "bl_{}".format(i)
# br_name = "br_{}".format(i)
# bl_pin = self.bitcell_array_inst.get_pin(bl_name)
# br_pin = self.bitcell_array_inst.get_pin(br_name)
# self.add_label(text=bl_name,
# layer="m2",
# offset=bl_pin.center())
# self.add_label(text=br_name,
# layer="m2",
# offset=br_pin.center())
# # Add the data output names to the sense amp output
# for i in range(self.word_size):
@ -953,24 +949,27 @@ class bank(design.design):
# offset=data_pin.center())
# Add labels on the decoder
for port in self.write_ports:
for i in range(self.word_size):
data_name = "dec_out_{}".format(i)
pin_name = "in_{}".format(i)
data_pin = self.wordline_driver_inst[port].get_pin(pin_name)
self.add_label(text=data_name,
layer="m1",
offset=data_pin.center())
# for port in self.write_ports:
# for i in range(self.word_size):
# data_name = "dec_out_{}".format(i)
# pin_name = "in_{}".format(i)
# data_pin = self.wordline_driver_inst[port].get_pin(pin_name)
# self.add_label(text=data_name,
# layer="m1",
# offset=data_pin.center())
def route_unused_wordlines(self):
""" Connect the unused RBL and dummy wordlines to gnd """
gnd_wl_names = []
# Connect unused RBL WL to gnd
array_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("rbl")])
dummy_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("dummy")])
rbl_wl_names = set([self.bitcell_array.get_rbl_wordline_names(x) for x in self.all_ports])
# All RBL WL names
array_rbl_names = set(self.bitcell_array.get_rbl_wordline_names())
dummy_rbl_names = set(self.bitcell_array.get_dummy_wordline_names())
# List of used RBL WL names
rbl_wl_names = set()
for port in self.all_ports:
rbl_wl_names.add(self.bitcell_array.get_rbl_wordline_names(port)[port])
gnd_wl_names = list((array_rbl_names - rbl_wl_names) | dummy_rbl_names)
for wl_name in gnd_wl_names:
@ -1003,7 +1002,7 @@ class bank(design.design):
rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)
connection.append((self.prefix + "wl_en{}".format(port),
self.bitcell_array_inst.get_pin(rbl_wl_name)))
self.bitcell_array_inst.get_pin(rbl_wl_name[port])))
if port in self.write_ports:
connection.append((self.prefix + "w_en{}".format(port),

View File

@ -31,32 +31,43 @@ class bitcell_base_array(design.design):
self.create_all_wordline_names()
def get_all_bitline_names(self, prefix=""):
return [prefix + x for x in self.bitline_names]
return [prefix + x for x in self.all_bitline_names]
def create_all_bitline_names(self):
self.bitline_names = list()
bitline_names = self.cell.get_all_bitline_names()
self.bitline_names = [[] for port in self.all_ports]
for col in range(self.column_size):
for cell_column in bitline_names:
self.bitline_names.append("{0}_{1}".format(cell_column, col))
for port in self.all_ports:
self.bitline_names[port].extend(["bl_{0}_{1}".format(port, col),
"br_{0}_{1}".format(port, col)])
# Make a flat list too
self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl]
def get_all_wordline_names(self, prefix=""):
return [prefix + x for x in self.wordline_names]
return [prefix + x for x in self.all_wordline_names]
def create_all_wordline_names(self):
self.wordline_names = list()
wordline_names = self.cell.get_all_wl_names()
self.wordline_names = [[] for port in self.all_ports]
for row in range(self.row_size):
for cell_row in wordline_names:
self.wordline_names.append("{0}_{1}".format(cell_row, row))
for port in self.all_ports:
self.wordline_names[port].append("wl_{0}_{1}".format(port, row))
self.all_wordline_names = [x for sl in zip(*self.wordline_names) for x in sl]
def get_bitline_names(self, port=None):
if port == None:
return self.all_bitline_names
else:
return self.bitline_names[port]
def get_wordline_names(self, port=None):
if port == None:
return self.all_wordline_names
else:
return self.wordline_names[port]
def add_pins(self):
for bl_name in self.bitline_names:
for bl_name in self.get_bitline_names():
self.add_pin(bl_name, "INOUT")
for wl_name in self.wordline_names:
for wl_name in self.get_wordline_names():
self.add_pin(wl_name, "INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
@ -64,12 +75,10 @@ class bitcell_base_array(design.design):
def get_bitcell_pins(self, row, col):
""" Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array """
bitcell_pins = []
# bitlines
bitcell_pins.extend([x for x in self.bitline_names if x.endswith("_{0}".format(col))])
# wordlines
bitcell_pins.extend([x for x in self.wordline_names if x.endswith("_{0}".format(row))])
for port in self.all_ports:
bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))])
bitcell_pins.extend([x for x in self.all_wordline_names if x.endswith("_{0}".format(row))])
bitcell_pins.append("vdd")
bitcell_pins.append("gnd")
@ -80,19 +89,25 @@ class bitcell_base_array(design.design):
bitline_names = self.cell.get_all_bitline_names()
for col in range(self.column_size):
for bl_name in bitline_names:
bl_pin = self.cell_inst[0, col].get_pin(bl_name)
self.add_layout_pin(text="{0}_{1}".format(bl_name, col),
for port in self.all_ports:
bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port])
self.add_layout_pin(text="bl_{0}_{1}".format(port, col),
layer=bl_pin.layer,
offset=bl_pin.ll().scale(1, 0),
width=bl_pin.width(),
height=self.height)
br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1])
self.add_layout_pin(text="br_{0}_{1}".format(port, col),
layer=br_pin.layer,
offset=br_pin.ll().scale(1, 0),
width=br_pin.width(),
height=self.height)
wl_names = self.cell.get_all_wl_names()
for row in range(self.row_size):
for wl_name in wl_names:
wl_pin = self.cell_inst[row, 0].get_pin(wl_name)
self.add_layout_pin(text="{0}_{1}".format(wl_name, row),
for port in self.all_ports:
wl_pin = self.cell_inst[row, 0].get_pin(wl_names[port])
self.add_layout_pin(text="wl_{0}_{1}".format(port, row),
layer=wl_pin.layer,
offset=wl_pin.ll().scale(0, 1),
width=self.width,

View File

@ -5,27 +5,35 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from bitcell_base_array import bitcell_base_array
from tech import drc, spice
import design
from globals import OPTS
from sram_factory import factory
from vector import vector
import debug
class global_bitcell_array(bitcell_base_array):
"""
Creates a global bitcell array with a number
of local arrays of a sizes given by a tuple in the list.
"""
def __init__(self, sizes, name=""):
# Each bank will have the same number of rows
self.rows = sizes[0][0]
for (r, c) in sizes:
debug.check(r[0] == self.rows, "Cannot have non-uniform number of rows in global array.")
# The total of all columns will be the number of columns
self.cols = sum(x[1] for x in sizes)
self.sizes = sizes
super().__init__(rows=self.rows, cols=self.cols, name=name)
class global_bitcell_array(design.design):
"""
Creates a global bitcell array.
Rows is an integer number for all local arrays.
Cols is a list of the array widths.
add_left_rbl and add_right_
"""
def __init__(self, rows, cols, ports, name=""):
# The total of all columns will be the number of columns
super().__init__(name=name)
self.cols = cols
self.rows = rows
self.all_ports = ports
debug.check(len(ports)<=2, "Only support dual port or less in global bitcell array.")
self.rbl = [1, 1 if len(self.all_ports)>1 else 0]
self.left_rbl = self.rbl[0]
self.right_rbl = self.rbl[1]
# Just used for pin names
self.cell = factory.create(module_type="bitcell")
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@ -49,18 +57,92 @@ class global_bitcell_array(bitcell_base_array):
def add_modules(self):
""" Add the modules used in this design """
self.local_mods = []
for (row, col) in self.sizes:
la = factory.create(module_type="local_bitcell_array", rows=row, cols=col)
for i, cols in enumerate(self.cols):
# Always add the left RBLs to the first subarray and the right RBLs to the last subarray
if i == 0:
la = factory.create(module_type="local_bitcell_array", rows=self.rows, cols=cols, rbl=self.rbl, add_rbl=[self.left_rbl, 0])
elif i == len(self.cols) - 1:
la = factory.create(module_type="local_bitcell_array", rows=self.rows, cols=cols, rbl=self.rbl, add_rbl=[0, self.right_rbl])
else:
la = factory.create(module_type="local_bitcell_array", rows=self.rows, cols=cols, rbl=self.rbl, add_rbl=[0, 0])
self.add_mod(la)
self.local_mods.append(la)
def add_pins(self):
return
self.add_bitline_pins()
self.add_wordline_pins()
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def add_bitline_pins(self):
for port in self.all_ports:
self.add_pin_list(self.replica_bitline_names[port], "INOUT")
self.add_pin_list(self.bitline_names, "INOUT")
def add_wordline_pins(self):
# All wordline names for all ports
self.wordline_names = []
# Wordline names for each port
self.wordline_names_by_port = [[] for x in self.all_ports]
# Replica wordlines by port
self.replica_wordline_names = [[] for x in self.all_ports]
# Regular array wordline names
self.bitcell_array_wordline_names = self.bitcell_array.get_all_wordline_names()
self.wordline_names = []
# Left port WLs
for port in range(self.left_rbl):
# Make names for all RBLs
wl_names=["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()]
# Keep track of the pin that is the RBL
self.replica_wordline_names[port] = wl_names
self.wordline_names.extend(wl_names)
# Regular WLs
self.wordline_names.extend(self.bitcell_array_wordline_names)
# Right port WLs
for port in range(self.left_rbl, self.left_rbl + self.right_rbl):
# Make names for all RBLs
wl_names=["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()]
# Keep track of the pin that is the RBL
self.replica_wordline_names[port] = wl_names
self.wordline_names.extend(wl_names)
# Array of all port wl names
for port in range(self.left_rbl + self.right_rbl):
wl_names = ["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()]
self.replica_wordline_names[port] = wl_names
self.add_pin_list(self.wordline_names, "INPUT")
def create_instances(self):
""" Create the module instances used in this design """
self.local_inst = {}
for i in range(self.sizes):
name = "local_array_{0}".format(i)
self.local_inst.append(self.add_inst(name=name,
mod=self.local_mods[i])
self.connect_inst(self.get_bitcell_pins(row, col))
self.local_insts = []
for i, mod in enumerate(self.local_mods):
name = "la_{0}".format(i)
self.local_insts.append(self.add_inst(name=name,
mod=mod))
self.connect_inst(mod.pins)
def place(self):
offset = vector(0, 0)
for inst in self.local_insts:
inst.place(offset)
offset = inst.rx() + 3 * self.m3_pitch
self.height = self.local_mods[0].height
self.width = self.local_insts[-1].rx()
def add_layout_pins(self):
pass

View File

@ -5,28 +5,31 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import bitcell_base_array
import design
from globals import OPTS
from sram_factory import factory
from vector import vector
from tech import drc
import debug
class local_bitcell_array(bitcell_base_array.bitcell_base_array):
class local_bitcell_array(design.design):
"""
A local bitcell array is a bitcell array with a wordline driver.
This can either be a single aray on its own if there is no hierarchical WL
or it can be combined into a larger array with hierarchical WL.
"""
def __init__(self, rows, cols, ports, left_rbl=0, right_rbl=0, add_replica=True, name=""):
super().__init__(name, rows, cols, 0)
debug.info(2, "create local array of size {} rows x {} cols words".format(rows,
cols + left_rbl + right_rbl))
def __init__(self, rows, cols, rbl, add_rbl=None, name=""):
super().__init__(name=name)
debug.info(2, "create local array of size {} rows x {} cols words".format(rows, cols))
self.rows = rows
self.cols = cols
self.add_replica=add_replica
self.all_ports = ports
self.rbl = rbl
if add_rbl == None:
self.add_rbl = rbl
else:
self.add_rbl = add_rbl
debug.check(len(self.all_ports) < 3, "Local bitcell array only supports dual port or less.")
self.create_netlist()
if not OPTS.netlist_only:
@ -62,67 +65,93 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
self.bitcell_array = factory.create(module_type="replica_bitcell_array",
cols=self.cols,
rows=self.rows,
left_rbl=1,
right_rbl=1 if len(self.all_ports)>1 else 0,
bitcell_ports=self.all_ports,
add_replica=self.add_replica)
rbl=self.rbl,
add_rbl=self.add_rbl)
self.add_mod(self.bitcell_array)
self.wl_array = factory.create(module_type="wordline_buffer_array",
rows=self.rows + len(self.all_ports),
rows=self.rows + 1,
cols=self.cols)
self.add_mod(self.wl_array)
def add_pins(self):
self.bitline_names = self.bitcell_array.get_all_bitline_names()
self.add_pin_list(self.bitline_names, "INOUT")
self.driver_wordline_inputs = [x for x in self.bitcell_array.get_all_wordline_names() if not x.startswith("dummy")]
self.driver_wordline_outputs = [x + "i" for x in self.driver_wordline_inputs]
self.array_wordline_inputs = [x + "i" if not x.startswith("dummy") else "gnd" for x in self.bitcell_array.get_all_wordline_names()]
self.add_pin_list(self.wordline_names, "INPUT")
self.replica_names = self.bitcell_array.get_rbl_wordline_names()
self.add_pin_list(self.replica_names, "INPUT")
self.bitline_names = self.bitcell_array.get_inouts()
# Inputs to the wordline driver (by port)
self.wordline_names = []
# Outputs from the wordline driver (by port)
self.driver_wordline_outputs = []
# Inputs to the bitcell array (by port)
self.array_wordline_inputs = []
for port in self.all_ports:
wordline_inputs = []
if port == 0:
wordline_inputs += [self.bitcell_array.get_rbl_wordline_names(0)[0]]
wordline_inputs += self.bitcell_array.get_wordline_names(port)
if port == 1:
wordline_inputs += [self.bitcell_array.get_rbl_wordline_names(1)[1]]
self.wordline_names.append(wordline_inputs)
self.driver_wordline_outputs.append([x + "i" for x in self.wordline_names[-1]])
self.gnd_wl_names = []
# Connect unused RBL WL to gnd
array_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("rbl")])
dummy_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("dummy")])
rbl_wl_names = set([x for rbl_port_names in self.wordline_names for x in rbl_port_names if x.startswith("rbl")])
self.gnd_wl_names = list((array_rbl_names - rbl_wl_names) | dummy_rbl_names)
self.all_array_wordline_inputs = [x + "i" if x not in self.gnd_wl_names else "gnd" for x in self.bitcell_array.get_all_wordline_names()]
self.bitline_names = self.bitcell_array.bitline_names
self.all_array_bitline_names = self.bitcell_array.get_all_bitline_names()
# Arrays are always:
# bit lines (left to right)
# word lines (bottom to top)
# vdd
# gnd
self.add_pin_list([x for x in self.all_array_bitline_names if not x.startswith("dummy")], "INOUT")
for port in self.all_ports:
self.add_pin_list(self.wordline_names[port], "INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def create_instances(self):
""" Create the module instances used in this design """
self.wl_inst = self.add_inst(name="wl_driver",
mod=self.wl_array)
self.connect_inst(self.driver_wordline_inputs + self.driver_wordline_outputs + ["vdd", "gnd"])
self.wl_insts = []
for port in self.all_ports:
self.wl_insts.append(self.add_inst(name="wl_driver",
mod=self.wl_array))
self.connect_inst(self.wordline_names[port] + self.driver_wordline_outputs[port] + ["vdd", "gnd"])
self.bitcell_array_inst = self.add_inst(name="array",
mod=self.bitcell_array,
offset=self.wl_inst.lr())
self.connect_inst(self.bitline_names + self.array_wordline_inputs + ["vdd", "gnd"])
mod=self.bitcell_array)
self.connect_inst(self.all_array_bitline_names + self.all_array_wordline_inputs + ["vdd", "gnd"])
def place(self):
""" Place the bitcelll array to the right of the wl driver. """
self.wl_inst.place(vector(0, self.cell.height))
# FIXME: Replace this with a tech specific paramter
driver_to_array_spacing = 3 * self.m3_pitch
self.bitcell_array_inst.place(vector(self.wl_inst.rx() + driver_to_array_spacing,
self.wl_insts[0].place(vector(0, self.cell.height))
self.bitcell_array_inst.place(vector(self.wl_insts[0].rx() + driver_to_array_spacing,
0))
if len(self.all_ports) > 1:
self.wl_insts[1].place(vector(self.bitcell_array_inst.rx() + self.wl_array.width + driver_to_array_spacing,
2 * self.cell.height),
mirror="MY")
self.height = self.bitcell_array.height
self.width = self.bitcell_array_inst.rx()
def route_unused_wordlines(self):
""" Connect the unused RBL and dummy wordlines to gnd """
gnd_wl_names = []
# Connect unused RBL WL to gnd
array_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("rbl")])
dummy_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("dummy")])
rbl_wl_names = set([self.bitcell_array.get_rbl_wordline_names(x) for x in self.all_ports])
gnd_wl_names = list((array_rbl_names - rbl_wl_names) | dummy_rbl_names)
for wl_name in gnd_wl_names:
for wl_name in self.gnd_wl_names:
pin = self.bitcell_array_inst.get_pin(wl_name)
pin_layer = pin.layer
layer_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer))
@ -141,13 +170,14 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
def add_layout_pins(self):
for (x, y) in zip(self.bitline_names, self.bitcell_array.get_inouts()):
self.copy_layout_pin(self.bitcell_array_inst, y, x)
for x in self.get_inouts():
self.copy_layout_pin(self.bitcell_array_inst, x)
for port in self.all_ports:
for (x, y) in zip(self.wordline_names[port], self.wl_array.get_inputs()):
self.copy_layout_pin(self.wl_insts[port], y, x)
for (x, y) in zip(self.driver_wordline_inputs, self.wl_array.get_inputs()):
self.copy_layout_pin(self.wl_inst, y, x)
supply_insts = [self.wl_inst, self.bitcell_array_inst]
supply_insts = [*self.wl_insts, self.bitcell_array_inst]
for pin_name in ["vdd", "gnd"]:
for inst in supply_insts:
pin_list = inst.get_pins(pin_name)
@ -157,12 +187,21 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
start_layer=pin.layer)
def route(self):
array_names = [x for x in self.bitcell_array.get_all_wordline_names() if not x.startswith("dummy")]
for (driver_name, array_name) in zip(self.wl_array.get_outputs(), array_names):
out_pin = self.wl_inst.get_pin(driver_name)
in_pin = self.bitcell_array_inst.get_pin(array_name)
mid_loc = self.wl_inst.rx() + 1.5 * self.m3_pitch
self.add_path(out_pin.layer, [out_pin.rc(), vector(mid_loc, out_pin.cy()), in_pin.lc()])
for port in self.all_ports:
for (driver_name, net_name) in zip(self.wl_insts[port].mod.get_outputs(), self.driver_wordline_outputs[port]):
array_name = net_name[:-1]
out_pin = self.wl_insts[port].get_pin(driver_name)
in_pin = self.bitcell_array_inst.get_pin(array_name)
if port == 0:
out_loc = out_pin.rc()
mid_loc = vector(self.wl_insts[port].rx() + 1.5 * self.m3_pitch, out_loc.y)
in_loc = in_pin.lc()
else:
out_loc = out_pin.lc()
mid_loc = vector(self.wl_insts[port].lx() - 1.5 * self.m3_pitch, out_loc.y)
in_loc = in_pin.rc()
self.add_path(out_pin.layer, [out_loc, mid_loc, in_loc])
self.route_unused_wordlines()

View File

@ -53,18 +53,10 @@ class port_data(design.design):
return self.precharge.get_br_names()
def get_bl_name(self, port=0):
bl_name = "bl"
if len(self.all_ports) == 1:
return bl_name
else:
return bl_name + "{}".format(port)
return "bl_{}".format(port)
def get_br_name(self, port=0):
br_name = "br"
if len(self.all_ports) == 1:
return br_name
else:
return br_name + "{}".format(port)
return "br_{}".format(port)
def create_netlist(self):
self.precompute_constants()
@ -110,15 +102,11 @@ class port_data(design.design):
self.add_pin("rbl_bl", "INOUT")
self.add_pin("rbl_br", "INOUT")
for bit in range(self.num_cols):
bl_name = self.get_bl_name(self.port)
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")
self.add_pin("bl_{0}".format(bit), "INOUT")
self.add_pin("br_{0}".format(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")
self.add_pin("sparebl_{0}".format(bit), "INOUT")
self.add_pin("sparebr_{0}".format(bit), "INOUT")
if self.port in self.read_ports:
for bit in range(self.word_size + self.num_spare_cols):
@ -274,21 +262,18 @@ class port_data(design.design):
self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port),
mod=self.precharge_array)
bl_name = self.get_bl_name(self.port)
br_name = self.get_br_name(self.port)
temp = []
# Use left BLs for RBL
if self.port==0:
temp.append("rbl_bl")
temp.append("rbl_br")
for bit in range(self.num_cols):
temp.append("{0}_{1}".format(bl_name, bit))
temp.append("{0}_{1}".format(br_name, bit))
temp.append("bl_{0}".format(bit))
temp.append("br_{0}".format(bit))
for bit in range(self.num_spare_cols):
temp.append("spare{0}_{1}".format(bl_name, bit))
temp.append("spare{0}_{1}".format(br_name, bit))
temp.append("sparebl_{0}".format(bit))
temp.append("sparebr_{0}".format(bit))
# Use right BLs for RBL
if self.port==1:
@ -308,17 +293,15 @@ class port_data(design.design):
self.column_mux_array_inst = self.add_inst(name="column_mux_array{}".format(self.port),
mod=self.column_mux_array)
bl_name = self.get_bl_name(self.port)
br_name = self.get_br_name(self.port)
temp = []
for col in range(self.num_cols):
temp.append("{0}_{1}".format(bl_name, col))
temp.append("{0}_{1}".format(br_name, col))
temp.append("bl_{0}".format(col))
temp.append("br_{0}".format(col))
for word in range(self.words_per_row):
temp.append("sel_{}".format(word))
for bit in range(self.word_size):
temp.append("{0}_out_{1}".format(bl_name, bit))
temp.append("{0}_out_{1}".format(br_name, bit))
temp.append("bl_out_{0}".format(bit))
temp.append("br_out_{0}".format(bit))
temp.append("gnd")
self.connect_inst(temp)
@ -335,22 +318,20 @@ class port_data(design.design):
self.sense_amp_array_inst = self.add_inst(name="sense_amp_array{}".format(self.port),
mod=self.sense_amp_array)
bl_name = self.get_bl_name(self.port)
br_name = self.get_br_name(self.port)
temp = []
for bit in range(self.word_size):
temp.append("dout_{}".format(bit))
if self.words_per_row == 1:
temp.append("{0}_{1}".format(bl_name, bit))
temp.append("{0}_{1}".format(br_name, bit))
temp.append("bl_{0}".format(bit))
temp.append("br_{0}".format(bit))
else:
temp.append("{0}_out_{1}".format(bl_name, bit))
temp.append("{0}_out_{1}".format(br_name, bit))
temp.append("bl_out_{0}".format(bit))
temp.append("br_out_{0}".format(bit))
for bit in range(self.num_spare_cols):
temp.append("dout_{}".format(self.word_size + bit))
temp.append("spare{0}_{1}".format(bl_name, bit))
temp.append("spare{0}_{1}".format(br_name, bit))
temp.append("sparebl_{0}".format(bit))
temp.append("sparebr_{0}".format(bit))
temp.append("s_en")
temp.extend(["vdd", "gnd"])
@ -364,24 +345,21 @@ class port_data(design.design):
""" Creating Write Driver """
self.write_driver_array_inst = self.add_inst(name="write_driver_array{}".format(self.port),
mod=self.write_driver_array)
bl_name = self.get_bl_name(self.port)
br_name = self.get_br_name(self.port)
temp = []
for bit in range(self.word_size + self.num_spare_cols):
temp.append("din_{}".format(bit))
for bit in range(self.word_size):
if (self.words_per_row == 1):
temp.append("{0}_{1}".format(bl_name, bit))
temp.append("{0}_{1}".format(br_name, bit))
temp.append("bl_{0}".format(bit))
temp.append("br_{0}".format(bit))
else:
temp.append("{0}_out_{1}".format(bl_name, bit))
temp.append("{0}_out_{1}".format(br_name, bit))
temp.append("bl_out_{0}".format(bit))
temp.append("br_out_{0}".format(bit))
for bit in range(self.num_spare_cols):
temp.append("spare{0}_{1}".format(bl_name, bit))
temp.append("spare{0}_{1}".format(br_name, bit))
temp.append("sparebl_{0}".format(bit))
temp.append("sparebr_{0}".format(bit))
if self.write_size is not None:
for i in range(self.num_wmasks):
@ -729,7 +707,7 @@ class port_data(design.design):
# Add spare columns' en_{} pins
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")
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), "bank_spare_wen{}".format(bit))
else:

View File

@ -21,34 +21,33 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
Requires a regular bitcell array, replica bitcell, and dummy
bitcell (Bl/BR disconnected).
"""
def __init__(self, rows, cols, left_rbl, right_rbl, bitcell_ports, name, add_replica=True):
def __init__(self, rows, cols, rbl, name, add_rbl=None):
super().__init__(name, rows, cols, column_offset=0)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.column_size = cols
self.row_size = rows
self.left_rbl = left_rbl
self.right_rbl = right_rbl
self.bitcell_ports = bitcell_ports
# If set to false, we increase the height for the replica wordline row, but don't
# actually add the column to this array. This is so the height matches other
# banks that have the replica columns.
# Number of replica columns to actually add
if add_replica:
self.add_left_rbl = self.left_rbl
self.add_right_rbl = self.right_rbl
# This is how many RBLs are in all the arrays
self.rbl = rbl
self.left_rbl = rbl[0]
self.right_rbl = rbl[1]
# This is how many RBLs are added to THIS array
if add_rbl == None:
self.add_left_rbl = rbl[0]
self.add_right_rbl = rbl[1]
else:
self.add_left_rbl = 0
self.add_right_rbl = 0
self.add_left_rbl = add_rbl[0]
self.add_right_rbl = add_rbl[1]
for a, b in zip(add_rbl, rbl):
debug.check(a <= b,
"Invalid number of RBLs for port configuration.")
debug.check(left_rbl + right_rbl <= len(self.all_ports),
debug.check(sum(rbl) <= len(self.all_ports),
"Invalid number of RBLs for port configuration.")
debug.check(left_rbl + right_rbl <= len(self.bitcell_ports),
"Bitcell ports must match total RBLs.")
# Two dummy rows plus replica even if we don't add the column
self.extra_rows = 2 + self.left_rbl + self.right_rbl
self.extra_rows = 2 + sum(rbl)
# Two dummy cols plus replica if we add the column
self.extra_cols = 2 + self.add_left_rbl + self.add_right_rbl
@ -59,7 +58,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
# We don't offset this because we need to align
# the replica bitcell in the control logic
# self.offset_all_coordinates()
def create_netlist(self):
""" Create and connect the netlist """
self.add_modules()
@ -112,8 +111,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
column_offset = self.left_rbl + 1
self.replica_columns[bit] = factory.create(module_type="replica_column",
rows=self.row_size,
left_rbl=self.add_left_rbl,
right_rbl=self.add_right_rbl,
rbl=self.rbl,
column_offset=column_offset,
replica_bit=replica_bit)
self.add_mod(self.replica_columns[bit])
@ -166,102 +164,104 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
def add_pins(self):
# Arrays are always:
# bitlines (column first then port order)
# word lines (row first then port order)
# dummy wordlines
# replica wordlines
# regular wordlines (bottom to top)
# # dummy bitlines
# replica bitlines (port order)
# regular bitlines (left to right port order)
#
# vdd
# gnd
self.add_bitline_pins()
self.add_wordline_pins()
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def add_bitline_pins(self):
# Regular bitline names for all ports
# Regular bitline names by port
self.bitline_names = []
# Bitline names for each port
self.bitline_names_by_port = [[] for x in self.all_ports]
# Replica wordlines by port
self.replica_bitline_names = [[] for x in self.all_ports]
# Replica wordlines by port (bl only)
self.replica_bl_names = [[] for x in self.all_ports]
# Dummy wordlines by port
self.dummy_bitline_names = []
# Replica bitlines by port
self.rbl_bitline_names = []
# Dummy bitlines by left/right
self.dummy_col_bitline_names = []
# Regular array bitline names
self.bitcell_array_bitline_names = self.bitcell_array.get_all_bitline_names()
for loc in ["left", "right"]:
self.dummy_col_bitline_names.append([])
for port in self.all_ports:
bitline_names = ["dummy_{0}_{1}".format(x, loc) for x in self.row_cap_left.get_bitline_names(port)]
self.dummy_col_bitline_names[-1].extend(bitline_names)
self.all_dummy_col_bitline_names = [x for sl in self.dummy_col_bitline_names for x in sl]
# These are the non-indexed names
dummy_bitline_names = ["dummy_" + x for x in self.cell.get_all_bitline_names()]
self.dummy_bitline_names.append([x + "_left" for x in dummy_bitline_names])
self.dummy_bitline_names.append([x + "_right" for x in dummy_bitline_names])
# Array of all port bitline names
for port in range(self.add_left_rbl + self.add_right_rbl):
left_names=["rbl_{0}_{1}".format(self.cell.get_bl_name(x), port) for x in range(len(self.all_ports))]
right_names=["rbl_{0}_{1}".format(self.cell.get_br_name(x), port) for x in range(len(self.all_ports))]
# Keep track of the left pins that are the RBL
self.replica_bl_names[port]=left_names[self.bitcell_ports[port]]
# Interleave the left and right lists
left_names=["rbl_bl_{0}_{1}".format(x, port) for x in self.all_ports]
right_names=["rbl_br_{0}_{1}".format(x, port) for x in self.all_ports]
bitline_names = [x for t in zip(left_names, right_names) for x in t]
self.replica_bitline_names[port] = bitline_names
# Dummy bitlines are not connected to anything
self.bitline_names.extend(self.bitcell_array_bitline_names)
self.rbl_bitline_names.append(bitline_names)
# Make a flat list too
self.all_rbl_bitline_names = [x for sl in self.rbl_bitline_names for x in sl]
for port in self.all_ports:
self.add_pin_list(self.replica_bitline_names[port], "INOUT")
self.add_pin_list(self.bitline_names, "INOUT")
bitline_names = self.bitcell_array.get_bitline_names(port)
self.bitline_names.append(bitline_names)
# Make a flat list too
self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl]
self.add_pin_list(self.dummy_col_bitline_names[0], "INOUT")
for port in range(self.add_left_rbl):
self.add_pin_list(self.rbl_bitline_names[port], "INOUT")
self.add_pin_list(self.all_bitline_names, "INOUT")
for port in range(self.add_left_rbl, self.add_left_rbl + self.add_right_rbl):
self.add_pin_list(self.rbl_bitline_names[port], "INOUT")
self.add_pin_list(self.dummy_col_bitline_names[1], "INOUT")
def add_wordline_pins(self):
# All wordline names for all ports
# Regular wordlines by port
self.wordline_names = []
# Wordline names for each port
self.wordline_names_by_port = [[] for x in self.all_ports]
# Replica wordlines by port
self.replica_wordline_names = [[] for x in self.all_ports]
# Dummy wordlines
self.dummy_wordline_names = {}
self.rbl_wordline_names = []
# Dummy wordlines by bot/top
self.dummy_row_wordline_names = []
# Regular array wordline names
self.bitcell_array_wordline_names = self.bitcell_array.get_all_wordline_names()
# These are the non-indexed names
dummy_cell_wl_names = ["dummy_" + x for x in self.cell.get_all_wl_names()]
# Create the full WL names include dummy, replica, and regular bit cells
self.wordline_names = []
self.dummy_wordline_names["bot"] = ["{0}_bot".format(x) for x in dummy_cell_wl_names]
self.wordline_names.extend(self.dummy_wordline_names["bot"])
# Left port WLs
for port in range(self.left_rbl):
# Make names for all RBLs
wl_names=["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()]
# Keep track of the pin that is the RBL
self.replica_wordline_names[port] = wl_names
self.wordline_names.extend(wl_names)
# Regular WLs
self.wordline_names.extend(self.bitcell_array_wordline_names)
# Right port WLs
for port in range(self.left_rbl, self.left_rbl + self.right_rbl):
# Make names for all RBLs
wl_names=["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()]
# Keep track of the pin that is the RBL
self.replica_wordline_names[port] = wl_names
self.wordline_names.extend(wl_names)
self.dummy_wordline_names["top"] = ["{0}_top".format(x) for x in dummy_cell_wl_names]
self.wordline_names.extend(self.dummy_wordline_names["top"])
dummy_row_wordline_names = ["dummy_" + x for x in self.col_cap.get_wordline_names()]
for loc in ["bot", "top"]:
wordline_names = ["{0}_{1}".format(wl_name, loc) for wl_name in dummy_row_wordline_names]
self.dummy_row_wordline_names.append(wordline_names)
self.all_dummy_row_wordline_names = [x for sl in self.dummy_row_wordline_names for x in sl]
# Array of all port wl names
for port in range(self.left_rbl + self.right_rbl):
wl_names = ["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()]
self.replica_wordline_names[port] = wl_names
wordline_names=["rbl_wl_{0}_{1}".format(x, port) for x in self.all_ports]
self.rbl_wordline_names.append(wordline_names)
self.all_rbl_wordline_names = [x for sl in self.rbl_wordline_names for x in sl]
for port in self.all_ports:
wordline_names = self.bitcell_array.get_wordline_names(port)
self.wordline_names.append(wordline_names)
self.all_wordline_names = [x for sl in zip(*self.wordline_names) for x in sl]
# All wordlines including dummy and RBL
self.replica_array_wordline_names = []
self.replica_array_wordline_names.extend(self.dummy_row_wordline_names[0])
for p in range(self.left_rbl):
self.replica_array_wordline_names.extend(self.rbl_wordline_names[p])
self.replica_array_wordline_names.extend(self.all_wordline_names)
for p in range(self.left_rbl, self.left_rbl + self.right_rbl):
self.replica_array_wordline_names.extend(self.rbl_wordline_names[p])
self.replica_array_wordline_names.extend(self.dummy_row_wordline_names[1])
self.add_pin_list(self.dummy_row_wordline_names[0], "INPUT")
for port in range(self.left_rbl):
self.add_pin_list(self.rbl_wordline_names[port], "INPUT")
self.add_pin_list(self.all_wordline_names, "INPUT")
for port in range(self.left_rbl, self.left_rbl + self.right_rbl):
self.add_pin_list(self.rbl_wordline_names[port], "INPUT")
self.add_pin_list(self.dummy_row_wordline_names[1], "INPUT")
self.add_pin_list(self.wordline_names, "INPUT")
def create_instances(self):
""" Create the module instances used in this design """
@ -273,42 +273,44 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
# Main array
self.bitcell_array_inst=self.add_inst(name="bitcell_array",
mod=self.bitcell_array)
self.connect_inst(self.bitcell_array_bitline_names + self.bitcell_array_wordline_names + supplies)
self.connect_inst(self.all_bitline_names + self.all_wordline_names + supplies)
# Replica columns
self.replica_col_inst = {}
self.replica_col_insts = []
for port in range(self.add_left_rbl + self.add_right_rbl):
self.replica_col_inst[port]=self.add_inst(name="replica_col_{}".format(port),
mod=self.replica_columns[port])
self.connect_inst(self.replica_bitline_names[port] + self.wordline_names + supplies)
self.replica_col_insts.append(self.add_inst(name="replica_col_{}".format(port),
mod=self.replica_columns[port]))
self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + supplies)
# Dummy rows under the bitcell array (connected with with the replica cell wl)
self.dummy_row_replica_inst = {}
self.dummy_row_replica_insts = []
# Note, this is the number of left and right even if we aren't adding the columns to this bitcell array!
for port in range(self.left_rbl + self.right_rbl):
self.dummy_row_replica_inst[port]=self.add_inst(name="dummy_row_{}".format(port),
mod=self.dummy_row)
self.connect_inst(self.bitcell_array_bitline_names + self.replica_wordline_names[port] + supplies)
self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port),
mod=self.dummy_row))
self.connect_inst(self.all_bitline_names + self.rbl_wordline_names[port] + supplies)
# Top/bottom dummy rows or col caps
self.dummy_row_bot_inst=self.add_inst(name="dummy_row_bot",
mod=self.col_cap)
self.connect_inst(self.bitcell_array_bitline_names
+ self.dummy_wordline_names["bot"]
self.dummy_row_insts = []
self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot",
mod=self.col_cap))
self.connect_inst(self.all_bitline_names
+ self.dummy_row_wordline_names[0]
+ supplies)
self.dummy_row_top_inst=self.add_inst(name="dummy_row_top",
mod=self.col_cap)
self.connect_inst(self.bitcell_array_bitline_names
+ self.dummy_wordline_names["top"]
self.dummy_row_insts.append(self.add_inst(name="dummy_row_top",
mod=self.col_cap))
self.connect_inst(self.all_bitline_names
+ self.dummy_row_wordline_names[1]
+ supplies)
# Left/right Dummy columns
self.dummy_col_left_inst=self.add_inst(name="dummy_col_left",
mod=self.row_cap_left)
self.connect_inst(self.dummy_bitline_names[0] + self.wordline_names + supplies)
self.dummy_col_right_inst=self.add_inst(name="dummy_col_right",
mod=self.row_cap_right)
self.connect_inst(self.dummy_bitline_names[-1] + self.wordline_names + supplies)
self.dummy_col_insts = []
self.dummy_col_insts.append(self.add_inst(name="dummy_col_left",
mod=self.row_cap_left))
self.connect_inst(self.dummy_col_bitline_names[0] + self.replica_array_wordline_names + supplies)
self.dummy_col_insts.append(self.add_inst(name="dummy_col_right",
mod=self.row_cap_right))
self.connect_inst(self.dummy_col_bitline_names[1] + self.replica_array_wordline_names + supplies)
def create_layout(self):
@ -340,22 +342,22 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
# Grow from left to right, toward the array
for bit in range(self.add_left_rbl):
offset = self.bitcell_offset.scale(-self.add_left_rbl + bit, -self.add_left_rbl - 1)
self.replica_col_inst[bit].place(offset)
offset = self.bitcell_offset.scale(-self.add_left_rbl + bit, -self.left_rbl - 1)
self.replica_col_insts[bit].place(offset)
# Grow to the right of the bitcell array, array outward
for bit in range(self.add_right_rbl):
offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.add_left_rbl - 1)
self.replica_col_inst[self.add_left_rbl + bit].place(offset)
offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.left_rbl - 1)
self.replica_col_insts[self.add_left_rbl + bit].place(offset)
# Replica dummy rows
# Add the dummy rows even if we aren't adding the replica column to this bitcell array
# These grow up, toward the array
for bit in range(self.left_rbl):
self.dummy_row_replica_inst[bit].place(offset=self.bitcell_offset.scale(0, -self.left_rbl + bit + (-self.left_rbl + bit) % 2),
self.dummy_row_replica_insts[bit].place(offset=self.bitcell_offset.scale(0, -self.left_rbl + bit + (-self.left_rbl + bit) % 2),
mirror="MX" if (-self.left_rbl + bit) % 2 else "R0")
# These grow up, away from the array
for bit in range(self.right_rbl):
self.dummy_row_replica_inst[self.left_rbl + bit].place(offset=self.bitcell_offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul(),
self.dummy_row_replica_insts[self.left_rbl + bit].place(offset=self.bitcell_offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul(),
mirror="MX" if bit % 2 else "R0")
def add_end_caps(self):
@ -365,54 +367,50 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
# Far top dummy row (first row above array is NOT flipped)
flip_dummy = self.right_rbl % 2
dummy_row_offset = self.bitcell_offset.scale(0, self.right_rbl + flip_dummy) + self.bitcell_array_inst.ul()
self.dummy_row_top_inst.place(offset=dummy_row_offset,
self.dummy_row_insts[1].place(offset=dummy_row_offset,
mirror="MX" if flip_dummy else "R0")
# FIXME: These depend on the array size itself
# Far bottom dummy row (first row below array IS flipped)
flip_dummy = (self.left_rbl + 1) % 2
dummy_row_offset = self.bitcell_offset.scale(0, -self.left_rbl - 1 + flip_dummy)
self.dummy_row_bot_inst.place(offset=dummy_row_offset,
mirror="MX" if flip_dummy else "R0")
self.dummy_row_insts[0].place(offset=dummy_row_offset,
mirror="MX" if flip_dummy else "R0")
# Far left dummy col
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array
dummy_col_offset = self.bitcell_offset.scale(-self.add_left_rbl - 1, -self.left_rbl - 1)
self.dummy_col_left_inst.place(offset=dummy_col_offset)
self.dummy_col_insts[0].place(offset=dummy_col_offset)
# Far right dummy col
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array
dummy_col_offset = self.bitcell_offset.scale(self.add_right_rbl, -self.left_rbl - 1) + self.bitcell_array_inst.lr()
self.dummy_col_right_inst.place(offset=dummy_col_offset)
self.dummy_col_insts[1].place(offset=dummy_col_offset)
def add_layout_pins(self):
""" Add the layout pins """
# All wordlines
# Main array wl and bl/br
pin_names = self.bitcell_array.get_pin_names()
for pin_name in pin_names:
for wl in self.bitcell_array_wordline_names:
if wl in pin_name:
pin_list = self.bitcell_array_inst.get_pins(pin_name)
for pin in pin_list:
self.add_layout_pin(text=pin_name,
layer=pin.layer,
offset=pin.ll().scale(0, 1),
width=self.width,
height=pin.height())
for bitline in self.bitcell_array_bitline_names:
if bitline in pin_name:
pin_list = self.bitcell_array_inst.get_pins(pin_name)
for pin in pin_list:
self.add_layout_pin(text=pin_name,
layer=pin.layer,
offset=pin.ll().scale(1, 0),
width=pin.width(),
height=self.height)
for pin_name in self.all_wordline_names:
pin_list = self.bitcell_array_inst.get_pins(pin_name)
for pin in pin_list:
self.add_layout_pin(text=pin_name,
layer=pin.layer,
offset=pin.ll().scale(0, 1),
width=self.width,
height=pin.height())
for pin_name in self.all_bitline_names:
pin_list = self.bitcell_array_inst.get_pins(pin_name)
for pin in pin_list:
self.add_layout_pin(text=pin_name,
layer=pin.layer,
offset=pin.ll().scale(1, 0),
width=pin.width(),
height=self.height)
# Dummy wordlines
for (name, inst) in [("bot", self.dummy_row_bot_inst), ("top", self.dummy_row_top_inst)]:
for (pin_name, wl_name) in zip(self.cell.get_all_wl_names(), self.dummy_wordline_names[name]):
for (names, inst) in zip(self.dummy_row_wordline_names, self.dummy_row_insts):
for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()):
# It's always a single row
pin = inst.get_pin(pin_name + "_0")
pin = inst.get_pin(pin_name)
self.add_layout_pin(text=wl_name,
layer=pin.layer,
offset=pin.ll().scale(0, 1),
@ -421,9 +419,9 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
# Replica wordlines (go by the row instead of replica column because we may have to add a pin
# even though the column is in another local bitcell array)
for (port, inst) in list(self.dummy_row_replica_inst.items()):
for (pin_name, wl_name) in zip(self.cell.get_all_wl_names(), self.replica_wordline_names[port]):
pin = inst.get_pin(pin_name + "_0")
for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts):
for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()):
pin = inst.get_pin(pin_name)
self.add_layout_pin(text=wl_name,
layer=pin.layer,
offset=pin.ll().scale(0, 1),
@ -431,16 +429,10 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
height=pin.height())
# Replica bitlines
for port in range(self.add_left_rbl + self.add_right_rbl):
inst = self.replica_col_inst[port]
for (pin_name, bl_name) in zip(self.cell.get_all_bitline_names(), self.replica_bitline_names[port]):
for (names, inst) in zip(self.rbl_bitline_names, self.replica_col_insts):
for (bl_name, pin_name) in zip(names, self.replica_columns[0].all_bitline_names):
pin = inst.get_pin(pin_name)
if bl_name in self.replica_bl_names:
name = bl_name
else:
name = "rbl_{0}_{1}".format(pin_name, port)
self.add_layout_pin(text=name,
self.add_layout_pin(text=bl_name,
layer=pin.layer,
offset=pin.ll().scale(1, 0),
width=pin.width(),
@ -448,8 +440,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
# vdd/gnd are only connected in the perimeter cells
# replica column should only have a vdd/gnd in the dummy cell on top/bottom
supply_insts = [self.dummy_col_left_inst, self.dummy_col_right_inst,
self.dummy_row_top_inst, self.dummy_row_bot_inst]
supply_insts = self.dummy_col_insts + self.dummy_row_insts
for pin_name in ["vdd", "gnd"]:
for inst in supply_insts:
pin_list = inst.get_pins(pin_name)
@ -459,7 +450,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
directions=("V", "V"),
start_layer=pin.layer)
for inst in list(self.replica_col_inst.values()):
for inst in self.replica_col_insts:
self.copy_layout_pin(inst, pin_name)
def get_rbl_wordline_names(self, port=None):
@ -468,33 +459,73 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
Inactive will be set to gnd.
"""
if port == None:
temp = []
for port in self.all_ports:
temp.extend(self.replica_wordline_names[port])
return temp
return self.all_rbl_wordline_names
else:
wl_names = self.replica_wordline_names[port]
return wl_names[port]
return self.rbl_wordline_names[port]
def get_rbl_bitline_names(self, port=None):
""" Return the BL for the given RBL port """
if port == None:
temp = []
for port in self.all_ports:
temp.extend(self.replica_bitline_names[port])
return temp
return self.all_rbl_bitline_names
else:
bl_names = self.replica_bitline_names[port]
return bl_names[2 * port:2 * port + 2]
return self.rbl_bitline_names[port]
def get_wordline_names(self):
""" Return the wordline names """
return self.wordline_names
def get_bitline_names(self, port=None):
""" Return the regular bitlines for the given port or all"""
if port == None:
return self.all_bitline_names
else:
return self.bitline_names[port]
def get_all_bitline_names(self):
""" Return ALL the bitline names (including dummy and rbl) """
temp = []
temp.extend(self.get_dummy_bitline_names(0))
if self.add_left_rbl > 0:
temp.extend(self.get_rbl_bitline_names(0))
temp.extend(self.get_bitline_names())
if self.add_right_rbl > 0:
temp.extend(self.get_rbl_bitline_names(self.add_left_rbl))
temp.extend(self.get_dummy_bitline_names(1))
return temp
def get_bitline_names(self):
""" Return the bitline names """
return self.bitline_names
def get_wordline_names(self, port=None):
""" Return the regular wordline names """
if port == None:
return self.all_wordline_names
else:
return self.wordline_names[port]
def get_all_wordline_names(self, port=None):
""" Return all the wordline names """
temp = []
temp.extend(self.get_dummy_wordline_names(0))
temp.extend(self.get_rbl_wordline_names(0))
if port == None:
temp.extend(self.all_wordline_names)
else:
temp.extend(self.wordline_names[port])
if len(self.all_ports) > 1:
temp.extend(self.get_rbl_wordline_names(1))
temp.extend(self.get_dummy_wordline_names(1))
return temp
def get_dummy_wordline_names(self, port=None):
"""
Return the ACTIVE WL for the given dummy port.
"""
if port == None:
return self.all_dummy_row_wordline_names
else:
return self.dummy_row_wordline_names[port]
def get_dummy_bitline_names(self, port=None):
""" Return the BL for the given dummy port """
if port == None:
return self.all_dummy_col_bitline_names
else:
return self.dummy_col_bitline_names[port]
def analytical_power(self, corner, load):
"""Power of Bitcell array and bitline in nW."""
# Dynamic Power from Bitline

View File

@ -15,18 +15,17 @@ class replica_column(design.design):
"""
Generate a replica bitline column for the replica array.
Rows is the total number of rows i the main array.
Left_rbl and right_rbl are the number of left and right replica bitlines.
rbl is a tuple with the number of left and right replica bitlines.
Replica bit specifies which replica column this is (to determine where to put the
replica cell.
replica cell relative to the bottom (including the dummy bit at 0).
"""
def __init__(self, name, rows, left_rbl, right_rbl, replica_bit,
column_offset=0):
def __init__(self, name, rows, rbl, replica_bit, column_offset=0):
super().__init__(name)
self.rows = rows
self.left_rbl = left_rbl
self.right_rbl = right_rbl
self.left_rbl = rbl[0]
self.right_rbl = rbl[1]
self.replica_bit = replica_bit
# left, right, regular rows plus top/bottom dummy cells
self.total_size = self.left_rbl + rows + self.right_rbl + 2
@ -34,10 +33,10 @@ class replica_column(design.design):
debug.check(replica_bit != 0 and replica_bit != rows,
"Replica bit cannot be the dummy row.")
debug.check(replica_bit <= left_rbl or replica_bit >= self.total_size - right_rbl - 1,
debug.check(replica_bit <= self.left_rbl or replica_bit >= self.total_size - self.right_rbl - 1,
"Replica bit cannot be in the regular array.")
if OPTS.tech_name == "sky130":
debug.check(rows % 2 == 0 and (left_rbl + 1) % 2 == 0,
debug.check(rows % 2 == 0 and (self.left_rbl + 1) % 2 == 0,
"sky130 currently requires rows to be even and to start with X mirroring"
+ " (left_rbl must be odd) for LVS.")
@ -61,13 +60,20 @@ class replica_column(design.design):
def add_pins(self):
for bl_name in self.cell.get_all_bitline_names():
# In the replica column, these are only outputs!
self.add_pin("{0}_{1}".format(bl_name, 0), "OUTPUT")
self.bitline_names = [[] for port in self.all_ports]
col = 0
for port in self.all_ports:
self.bitline_names[port].append("bl_{0}_{1}".format(port, col))
self.bitline_names[port].append("br_{0}_{1}".format(port, col))
self.all_bitline_names = [x for sl in self.bitline_names for x in sl]
self.add_pin_list(self.all_bitline_names, "OUTPUT")
self.wordline_names = [[] for port in self.all_ports]
for row in range(self.total_size):
for wl_name in self.cell.get_all_wl_names():
self.add_pin("{0}_{1}".format(wl_name, row), "INPUT")
for port in self.all_ports:
self.wordline_names[port].append("wl_{0}_{1}".format(port, row))
self.all_wordline_names = [x for sl in zip(*self.wordline_names) for x in sl]
self.add_pin_list(self.all_wordline_names, "INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
@ -154,9 +160,15 @@ class replica_column(design.design):
def add_layout_pins(self):
""" Add the layout pins """
for bl_name in self.cell.get_all_bitline_names():
bl_pin = self.cell_inst[0].get_pin(bl_name)
self.add_layout_pin(text=bl_name,
for port in self.all_ports:
bl_pin = self.cell_inst[0].get_pin(self.cell.get_bl_name(port))
self.add_layout_pin(text="bl_{0}_{1}".format(port, 0),
layer=bl_pin.layer,
offset=bl_pin.ll().scale(1, 0),
width=bl_pin.width(),
height=self.height)
bl_pin = self.cell_inst[0].get_pin(self.cell.get_br_name(port))
self.add_layout_pin(text="br_{0}_{1}".format(port, 0),
layer=bl_pin.layer,
offset=bl_pin.ll().scale(1, 0),
width=bl_pin.width(),
@ -174,10 +186,10 @@ class replica_column(design.design):
row_range_max = self.total_size
row_range_min = 0
for row in range(row_range_min, row_range_max):
for wl_name in self.cell.get_all_wl_names():
wl_pin = self.cell_inst[row].get_pin(wl_name)
self.add_layout_pin(text="{0}_{1}".format(wl_name, row),
for port in self.all_ports:
for row in range(row_range_min, row_range_max):
wl_pin = self.cell_inst[row].get_pin(self.cell.get_wl_name(port))
self.add_layout_pin(text="wl_{0}_{1}".format(port, row),
layer=wl_pin.layer,
offset=wl_pin.ll().scale(0, 1),
width=self.width,
@ -191,18 +203,19 @@ class replica_column(design.design):
else:
self.copy_layout_pin(inst, pin_name)
def get_bitline_names(self, port=None):
if port == None:
return self.all_bitline_names
else:
return self.bitline_names[port]
def get_bitcell_pins(self, row, col):
""" Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array """
bitcell_pins = []
pin_names = self.cell.get_all_bitline_names()
for pin in pin_names:
bitcell_pins.append(pin + "_{0}".format(col))
pin_names = self.cell.get_all_wl_names()
for pin in pin_names:
bitcell_pins.append(pin + "_{0}".format(row))
for port in self.all_ports:
bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))])
bitcell_pins.extend([x for x in self.all_wordline_names if x.endswith("_{0}".format(row))])
bitcell_pins.append("vdd")
bitcell_pins.append("gnd")
@ -211,13 +224,11 @@ class replica_column(design.design):
def get_bitcell_pins_col_cap(self, row, col):
""" Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array """
bitcell_pins = []
pin_names = self.cell.get_all_bitline_names()
for pin in pin_names:
bitcell_pins.append(pin + "_{0}".format(col))
for port in self.all_ports:
bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))])
bitcell_pins.append("vdd")
bitcell_pins.append("gnd")
return bitcell_pins

View File

@ -260,6 +260,8 @@ class sram_1bank(sram_base):
for signal in self.control_logic_inputs[port]:
if signal == "clk":
continue
if signal.startswith("rbl"):
continue
if OPTS.perimeter_pins:
self.add_perimeter_pin(name=signal + "{}".format(port),
pin=self.control_logic_insts[port].get_pin(signal),
@ -554,7 +556,7 @@ class sram_1bank(sram_base):
for port in self.all_ports:
# Only input (besides pins) is the replica bitline
src_pin = self.control_logic_insts[port].get_pin("rbl_bl")
dest_pin = self.bank_inst.get_pin("rbl_bl{}".format(port))
dest_pin = self.bank_inst.get_pin("rbl_bl_{0}_{0}".format(port))
self.add_wire(self.m2_stack[::-1],
[src_pin.center(), vector(src_pin.cx(), dest_pin.cy()), dest_pin.rc()])
self.add_via_stack_center(from_layer=src_pin.layer,
@ -590,7 +592,7 @@ class sram_1bank(sram_base):
These should probably be turned off by default though, since extraction
will show these as ports in the extracted netlist.
"""
return
for n in self.control_logic_outputs[0]:
pin = self.control_logic_insts[0].get_pin(n)
self.add_label(text=n,

View File

@ -414,7 +414,6 @@ class sram_base(design, verilog, lef):
temp.append("dout{0}[{1}]".format(port, bit))
for port in self.all_ports:
temp.append("rbl_bl{0}".format(port))
temp.append("rbl_br{0}".format(port))
for port in self.write_ports:
for bit in range(self.word_size + self.num_spare_cols):
temp.append("bank_din{0}[{1}]".format(port, bit))

View File

@ -28,31 +28,34 @@ class replica_bitcell_array_1rw_1r_test(openram_test):
a = factory.create(module_type="replica_bitcell_array",
cols=4,
rows=4,
left_rbl=1,
right_rbl=1,
bitcell_ports=[0, 1],
add_replica=False)
rbl=[1, 1],
add_rbl=[0, 0])
self.local_check(a)
debug.info(2, "Testing 4x4 array for cell_1rw_1r")
debug.info(2, "Testing 4x4 left replica array for cell_1rw_1r")
a = factory.create(module_type="replica_bitcell_array",
cols=4,
rows=4,
left_rbl=1,
right_rbl=1,
bitcell_ports=[0, 1])
rbl=[1, 1],
add_rbl=[1, 0])
self.local_check(a)
debug.info(2, "Testing 4x4 array left and right replica for cell_1rw_1r")
a = factory.create(module_type="replica_bitcell_array",
cols=4,
rows=4,
rbl=[1, 1])
self.local_check(a)
# Sky 130 has restrictions on the symmetries
if OPTS.tech_name != "sky130":
debug.info(2, "Testing 4x4 array for cell_1rw_1r")
debug.info(2, "Testing 4x4 array right only replica for cell_1rw_1r")
a = factory.create(module_type="replica_bitcell_array",
cols=4,
rows=4,
left_rbl=2,
right_rbl=0,
bitcell_ports=[0, 1])
rbl=[1, 1],
add_rbl=[0, 1])
self.local_check(a)
globals.end_openram()

View File

@ -25,7 +25,7 @@ class replica_bitcell_array_test(openram_test):
factory.reset()
debug.info(2, "Testing 4x4 array for bitcell")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0])
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 0])
self.local_check(a)
globals.end_openram()

View File

@ -25,15 +25,15 @@ class replica_column_test(openram_test):
globals.setup_bitcell()
debug.info(2, "Testing replica column for 6t_cell")
a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=0, replica_bit=1)
a = factory.create(module_type="replica_column", rows=4, rbl=[1, 0], replica_bit=1)
self.local_check(a)
debug.info(2, "Testing replica column for 6t_cell")
a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=1, replica_bit=6)
a = factory.create(module_type="replica_column", rows=4, rbl=[1, 1], replica_bit=6)
self.local_check(a)
debug.info(2, "Testing replica column for 6t_cell")
a = factory.create(module_type="replica_column", rows=4, left_rbl=2, right_rbl=0, replica_bit=2)
a = factory.create(module_type="replica_column", rows=4, rbl=[2, 0], replica_bit=2)
self.local_check(a)
globals.end_openram()

View File

@ -20,15 +20,15 @@ class replica_column_test(openram_test):
globals.init_openram(config_file)
debug.info(2, "Testing replica column for 6t_cell")
a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=0, replica_bit=1)
a = factory.create(module_type="replica_column", rows=4, rbl=[1, 0], replica_bit=1)
self.local_check(a)
debug.info(2, "Testing replica column for 6t_cell")
a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=1, replica_bit=6)
a = factory.create(module_type="replica_column", rows=4, rbl=[1, 1], replica_bit=6)
self.local_check(a)
debug.info(2, "Testing replica column for 6t_cell")
a = factory.create(module_type="replica_column", rows=4, left_rbl=2, right_rbl=0, replica_bit=2)
a = factory.create(module_type="replica_column", rows=4, rbl=[2, 0], replica_bit=2)
self.local_check(a)
globals.end_openram()

View File

@ -27,7 +27,7 @@ class replica_pbitcell_array_test(openram_test):
OPTS.num_w_ports = 0
debug.info(2, "Testing 4x4 array for pbitcell")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=1, bitcell_ports=[0,1])
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], add_rbl=[1, 1])
self.local_check(a)
OPTS.bitcell = "pbitcell"
@ -39,7 +39,7 @@ class replica_pbitcell_array_test(openram_test):
factory.reset()
debug.info(2, "Testing 4x4 array for pbitcell")
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0])
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 0], add_rbl=[1, 0])
self.local_check(a)
globals.end_openram()

View File

@ -0,0 +1,41 @@
#!/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 sram_factory import factory
import debug
@unittest.skip("SKIPPING 05_global_bitcell_array_test")
class global_bitcell_array_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
debug.info(2, "Testing 2 x 4x4 global bitcell array for 6t_cell without replica")
a = factory.create(module_type="global_bitcell_array", cols=[4, 4], rows=4, ports=[0])
self.local_check(a)
# debug.info(2, "Testing 4x4 local bitcell array for 6t_cell with replica column")
# a = factory.create(module_type="local_bitcell_array", cols=4, left_rbl=1, rows=4, ports=[0])
# 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,53 @@
#!/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 sram_factory import factory
import debug
# @unittest.skip("SKIPPING 05_local_bitcell_array_test")
class local_bitcell_array_1rw_1r_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r without replica")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], add_rbl=[0, 0])
self.local_check(a)
debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r with replica column")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], add_rbl=[1, 0])
self.local_check(a)
debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r with replica column")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], add_rbl=[0, 1])
self.local_check(a)
debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r with replica column")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], add_rbl=[1, 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())

View File

@ -15,7 +15,7 @@ from sram_factory import factory
import debug
#@unittest.skip("SKIPPING 05_local_bitcell_array_test")
# @unittest.skip("SKIPPING 05_local_bitcell_array_test")
class local_bitcell_array_test(openram_test):
def runTest(self):
@ -23,13 +23,13 @@ class local_bitcell_array_test(openram_test):
globals.init_openram(config_file)
debug.info(2, "Testing 4x4 local bitcell array for 6t_cell without replica")
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, ports=[0], add_replica=False)
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 0], add_rbl=[0, 0])
self.local_check(a)
debug.info(2, "Testing 4x4 local bitcell array for 6t_cell with replica column")
a = factory.create(module_type="local_bitcell_array", cols=4, left_rbl=1, rows=4, ports=[0])
a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 0], add_rbl=[1, 0])
self.local_check(a)
globals.end_openram()

View File

@ -150,7 +150,7 @@ def write_netgen_script(cell_name):
f.write("{} -noconsole << EOF\n".format(OPTS.lvs_exe[1]))
f.write("readnet spice {0}.spice\n".format(cell_name))
f.write("readnet spice {0}.sp\n".format(cell_name))
f.write("lvs {{{0}.spice {0}}} {{{0}.sp {0}}} {1} {0}.lvs.report\n".format(cell_name, setup_file))
f.write("lvs {{{0}.spice {0}}} {{{0}.sp {0}}} {1} {0}.lvs.report -json\n".format(cell_name, setup_file))
f.write("quit\n")
f.write("EOF\n")
f.close()