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 there is a problem. The check option can be set to false
where we dynamically generate groups of connections after a where we dynamically generate groups of connections after a
group of modules are generated.""" 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 from pprint import pformat
modpins_string=pformat(self.insts[-1].mod.pins) if num_pins < num_args:
argpins_string=pformat(args) mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins)
debug.error("Mod connections: {}".format(modpins_string)) arg_pins = args
debug.error("Inst connections: {}".format(argpins_string)) else:
debug.error("Number of net connections ({0}) does not match last instance ({1})".format(len(self.insts[-1].mod.pins), arg_pins = args + [""] * (num_pins - num_args)
len(args)), 1) 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) self.conns.append(args)
if check and (len(self.insts)!=len(self.conns)): 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): for bit in range(self.word_size + self.num_spare_cols):
self.add_pin("dout{0}_{1}".format(port, bit), "OUTPUT") self.add_pin("dout{0}_{1}".format(port, bit), "OUTPUT")
for port in self.all_ports: 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 port in self.write_ports:
for bit in range(self.word_size + self.num_spare_cols): for bit in range(self.word_size + self.num_spare_cols):
self.add_pin("din{0}_{1}".format(port, bit), "INPUT") self.add_pin("din{0}_{1}".format(port, bit), "INPUT")
@ -144,7 +144,7 @@ class bank(design.design):
to_layer="m3", to_layer="m3",
offset=pin_offset) offset=pin_offset)
self.add_path(bl_pin.layer, [pin_offset, pin_pos]) 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", layer="m3",
start=left_right_offset, start=left_right_offset,
end=pin_offset) end=pin_offset)
@ -356,13 +356,6 @@ class bank(design.design):
def add_modules(self): def add_modules(self):
""" Add all the modules using the class loader """ """ 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 = [] self.port_data = []
for port in self.all_ports: for port in self.all_ports:
temp_pre = factory.create(module_type="port_data", 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", self.bitcell_array = factory.create(module_type="replica_bitcell_array",
cols=self.num_cols + self.num_spare_cols, cols=self.num_cols + self.num_spare_cols,
rows=self.num_rows, rows=self.num_rows,
left_rbl=1, rbl=[1, 1 if len(self.all_ports)>1 else 0])
right_rbl=1 if len(self.all_ports)>1 else 0,
bitcell_ports=self.all_ports)
self.add_mod(self.bitcell_array) self.add_mod(self.bitcell_array)
if(self.num_banks > 1): if(self.num_banks > 1):
@ -394,28 +386,29 @@ class bank(design.design):
""" Creating Bitcell Array """ """ Creating Bitcell Array """
self.bitcell_array_inst=self.add_inst(name="replica_bitcell_array", self.bitcell_array_inst=self.add_inst(name="replica_bitcell_array",
mod=self.bitcell_array) mod=self.bitcell_array)
temp = [] # Arrays are always:
rbl_names = self.bitcell_array.get_rbl_bitline_names() # word lines (bottom to top)
temp.extend(rbl_names) # bit lines (left to right)
bitline_names = self.bitcell_array.get_bitline_names() # vdd
temp.extend(bitline_names) # gnd
# Replace RBL wordline with wl_en#
wordline_names = self.bitcell_array.get_wordline_names()
rbl_wl_names = [] temp = self.bitcell_array.get_all_bitline_names()
for port in self.all_ports:
rbl_wl_names.append(self.bitcell_array.get_rbl_wordline_names(port)) wordline_names = self.bitcell_array.get_all_wordline_names()
# Rename the RBL WL to the enable name # Rename the RBL WL to the enable name
for port in self.all_ports: 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 # Connect the other RBL WL to gnd
wordline_names = ["gnd" if x.startswith("rbl_wl") else x for x in wordline_names] wordline_names = ["gnd" if x.startswith("rbl_wl") else x for x in wordline_names]
# Connect the dummy WL to gnd # Connect the dummy WL to gnd
wordline_names = ["gnd" if x.startswith("dummy") else x for x in wordline_names] wordline_names = ["gnd" if x.startswith("dummy") else x for x in wordline_names]
temp.extend(wordline_names) temp.extend(wordline_names)
temp.append("vdd") temp.append("vdd")
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) self.connect_inst(temp)
def place_bitcell_array(self, offset): def place_bitcell_array(self, offset):
@ -424,17 +417,15 @@ class bank(design.design):
def create_port_data(self): def create_port_data(self):
""" Creating Port Data """ """ Creating Port Data """
self.port_data_inst = [None] * len(self.all_ports) self.port_data_inst = [None] * len(self.all_ports)
for port in self.all_ports: for port in self.all_ports:
self.port_data_inst[port]=self.add_inst(name="port_data{}".format(port), self.port_data_inst[port]=self.add_inst(name="port_data{}".format(port),
mod=self.port_data[port]) mod=self.port_data[port])
temp = [] temp = []
rbl_bl_names = self.bitcell_array.get_rbl_bitline_names(port) temp.extend(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)])
temp.extend(rbl_bl_names) temp.extend(self.bitcell_array.get_bitline_names(port))
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))
if port in self.read_ports: if port in self.read_ports:
for bit in range(self.word_size + self.num_spare_cols): for bit in range(self.word_size + self.num_spare_cols):
temp.append("dout{0}_{1}".format(port, bit)) temp.append("dout{0}_{1}".format(port, bit))
@ -479,8 +470,7 @@ class bank(design.design):
for bit in range(self.row_addr_size): for bit in range(self.row_addr_size):
temp.append("addr{0}_{1}".format(port, bit + self.col_addr_size)) temp.append("addr{0}_{1}".format(port, bit + self.col_addr_size))
temp.append("wl_en{}".format(port)) temp.append("wl_en{}".format(port))
for row in range(self.num_rows): temp.extend(self.bitcell_array.get_wordline_names(port))
temp.append("{0}_{1}".format(self.wl_names[port], row))
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
@ -698,27 +688,28 @@ class bank(design.design):
# Connect the regular bitlines # Connect the regular bitlines
inst2 = self.port_data_inst[port] inst2 = self.port_data_inst[port]
inst1 = self.bitcell_array_inst inst1 = self.bitcell_array_inst
inst1_bl_name = self.bl_names[port] + "_{}" inst1_bl_name = [x for x in self.bitcell_array.get_bitline_names(port) if "bl" in x]
inst1_br_name = self.br_names[port] + "_{}" 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, self.connect_bitlines(inst1=inst1,
inst2=inst2, inst2=inst2,
num_bits=self.num_cols,
inst1_bl_name=inst1_bl_name, inst1_bl_name=inst1_bl_name,
inst1_br_name=inst1_br_name, inst1_br_name=inst1_br_name,
inst2_bl_name=inst2_bl_name, inst2_bl_name=inst2_bl_name,
inst2_br_name=inst2_br_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 # 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"]): for (array_name, data_name) in zip(rbl_bl_names, ["rbl_bl", "rbl_br"]):
self.connect_bitline(inst1, inst2, array_name, data_name) self.connect_bitline(inst1, inst2, array_name, data_name)
@ -817,16 +808,16 @@ class bank(design.design):
vector(top_loc.x, yoffset), vector(top_loc.x, yoffset),
top_loc]) top_loc])
def connect_bitlines(self, inst1, inst2, num_bits, def connect_bitlines(self, inst1, inst2,
inst1_bl_name, inst1_br_name, inst1_bl_name, inst1_br_name,
inst2_bl_name, inst2_br_name): inst2_bl_name, inst2_br_name):
""" """
Connect the bl and br of two modules. Connect the bl and br of two modules.
""" """
for (name1, name2) in zip(inst1_bl_name, inst2_bl_name):
for col in range(num_bits): self.connect_bitline(inst1, inst2, name1, name2)
self.connect_bitline(inst1, inst2, inst1_bl_name.format(col), inst2_bl_name.format(col)) for (name1, name2) in zip(inst1_br_name, inst2_br_name):
self.connect_bitline(inst1, inst2, inst1_br_name.format(col), inst2_br_name.format(col)) self.connect_bitline(inst1, inst2, name1, name2)
def route_port_address(self, port): def route_port_address(self, port):
""" Connect Wordline driver to bitcell array wordline """ """ Connect Wordline driver to bitcell array wordline """
@ -841,11 +832,12 @@ class bank(design.design):
def route_port_address_left(self, port): def route_port_address_left(self, port):
""" Connecting Wordline driver output to Bitcell WL connection """ """ 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. # 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() 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() 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) 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) 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): def route_port_address_right(self, port):
""" Connecting Wordline driver output to Bitcell WL connection """ """ 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. # 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() 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() 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) 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) 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 These should probably be turned off by default though, since extraction
will show these as ports in the extracted netlist. 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 # Add the wordline names
for i in range(self.num_rows): # for i in range(self.num_rows):
wl_name = "wl_{}".format(i) # wl_name = "wl_{}".format(i)
wl_pin = self.bitcell_array_inst.get_pin(wl_name) # wl_pin = self.bitcell_array_inst.get_pin(wl_name)
self.add_label(text=wl_name, # self.add_label(text=wl_name,
layer="m1", # layer="m1",
offset=wl_pin.center()) # offset=wl_pin.center())
# Add the bitline names # # Add the bitline names
for i in range(self.num_cols): # for i in range(self.num_cols):
bl_name = "bl_{}".format(i) # bl_name = "bl_{}".format(i)
br_name = "br_{}".format(i) # br_name = "br_{}".format(i)
bl_pin = self.bitcell_array_inst.get_pin(bl_name) # bl_pin = self.bitcell_array_inst.get_pin(bl_name)
br_pin = self.bitcell_array_inst.get_pin(br_name) # br_pin = self.bitcell_array_inst.get_pin(br_name)
self.add_label(text=bl_name, # self.add_label(text=bl_name,
layer="m2", # layer="m2",
offset=bl_pin.center()) # offset=bl_pin.center())
self.add_label(text=br_name, # self.add_label(text=br_name,
layer="m2", # layer="m2",
offset=br_pin.center()) # offset=br_pin.center())
# # Add the data output names to the sense amp output # # Add the data output names to the sense amp output
# for i in range(self.word_size): # for i in range(self.word_size):
@ -953,24 +949,27 @@ class bank(design.design):
# offset=data_pin.center()) # offset=data_pin.center())
# Add labels on the decoder # Add labels on the decoder
for port in self.write_ports: # for port in self.write_ports:
for i in range(self.word_size): # for i in range(self.word_size):
data_name = "dec_out_{}".format(i) # data_name = "dec_out_{}".format(i)
pin_name = "in_{}".format(i) # pin_name = "in_{}".format(i)
data_pin = self.wordline_driver_inst[port].get_pin(pin_name) # data_pin = self.wordline_driver_inst[port].get_pin(pin_name)
self.add_label(text=data_name, # self.add_label(text=data_name,
layer="m1", # layer="m1",
offset=data_pin.center()) # offset=data_pin.center())
def route_unused_wordlines(self): def route_unused_wordlines(self):
""" Connect the unused RBL and dummy wordlines to gnd """ """ Connect the unused RBL and dummy wordlines to gnd """
gnd_wl_names = [] gnd_wl_names = []
# Connect unused RBL WL to gnd # 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")]) # All RBL WL names
dummy_rbl_names = set([x for x in self.bitcell_array.get_all_wordline_names() if x.startswith("dummy")]) array_rbl_names = set(self.bitcell_array.get_rbl_wordline_names())
rbl_wl_names = set([self.bitcell_array.get_rbl_wordline_names(x) for x in self.all_ports]) 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) gnd_wl_names = list((array_rbl_names - rbl_wl_names) | dummy_rbl_names)
for wl_name in gnd_wl_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) rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)
connection.append((self.prefix + "wl_en{}".format(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: if port in self.write_ports:
connection.append((self.prefix + "w_en{}".format(port), 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() self.create_all_wordline_names()
def get_all_bitline_names(self, prefix=""): 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): def create_all_bitline_names(self):
self.bitline_names = list() self.bitline_names = [[] for port in self.all_ports]
bitline_names = self.cell.get_all_bitline_names()
for col in range(self.column_size): for col in range(self.column_size):
for cell_column in bitline_names: for port in self.all_ports:
self.bitline_names.append("{0}_{1}".format(cell_column, col)) 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=""): 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): def create_all_wordline_names(self):
self.wordline_names = [[] for port in self.all_ports]
self.wordline_names = list()
wordline_names = self.cell.get_all_wl_names()
for row in range(self.row_size): for row in range(self.row_size):
for cell_row in wordline_names: for port in self.all_ports:
self.wordline_names.append("{0}_{1}".format(cell_row, row)) 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): 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") 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(wl_name, "INPUT")
self.add_pin("vdd", "POWER") self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
@ -64,12 +75,10 @@ class bitcell_base_array(design.design):
def get_bitcell_pins(self, row, col): def get_bitcell_pins(self, row, col):
""" Creates a list of connections in the bitcell, """ Creates a list of connections in the bitcell,
indexed by column and row, for instance use in bitcell_array """ indexed by column and row, for instance use in bitcell_array """
bitcell_pins = [] bitcell_pins = []
# bitlines for port in self.all_ports:
bitcell_pins.extend([x for x in self.bitline_names if x.endswith("_{0}".format(col))]) bitcell_pins.extend([x for x in self.get_bitline_names(port) if x.endswith("_{0}".format(col))])
# wordlines bitcell_pins.extend([x for x in self.all_wordline_names if x.endswith("_{0}".format(row))])
bitcell_pins.extend([x for x in self.wordline_names if x.endswith("_{0}".format(row))])
bitcell_pins.append("vdd") bitcell_pins.append("vdd")
bitcell_pins.append("gnd") bitcell_pins.append("gnd")
@ -80,19 +89,25 @@ class bitcell_base_array(design.design):
bitline_names = self.cell.get_all_bitline_names() bitline_names = self.cell.get_all_bitline_names()
for col in range(self.column_size): for col in range(self.column_size):
for bl_name in bitline_names: for port in self.all_ports:
bl_pin = self.cell_inst[0, col].get_pin(bl_name) bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port])
self.add_layout_pin(text="{0}_{1}".format(bl_name, col), self.add_layout_pin(text="bl_{0}_{1}".format(port, col),
layer=bl_pin.layer, layer=bl_pin.layer,
offset=bl_pin.ll().scale(1, 0), offset=bl_pin.ll().scale(1, 0),
width=bl_pin.width(), width=bl_pin.width(),
height=self.height) 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() wl_names = self.cell.get_all_wl_names()
for row in range(self.row_size): for row in range(self.row_size):
for wl_name in wl_names: for port in self.all_ports:
wl_pin = self.cell_inst[row, 0].get_pin(wl_name) wl_pin = self.cell_inst[row, 0].get_pin(wl_names[port])
self.add_layout_pin(text="{0}_{1}".format(wl_name, row), self.add_layout_pin(text="wl_{0}_{1}".format(port, row),
layer=wl_pin.layer, layer=wl_pin.layer,
offset=wl_pin.ll().scale(0, 1), offset=wl_pin.ll().scale(0, 1),
width=self.width, width=self.width,

View File

@ -5,27 +5,35 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from bitcell_base_array import bitcell_base_array import design
from tech import drc, spice
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
from vector import vector
import debug 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() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
@ -49,18 +57,92 @@ class global_bitcell_array(bitcell_base_array):
def add_modules(self): def add_modules(self):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.local_mods = [] 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.add_mod(la)
self.local_mods.append(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): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """
self.local_inst = {} self.local_insts = []
for i in range(self.sizes): for i, mod in enumerate(self.local_mods):
name = "local_array_{0}".format(i) name = "la_{0}".format(i)
self.local_inst.append(self.add_inst(name=name, self.local_insts.append(self.add_inst(name=name,
mod=self.local_mods[i]) mod=mod))
self.connect_inst(self.get_bitcell_pins(row, col)) 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) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import bitcell_base_array import design
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
from vector import vector from vector import vector
from tech import drc
import debug 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. 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 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. 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=""): def __init__(self, rows, cols, rbl, add_rbl=None, name=""):
super().__init__(name, rows, cols, 0) super().__init__(name=name)
debug.info(2, "create local array of size {} rows x {} cols words".format(rows, debug.info(2, "create local array of size {} rows x {} cols words".format(rows, cols))
cols + left_rbl + right_rbl))
self.rows = rows self.rows = rows
self.cols = cols self.cols = cols
self.add_replica=add_replica self.rbl = rbl
self.all_ports = ports 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() self.create_netlist()
if not OPTS.netlist_only: 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", self.bitcell_array = factory.create(module_type="replica_bitcell_array",
cols=self.cols, cols=self.cols,
rows=self.rows, rows=self.rows,
left_rbl=1, rbl=self.rbl,
right_rbl=1 if len(self.all_ports)>1 else 0, add_rbl=self.add_rbl)
bitcell_ports=self.all_ports,
add_replica=self.add_replica)
self.add_mod(self.bitcell_array) self.add_mod(self.bitcell_array)
self.wl_array = factory.create(module_type="wordline_buffer_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) cols=self.cols)
self.add_mod(self.wl_array) self.add_mod(self.wl_array)
def add_pins(self): def add_pins(self):
self.bitline_names = self.bitcell_array.get_all_bitline_names() # Inputs to the wordline driver (by port)
self.add_pin_list(self.bitline_names, "INOUT") self.wordline_names = []
self.driver_wordline_inputs = [x for x in self.bitcell_array.get_all_wordline_names() if not x.startswith("dummy")] # Outputs from the wordline driver (by port)
self.driver_wordline_outputs = [x + "i" for x in self.driver_wordline_inputs] self.driver_wordline_outputs = []
self.array_wordline_inputs = [x + "i" if not x.startswith("dummy") else "gnd" for x in self.bitcell_array.get_all_wordline_names()] # Inputs to the bitcell array (by port)
self.add_pin_list(self.wordline_names, "INPUT") self.array_wordline_inputs = []
self.replica_names = self.bitcell_array.get_rbl_wordline_names()
self.add_pin_list(self.replica_names, "INPUT") for port in self.all_ports:
self.bitline_names = self.bitcell_array.get_inouts() 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("vdd", "POWER")
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """
self.wl_inst = self.add_inst(name="wl_driver", self.wl_insts = []
mod=self.wl_array) for port in self.all_ports:
self.connect_inst(self.driver_wordline_inputs + self.driver_wordline_outputs + ["vdd", "gnd"]) 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", self.bitcell_array_inst = self.add_inst(name="array",
mod=self.bitcell_array, mod=self.bitcell_array)
offset=self.wl_inst.lr())
self.connect_inst(self.bitline_names + self.array_wordline_inputs + ["vdd", "gnd"]) self.connect_inst(self.all_array_bitline_names + self.all_array_wordline_inputs + ["vdd", "gnd"])
def place(self): def place(self):
""" Place the bitcelll array to the right of the wl driver. """ """ 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 # FIXME: Replace this with a tech specific paramter
driver_to_array_spacing = 3 * self.m3_pitch 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)) 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.height = self.bitcell_array.height
self.width = self.bitcell_array_inst.rx() self.width = self.bitcell_array_inst.rx()
def route_unused_wordlines(self): def route_unused_wordlines(self):
""" Connect the unused RBL and dummy wordlines to gnd """ """ Connect the unused RBL and dummy wordlines to gnd """
gnd_wl_names = []
# Connect unused RBL WL to gnd for wl_name in self.gnd_wl_names:
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:
pin = self.bitcell_array_inst.get_pin(wl_name) pin = self.bitcell_array_inst.get_pin(wl_name)
pin_layer = pin.layer pin_layer = pin.layer
layer_pitch = 1.5 * getattr(self, "{}_pitch".format(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): def add_layout_pins(self):
for (x, y) in zip(self.bitline_names, self.bitcell_array.get_inouts()): for x in self.get_inouts():
self.copy_layout_pin(self.bitcell_array_inst, y, x) 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()): supply_insts = [*self.wl_insts, self.bitcell_array_inst]
self.copy_layout_pin(self.wl_inst, y, x)
supply_insts = [self.wl_inst, self.bitcell_array_inst]
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
for inst in supply_insts: for inst in supply_insts:
pin_list = inst.get_pins(pin_name) 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) start_layer=pin.layer)
def route(self): 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): for port in self.all_ports:
out_pin = self.wl_inst.get_pin(driver_name) for (driver_name, net_name) in zip(self.wl_insts[port].mod.get_outputs(), self.driver_wordline_outputs[port]):
in_pin = self.bitcell_array_inst.get_pin(array_name) array_name = net_name[:-1]
mid_loc = self.wl_inst.rx() + 1.5 * self.m3_pitch out_pin = self.wl_insts[port].get_pin(driver_name)
self.add_path(out_pin.layer, [out_pin.rc(), vector(mid_loc, out_pin.cy()), in_pin.lc()]) 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() self.route_unused_wordlines()

View File

@ -53,18 +53,10 @@ class port_data(design.design):
return self.precharge.get_br_names() return self.precharge.get_br_names()
def get_bl_name(self, port=0): def get_bl_name(self, port=0):
bl_name = "bl" return "bl_{}".format(port)
if len(self.all_ports) == 1:
return bl_name
else:
return bl_name + "{}".format(port)
def get_br_name(self, port=0): def get_br_name(self, port=0):
br_name = "br" return "br_{}".format(port)
if len(self.all_ports) == 1:
return br_name
else:
return br_name + "{}".format(port)
def create_netlist(self): def create_netlist(self):
self.precompute_constants() self.precompute_constants()
@ -110,15 +102,11 @@ class port_data(design.design):
self.add_pin("rbl_bl", "INOUT") self.add_pin("rbl_bl", "INOUT")
self.add_pin("rbl_br", "INOUT") self.add_pin("rbl_br", "INOUT")
for bit in range(self.num_cols): for bit in range(self.num_cols):
bl_name = self.get_bl_name(self.port) self.add_pin("bl_{0}".format(bit), "INOUT")
br_name = self.get_br_name(self.port) self.add_pin("br_{0}".format(bit), "INOUT")
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): for bit in range(self.num_spare_cols):
bl_name = self.get_bl_name(self.port) self.add_pin("sparebl_{0}".format(bit), "INOUT")
br_name = self.get_br_name(self.port) self.add_pin("sparebr_{0}".format(bit), "INOUT")
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: if self.port in self.read_ports:
for bit in range(self.word_size + self.num_spare_cols): 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), self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port),
mod=self.precharge_array) mod=self.precharge_array)
bl_name = self.get_bl_name(self.port)
br_name = self.get_br_name(self.port)
temp = [] temp = []
# Use left BLs for RBL # Use left BLs for RBL
if self.port==0: if self.port==0:
temp.append("rbl_bl") temp.append("rbl_bl")
temp.append("rbl_br") temp.append("rbl_br")
for bit in range(self.num_cols): for bit in range(self.num_cols):
temp.append("{0}_{1}".format(bl_name, bit)) temp.append("bl_{0}".format(bit))
temp.append("{0}_{1}".format(br_name, bit)) temp.append("br_{0}".format(bit))
for bit in range(self.num_spare_cols): for bit in range(self.num_spare_cols):
temp.append("spare{0}_{1}".format(bl_name, bit)) temp.append("sparebl_{0}".format(bit))
temp.append("spare{0}_{1}".format(br_name, bit)) temp.append("sparebr_{0}".format(bit))
# Use right BLs for RBL # Use right BLs for RBL
if self.port==1: 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), self.column_mux_array_inst = self.add_inst(name="column_mux_array{}".format(self.port),
mod=self.column_mux_array) mod=self.column_mux_array)
bl_name = self.get_bl_name(self.port)
br_name = self.get_br_name(self.port)
temp = [] temp = []
for col in range(self.num_cols): for col in range(self.num_cols):
temp.append("{0}_{1}".format(bl_name, col)) temp.append("bl_{0}".format(col))
temp.append("{0}_{1}".format(br_name, col)) temp.append("br_{0}".format(col))
for word in range(self.words_per_row): for word in range(self.words_per_row):
temp.append("sel_{}".format(word)) temp.append("sel_{}".format(word))
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append("{0}_out_{1}".format(bl_name, bit)) temp.append("bl_out_{0}".format(bit))
temp.append("{0}_out_{1}".format(br_name, bit)) temp.append("br_out_{0}".format(bit))
temp.append("gnd") temp.append("gnd")
self.connect_inst(temp) 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), self.sense_amp_array_inst = self.add_inst(name="sense_amp_array{}".format(self.port),
mod=self.sense_amp_array) mod=self.sense_amp_array)
bl_name = self.get_bl_name(self.port)
br_name = self.get_br_name(self.port)
temp = [] temp = []
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append("dout_{}".format(bit)) temp.append("dout_{}".format(bit))
if self.words_per_row == 1: if self.words_per_row == 1:
temp.append("{0}_{1}".format(bl_name, bit)) temp.append("bl_{0}".format(bit))
temp.append("{0}_{1}".format(br_name, bit)) temp.append("br_{0}".format(bit))
else: else:
temp.append("{0}_out_{1}".format(bl_name, bit)) temp.append("bl_out_{0}".format(bit))
temp.append("{0}_out_{1}".format(br_name, bit)) temp.append("br_out_{0}".format(bit))
for bit in range(self.num_spare_cols): for bit in range(self.num_spare_cols):
temp.append("dout_{}".format(self.word_size + bit)) temp.append("dout_{}".format(self.word_size + bit))
temp.append("spare{0}_{1}".format(bl_name, bit)) temp.append("sparebl_{0}".format(bit))
temp.append("spare{0}_{1}".format(br_name, bit)) temp.append("sparebr_{0}".format(bit))
temp.append("s_en") temp.append("s_en")
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
@ -364,24 +345,21 @@ class port_data(design.design):
""" Creating Write Driver """ """ Creating Write Driver """
self.write_driver_array_inst = self.add_inst(name="write_driver_array{}".format(self.port), self.write_driver_array_inst = self.add_inst(name="write_driver_array{}".format(self.port),
mod=self.write_driver_array) mod=self.write_driver_array)
bl_name = self.get_bl_name(self.port)
br_name = self.get_br_name(self.port)
temp = [] temp = []
for bit in range(self.word_size + self.num_spare_cols): for bit in range(self.word_size + self.num_spare_cols):
temp.append("din_{}".format(bit)) temp.append("din_{}".format(bit))
for bit in range(self.word_size): for bit in range(self.word_size):
if (self.words_per_row == 1): if (self.words_per_row == 1):
temp.append("{0}_{1}".format(bl_name, bit)) temp.append("bl_{0}".format(bit))
temp.append("{0}_{1}".format(br_name, bit)) temp.append("br_{0}".format(bit))
else: else:
temp.append("{0}_out_{1}".format(bl_name, bit)) temp.append("bl_out_{0}".format(bit))
temp.append("{0}_out_{1}".format(br_name, bit)) temp.append("br_out_{0}".format(bit))
for bit in range(self.num_spare_cols): for bit in range(self.num_spare_cols):
temp.append("spare{0}_{1}".format(bl_name, bit)) temp.append("sparebl_{0}".format(bit))
temp.append("spare{0}_{1}".format(br_name, bit)) temp.append("sparebr_{0}".format(bit))
if self.write_size is not None: if self.write_size is not None:
for i in range(self.num_wmasks): for i in range(self.num_wmasks):
@ -729,7 +707,7 @@ class port_data(design.design):
# Add spare columns' en_{} pins # 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)) 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: 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): 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)) self.copy_layout_pin(self.write_driver_array_inst, "en_{}".format(bit + 1), "bank_spare_wen{}".format(bit))
else: 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 Requires a regular bitcell array, replica bitcell, and dummy
bitcell (Bl/BR disconnected). 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) super().__init__(name, rows, cols, column_offset=0)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.add_comment("rows: {0} cols: {1}".format(rows, cols)) self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.column_size = cols self.column_size = cols
self.row_size = rows self.row_size = rows
self.left_rbl = left_rbl # This is how many RBLs are in all the arrays
self.right_rbl = right_rbl self.rbl = rbl
self.bitcell_ports = bitcell_ports self.left_rbl = rbl[0]
# If set to false, we increase the height for the replica wordline row, but don't self.right_rbl = rbl[1]
# actually add the column to this array. This is so the height matches other # This is how many RBLs are added to THIS array
# banks that have the replica columns. if add_rbl == None:
# Number of replica columns to actually add self.add_left_rbl = rbl[0]
if add_replica: self.add_right_rbl = rbl[1]
self.add_left_rbl = self.left_rbl
self.add_right_rbl = self.right_rbl
else: else:
self.add_left_rbl = 0 self.add_left_rbl = add_rbl[0]
self.add_right_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.") "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 # 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 # Two dummy cols plus replica if we add the column
self.extra_cols = 2 + self.add_left_rbl + self.add_right_rbl 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 # We don't offset this because we need to align
# the replica bitcell in the control logic # the replica bitcell in the control logic
# self.offset_all_coordinates() # self.offset_all_coordinates()
def create_netlist(self): def create_netlist(self):
""" Create and connect the netlist """ """ Create and connect the netlist """
self.add_modules() self.add_modules()
@ -112,8 +111,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
column_offset = self.left_rbl + 1 column_offset = self.left_rbl + 1
self.replica_columns[bit] = factory.create(module_type="replica_column", self.replica_columns[bit] = factory.create(module_type="replica_column",
rows=self.row_size, rows=self.row_size,
left_rbl=self.add_left_rbl, rbl=self.rbl,
right_rbl=self.add_right_rbl,
column_offset=column_offset, column_offset=column_offset,
replica_bit=replica_bit) replica_bit=replica_bit)
self.add_mod(self.replica_columns[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): 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_bitline_pins()
self.add_wordline_pins() self.add_wordline_pins()
self.add_pin("vdd", "POWER") self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
def add_bitline_pins(self): def add_bitline_pins(self):
# Regular bitline names by port
# Regular bitline names for all ports
self.bitline_names = [] self.bitline_names = []
# Bitline names for each port # Replica bitlines by port
self.bitline_names_by_port = [[] for x in self.all_ports] self.rbl_bitline_names = []
# Replica wordlines by port # Dummy bitlines by left/right
self.replica_bitline_names = [[] for x in self.all_ports] self.dummy_col_bitline_names = []
# Replica wordlines by port (bl only)
self.replica_bl_names = [[] for x in self.all_ports]
# Dummy wordlines by port
self.dummy_bitline_names = []
# Regular array bitline names for loc in ["left", "right"]:
self.bitcell_array_bitline_names = self.bitcell_array.get_all_bitline_names() 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): 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))] left_names=["rbl_bl_{0}_{1}".format(x, port) for x in self.all_ports]
right_names=["rbl_{0}_{1}".format(self.cell.get_br_name(x), port) for x in range(len(self.all_ports))] right_names=["rbl_br_{0}_{1}".format(x, port) for x in 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
bitline_names = [x for t in zip(left_names, right_names) for x in t] bitline_names = [x for t in zip(left_names, right_names) for x in t]
self.replica_bitline_names[port] = bitline_names self.rbl_bitline_names.append(bitline_names)
# Make a flat list too
# Dummy bitlines are not connected to anything self.all_rbl_bitline_names = [x for sl in self.rbl_bitline_names for x in sl]
self.bitline_names.extend(self.bitcell_array_bitline_names)
for port in self.all_ports: for port in self.all_ports:
self.add_pin_list(self.replica_bitline_names[port], "INOUT") bitline_names = self.bitcell_array.get_bitline_names(port)
self.add_pin_list(self.bitline_names, "INOUT") 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): def add_wordline_pins(self):
# All wordline names for all ports # Regular wordlines by port
self.wordline_names = [] self.wordline_names = []
# Wordline names for each port
self.wordline_names_by_port = [[] for x in self.all_ports]
# Replica wordlines by port # Replica wordlines by port
self.replica_wordline_names = [[] for x in self.all_ports] self.rbl_wordline_names = []
# Dummy wordlines # Dummy wordlines by bot/top
self.dummy_wordline_names = {} self.dummy_row_wordline_names = []
# Regular array wordline names dummy_row_wordline_names = ["dummy_" + x for x in self.col_cap.get_wordline_names()]
self.bitcell_array_wordline_names = self.bitcell_array.get_all_wordline_names() for loc in ["bot", "top"]:
wordline_names = ["{0}_{1}".format(wl_name, loc) for wl_name in dummy_row_wordline_names]
# These are the non-indexed names self.dummy_row_wordline_names.append(wordline_names)
dummy_cell_wl_names = ["dummy_" + x for x in self.cell.get_all_wl_names()] self.all_dummy_row_wordline_names = [x for sl in self.dummy_row_wordline_names for x in sl]
# 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"])
# Array of all port wl names
for port in range(self.left_rbl + self.right_rbl): 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()] wordline_names=["rbl_wl_{0}_{1}".format(x, port) for x in self.all_ports]
self.replica_wordline_names[port] = wl_names 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): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """
@ -273,42 +273,44 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
# Main array # Main array
self.bitcell_array_inst=self.add_inst(name="bitcell_array", self.bitcell_array_inst=self.add_inst(name="bitcell_array",
mod=self.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 # Replica columns
self.replica_col_inst = {} self.replica_col_insts = []
for port in range(self.add_left_rbl + self.add_right_rbl): 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), self.replica_col_insts.append(self.add_inst(name="replica_col_{}".format(port),
mod=self.replica_columns[port]) mod=self.replica_columns[port]))
self.connect_inst(self.replica_bitline_names[port] + self.wordline_names + supplies) 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) # 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! # 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): for port in range(self.left_rbl + self.right_rbl):
self.dummy_row_replica_inst[port]=self.add_inst(name="dummy_row_{}".format(port), self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port),
mod=self.dummy_row) mod=self.dummy_row))
self.connect_inst(self.bitcell_array_bitline_names + self.replica_wordline_names[port] + supplies) self.connect_inst(self.all_bitline_names + self.rbl_wordline_names[port] + supplies)
# Top/bottom dummy rows or col caps # Top/bottom dummy rows or col caps
self.dummy_row_bot_inst=self.add_inst(name="dummy_row_bot", self.dummy_row_insts = []
mod=self.col_cap) self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot",
self.connect_inst(self.bitcell_array_bitline_names mod=self.col_cap))
+ self.dummy_wordline_names["bot"] self.connect_inst(self.all_bitline_names
+ self.dummy_row_wordline_names[0]
+ supplies) + supplies)
self.dummy_row_top_inst=self.add_inst(name="dummy_row_top", self.dummy_row_insts.append(self.add_inst(name="dummy_row_top",
mod=self.col_cap) mod=self.col_cap))
self.connect_inst(self.bitcell_array_bitline_names self.connect_inst(self.all_bitline_names
+ self.dummy_wordline_names["top"] + self.dummy_row_wordline_names[1]
+ supplies) + supplies)
# Left/right Dummy columns # Left/right Dummy columns
self.dummy_col_left_inst=self.add_inst(name="dummy_col_left", self.dummy_col_insts = []
mod=self.row_cap_left) self.dummy_col_insts.append(self.add_inst(name="dummy_col_left",
self.connect_inst(self.dummy_bitline_names[0] + self.wordline_names + supplies) mod=self.row_cap_left))
self.dummy_col_right_inst=self.add_inst(name="dummy_col_right", self.connect_inst(self.dummy_col_bitline_names[0] + self.replica_array_wordline_names + supplies)
mod=self.row_cap_right) self.dummy_col_insts.append(self.add_inst(name="dummy_col_right",
self.connect_inst(self.dummy_bitline_names[-1] + self.wordline_names + supplies) mod=self.row_cap_right))
self.connect_inst(self.dummy_col_bitline_names[1] + self.replica_array_wordline_names + supplies)
def create_layout(self): 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 # Grow from left to right, toward the array
for bit in range(self.add_left_rbl): for bit in range(self.add_left_rbl):
offset = self.bitcell_offset.scale(-self.add_left_rbl + bit, -self.add_left_rbl - 1) offset = self.bitcell_offset.scale(-self.add_left_rbl + bit, -self.left_rbl - 1)
self.replica_col_inst[bit].place(offset) self.replica_col_insts[bit].place(offset)
# Grow to the right of the bitcell array, array outward # Grow to the right of the bitcell array, array outward
for bit in range(self.add_right_rbl): for bit in range(self.add_right_rbl):
offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.add_left_rbl - 1) offset = self.bitcell_array_inst.lr() + self.bitcell_offset.scale(bit, -self.left_rbl - 1)
self.replica_col_inst[self.add_left_rbl + bit].place(offset) self.replica_col_insts[self.add_left_rbl + bit].place(offset)
# Replica dummy rows # Replica dummy rows
# Add the dummy rows even if we aren't adding the replica column to this bitcell array # Add the dummy rows even if we aren't adding the replica column to this bitcell array
# These grow up, toward the array # These grow up, toward the array
for bit in range(self.left_rbl): 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") mirror="MX" if (-self.left_rbl + bit) % 2 else "R0")
# These grow up, away from the array # These grow up, away from the array
for bit in range(self.right_rbl): 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") mirror="MX" if bit % 2 else "R0")
def add_end_caps(self): 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) # Far top dummy row (first row above array is NOT flipped)
flip_dummy = self.right_rbl % 2 flip_dummy = self.right_rbl % 2
dummy_row_offset = self.bitcell_offset.scale(0, self.right_rbl + flip_dummy) + self.bitcell_array_inst.ul() 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") mirror="MX" if flip_dummy else "R0")
# FIXME: These depend on the array size itself # FIXME: These depend on the array size itself
# Far bottom dummy row (first row below array IS flipped) # Far bottom dummy row (first row below array IS flipped)
flip_dummy = (self.left_rbl + 1) % 2 flip_dummy = (self.left_rbl + 1) % 2
dummy_row_offset = self.bitcell_offset.scale(0, -self.left_rbl - 1 + flip_dummy) dummy_row_offset = self.bitcell_offset.scale(0, -self.left_rbl - 1 + flip_dummy)
self.dummy_row_bot_inst.place(offset=dummy_row_offset, self.dummy_row_insts[0].place(offset=dummy_row_offset,
mirror="MX" if flip_dummy else "R0") mirror="MX" if flip_dummy else "R0")
# Far left dummy col # Far left dummy col
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array # 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) 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 # Far right dummy col
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array # 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() 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): def add_layout_pins(self):
""" Add the layout pins """ """ Add the layout pins """
# All wordlines # All wordlines
# Main array wl and bl/br # Main array wl and bl/br
pin_names = self.bitcell_array.get_pin_names() for pin_name in self.all_wordline_names:
for pin_name in pin_names: pin_list = self.bitcell_array_inst.get_pins(pin_name)
for wl in self.bitcell_array_wordline_names: for pin in pin_list:
if wl in pin_name: self.add_layout_pin(text=pin_name,
pin_list = self.bitcell_array_inst.get_pins(pin_name) layer=pin.layer,
for pin in pin_list: offset=pin.ll().scale(0, 1),
self.add_layout_pin(text=pin_name, width=self.width,
layer=pin.layer, height=pin.height())
offset=pin.ll().scale(0, 1), for pin_name in self.all_bitline_names:
width=self.width, pin_list = self.bitcell_array_inst.get_pins(pin_name)
height=pin.height()) for pin in pin_list:
for bitline in self.bitcell_array_bitline_names: self.add_layout_pin(text=pin_name,
if bitline in pin_name: layer=pin.layer,
pin_list = self.bitcell_array_inst.get_pins(pin_name) offset=pin.ll().scale(1, 0),
for pin in pin_list: width=pin.width(),
self.add_layout_pin(text=pin_name, height=self.height)
layer=pin.layer,
offset=pin.ll().scale(1, 0),
width=pin.width(),
height=self.height)
# Dummy wordlines # Dummy wordlines
for (name, inst) in [("bot", self.dummy_row_bot_inst), ("top", self.dummy_row_top_inst)]: for (names, inst) in zip(self.dummy_row_wordline_names, self.dummy_row_insts):
for (pin_name, wl_name) in zip(self.cell.get_all_wl_names(), self.dummy_wordline_names[name]): for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()):
# It's always a single row # 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, self.add_layout_pin(text=wl_name,
layer=pin.layer, layer=pin.layer,
offset=pin.ll().scale(0, 1), 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 # 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) # even though the column is in another local bitcell array)
for (port, inst) in list(self.dummy_row_replica_inst.items()): for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts):
for (pin_name, wl_name) in zip(self.cell.get_all_wl_names(), self.replica_wordline_names[port]): for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()):
pin = inst.get_pin(pin_name + "_0") pin = inst.get_pin(pin_name)
self.add_layout_pin(text=wl_name, self.add_layout_pin(text=wl_name,
layer=pin.layer, layer=pin.layer,
offset=pin.ll().scale(0, 1), offset=pin.ll().scale(0, 1),
@ -431,16 +429,10 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
height=pin.height()) height=pin.height())
# Replica bitlines # Replica bitlines
for port in range(self.add_left_rbl + self.add_right_rbl): for (names, inst) in zip(self.rbl_bitline_names, self.replica_col_insts):
inst = self.replica_col_inst[port] for (bl_name, pin_name) in zip(names, self.replica_columns[0].all_bitline_names):
for (pin_name, bl_name) in zip(self.cell.get_all_bitline_names(), self.replica_bitline_names[port]):
pin = inst.get_pin(pin_name) pin = inst.get_pin(pin_name)
self.add_layout_pin(text=bl_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,
layer=pin.layer, layer=pin.layer,
offset=pin.ll().scale(1, 0), offset=pin.ll().scale(1, 0),
width=pin.width(), 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 # vdd/gnd are only connected in the perimeter cells
# replica column should only have a vdd/gnd in the dummy cell on top/bottom # 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, supply_insts = self.dummy_col_insts + self.dummy_row_insts
self.dummy_row_top_inst, self.dummy_row_bot_inst]
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
for inst in supply_insts: for inst in supply_insts:
pin_list = inst.get_pins(pin_name) pin_list = inst.get_pins(pin_name)
@ -459,7 +450,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
directions=("V", "V"), directions=("V", "V"),
start_layer=pin.layer) 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) self.copy_layout_pin(inst, pin_name)
def get_rbl_wordline_names(self, port=None): 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. Inactive will be set to gnd.
""" """
if port == None: if port == None:
temp = [] return self.all_rbl_wordline_names
for port in self.all_ports:
temp.extend(self.replica_wordline_names[port])
return temp
else: else:
wl_names = self.replica_wordline_names[port] return self.rbl_wordline_names[port]
return wl_names[port]
def get_rbl_bitline_names(self, port=None): def get_rbl_bitline_names(self, port=None):
""" Return the BL for the given RBL port """ """ Return the BL for the given RBL port """
if port == None: if port == None:
temp = [] return self.all_rbl_bitline_names
for port in self.all_ports:
temp.extend(self.replica_bitline_names[port])
return temp
else: else:
bl_names = self.replica_bitline_names[port] return self.rbl_bitline_names[port]
return bl_names[2 * port:2 * port + 2]
def get_wordline_names(self): def get_bitline_names(self, port=None):
""" Return the wordline names """ """ Return the regular bitlines for the given port or all"""
return self.wordline_names 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): def get_wordline_names(self, port=None):
""" Return the bitline names """ """ Return the regular wordline names """
return self.bitline_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): def analytical_power(self, corner, load):
"""Power of Bitcell array and bitline in nW.""" """Power of Bitcell array and bitline in nW."""
# Dynamic Power from Bitline # Dynamic Power from Bitline

View File

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

View File

@ -260,6 +260,8 @@ class sram_1bank(sram_base):
for signal in self.control_logic_inputs[port]: for signal in self.control_logic_inputs[port]:
if signal == "clk": if signal == "clk":
continue continue
if signal.startswith("rbl"):
continue
if OPTS.perimeter_pins: if OPTS.perimeter_pins:
self.add_perimeter_pin(name=signal + "{}".format(port), self.add_perimeter_pin(name=signal + "{}".format(port),
pin=self.control_logic_insts[port].get_pin(signal), pin=self.control_logic_insts[port].get_pin(signal),
@ -554,7 +556,7 @@ class sram_1bank(sram_base):
for port in self.all_ports: for port in self.all_ports:
# Only input (besides pins) is the replica bitline # Only input (besides pins) is the replica bitline
src_pin = self.control_logic_insts[port].get_pin("rbl_bl") 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], self.add_wire(self.m2_stack[::-1],
[src_pin.center(), vector(src_pin.cx(), dest_pin.cy()), dest_pin.rc()]) [src_pin.center(), vector(src_pin.cx(), dest_pin.cy()), dest_pin.rc()])
self.add_via_stack_center(from_layer=src_pin.layer, 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 These should probably be turned off by default though, since extraction
will show these as ports in the extracted netlist. will show these as ports in the extracted netlist.
""" """
return
for n in self.control_logic_outputs[0]: for n in self.control_logic_outputs[0]:
pin = self.control_logic_insts[0].get_pin(n) pin = self.control_logic_insts[0].get_pin(n)
self.add_label(text=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)) temp.append("dout{0}[{1}]".format(port, bit))
for port in self.all_ports: for port in self.all_ports:
temp.append("rbl_bl{0}".format(port)) temp.append("rbl_bl{0}".format(port))
temp.append("rbl_br{0}".format(port))
for port in self.write_ports: for port in self.write_ports:
for bit in range(self.word_size + self.num_spare_cols): for bit in range(self.word_size + self.num_spare_cols):
temp.append("bank_din{0}[{1}]".format(port, bit)) 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", a = factory.create(module_type="replica_bitcell_array",
cols=4, cols=4,
rows=4, rows=4,
left_rbl=1, rbl=[1, 1],
right_rbl=1, add_rbl=[0, 0])
bitcell_ports=[0, 1],
add_replica=False)
self.local_check(a) 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", a = factory.create(module_type="replica_bitcell_array",
cols=4, cols=4,
rows=4, rows=4,
left_rbl=1, rbl=[1, 1],
right_rbl=1, add_rbl=[1, 0])
bitcell_ports=[0, 1]) 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) self.local_check(a)
# Sky 130 has restrictions on the symmetries # Sky 130 has restrictions on the symmetries
if OPTS.tech_name != "sky130": 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", a = factory.create(module_type="replica_bitcell_array",
cols=4, cols=4,
rows=4, rows=4,
left_rbl=2, rbl=[1, 1],
right_rbl=0, add_rbl=[0, 1])
bitcell_ports=[0, 1])
self.local_check(a) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -25,7 +25,7 @@ class replica_bitcell_array_test(openram_test):
factory.reset() factory.reset()
debug.info(2, "Testing 4x4 array for bitcell") 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) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -25,15 +25,15 @@ class replica_column_test(openram_test):
globals.setup_bitcell() globals.setup_bitcell()
debug.info(2, "Testing replica column for 6t_cell") 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) self.local_check(a)
debug.info(2, "Testing replica column for 6t_cell") 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) self.local_check(a)
debug.info(2, "Testing replica column for 6t_cell") 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) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -20,15 +20,15 @@ class replica_column_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
debug.info(2, "Testing replica column for 6t_cell") 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) self.local_check(a)
debug.info(2, "Testing replica column for 6t_cell") 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) self.local_check(a)
debug.info(2, "Testing replica column for 6t_cell") 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) self.local_check(a)
globals.end_openram() globals.end_openram()

View File

@ -27,7 +27,7 @@ class replica_pbitcell_array_test(openram_test):
OPTS.num_w_ports = 0 OPTS.num_w_ports = 0
debug.info(2, "Testing 4x4 array for pbitcell") 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) self.local_check(a)
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
@ -39,7 +39,7 @@ class replica_pbitcell_array_test(openram_test):
factory.reset() factory.reset()
debug.info(2, "Testing 4x4 array for pbitcell") 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) self.local_check(a)
globals.end_openram() 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 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): class local_bitcell_array_test(openram_test):
def runTest(self): def runTest(self):
@ -23,13 +23,13 @@ class local_bitcell_array_test(openram_test):
globals.init_openram(config_file) globals.init_openram(config_file)
debug.info(2, "Testing 4x4 local bitcell array for 6t_cell without replica") 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) self.local_check(a)
debug.info(2, "Testing 4x4 local bitcell array for 6t_cell with replica column") 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) self.local_check(a)
globals.end_openram() 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("{} -noconsole << EOF\n".format(OPTS.lvs_exe[1]))
f.write("readnet spice {0}.spice\n".format(cell_name)) f.write("readnet spice {0}.spice\n".format(cell_name))
f.write("readnet spice {0}.sp\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("quit\n")
f.write("EOF\n") f.write("EOF\n")
f.close() f.close()