Merge branch 'wlbuffer' into dev

This commit is contained in:
mrg 2020-08-25 15:50:08 -07:00
commit 652f160aca
14 changed files with 678 additions and 431 deletions

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",
@ -393,28 +386,41 @@ 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 = []
for port in self.all_ports:
rbl_wl_names.append(self.bitcell_array.get_rbl_wordline_names(port)) temp.extend(self.bitcell_array.get_dummy_bitline_names(0))
temp.extend(self.bitcell_array.get_rbl_bitline_names(0))
temp.extend(self.bitcell_array.get_bitline_names())
if len(self.all_ports) > 1:
temp.extend(self.bitcell_array.get_rbl_bitline_names(1))
temp.extend(self.bitcell_array.get_dummy_bitline_names(1))
wordline_names = self.bitcell_array.get_dummy_wordline_names(0)
wordline_names.extend(self.bitcell_array.get_rbl_wordline_names(0))
wordline_names.extend(self.bitcell_array.get_wordline_names())
if len(self.all_ports) > 1:
wordline_names.extend(self.bitcell_array.get_rbl_wordline_names(1))
wordline_names.extend(self.bitcell_array.get_dummy_wordline_names(1))
# 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):
@ -423,17 +429,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))
@ -478,8 +482,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)
@ -697,27 +700,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.mod.get_bl_names() + "_{}" inst2_bl_name = []
inst2_br_name = inst2.mod.get_br_names() + "_{}" 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))
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)
@ -816,16 +820,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 """
@ -840,11 +844,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)
@ -857,11 +862,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)
@ -922,26 +928,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.
""" """
# Add the wordline names
for i in range(self.num_rows):
wl_name = "wl_{}".format(i)
wl_pin = self.bitcell_array_inst.get_pin(wl_name)
self.add_label(text=wl_name,
layer="m1",
offset=wl_pin.center())
# Add the bitline names for pin_name in self.bitcell_array.get_all_bitline_names():
for i in range(self.num_cols): self.copy_layout_pin(self.bitcell_array, pin_name)
bl_name = "bl_{}".format(i) # Add the wordline names
br_name = "br_{}".format(i) # for i in range(self.num_rows):
bl_pin = self.bitcell_array_inst.get_pin(bl_name) # wl_name = "wl_{}".format(i)
br_pin = self.bitcell_array_inst.get_pin(br_name) # wl_pin = self.bitcell_array_inst.get_pin(wl_name)
self.add_label(text=bl_name, # self.add_label(text=wl_name,
layer="m2", # layer="m1",
offset=bl_pin.center()) # offset=wl_pin.center())
self.add_label(text=br_name,
layer="m2", # # Add the bitline names
offset=br_pin.center()) # for i in range(self.num_cols):
# bl_name = "bl_{}".format(i)
# br_name = "br_{}".format(i)
# bl_pin = self.bitcell_array_inst.get_pin(bl_name)
# br_pin = self.bitcell_array_inst.get_pin(br_name)
# self.add_label(text=bl_name,
# layer="m2",
# offset=bl_pin.center())
# self.add_label(text=br_name,
# layer="m2",
# offset=br_pin.center())
# # Add the data output names to the sense amp output # # Add the data output names to the sense amp output
# for i in range(self.word_size): # for i in range(self.word_size):
@ -952,24 +961,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:
@ -1002,7 +1014,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,24 +5,34 @@
# (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):
class global_bitcell_array(design.design):
""" """
Creates a global bitcell array with a number Creates a global bitcell array.
of local arrays of a sizes given by a tuple in the list. 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, add_replica, name=""): def __init__(self, rows, cols, ports, name=""):
# The total of all columns will be the number of columns # The total of all columns will be the number of columns
self.cols = sum(cols) super().__init__(name=name)
self.local_cols = cols self.cols = cols
self.rows = rows self.rows = rows
self.sizes = sizes self.all_ports = ports
super().__init__(rows=self.rows, cols=self.cols, name=name)
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:
@ -47,24 +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 i, col in enumerate(self.local_cols):
if i==self.add_replica[0]:
la = factory.create(module_type="local_bitcell_array", rows=row, cols=col, left_rbl=i, add_replica=True)
elif len(self.add_replica)==2 and i==self.add_replica[2]:
la = factory.create(module_type="local_bitcell_array", rows=row, cols=col, left_rbl=i, add_replica=True)
else:
la = factory.create(module_type="local_bitcell_array", rows=row, cols=col, add_replica=False)
self.add_mod(la) for i, cols in enumerate(self.cols):
# Always add the left RBLs to the first subarray and the right RBLs to the last subarray
if i == 0:
la = factory.create(module_type="local_bitcell_array", rows=self.rows, cols=cols, rbl=self.rbl, add_rbl=[self.left_rbl, 0])
elif i == len(self.cols) - 1:
la = factory.create(module_type="local_bitcell_array", rows=self.rows, cols=cols, rbl=self.rbl, add_rbl=[0, self.right_rbl])
else:
la = factory.create(module_type="local_bitcell_array", rows=self.rows, cols=cols, rbl=self.rbl, add_rbl=[0, 0])
self.add_mod(la)
self.local_mods.append(la) 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

@ -9,7 +9,6 @@ import bitcell_base_array
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(bitcell_base_array.bitcell_base_array):
@ -20,14 +19,17 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
""" """
def __init__(self, rows, cols, rbl, add_rbl=None, name=""): def __init__(self, rows, cols, rbl, add_rbl=None, name=""):
super().__init__(name, rows, cols, 0) super().__init__(name, rows, cols, 0)
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 + sum(rbl)))
self.rows = rows self.rows = rows
self.cols = cols self.cols = cols
self.rbl = rbl self.rbl = rbl
if add_rbl == None: if add_rbl == None:
self.add_rbl = rbl 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:
@ -63,64 +65,100 @@ 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,
rbl=self.rbl) rbl=self.rbl,
add_rbl=self.add_rbl)
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() self.wordline_names = []
self.add_pin_list(self.bitline_names, "INOUT") self.driver_wordline_outputs = []
self.driver_wordline_inputs = [x for x in self.bitcell_array.get_all_wordline_names() if not x.startswith("dummy")] self.array_wordline_inputs = []
self.driver_wordline_outputs = [x + "i" for x in self.driver_wordline_inputs]
self.array_wordline_inputs = [x + "i" if not x.startswith("dummy") else "gnd" for x in self.bitcell_array.get_all_wordline_names()] # Port 0
self.add_pin_list(self.wordline_names, "INPUT") wordline_inputs = [x for x in self.bitcell_array.get_wordline_names(0) if not x.startswith("dummy")]
if len(self.all_ports) > 1:
# Drop off the RBL for port 1
self.wordline_names.append(wordline_inputs[:-1])
else:
self.wordline_names.append(wordline_inputs)
self.driver_wordline_outputs.append([x + "i" for x in self.wordline_names[-1]])
self.array_wordline_inputs.append([x + "i" if not x.startswith("dummy") else "gnd" for x in self.bitcell_array.get_wordline_names(0)])
# Port 1
if len(self.all_ports) > 1:
self.wordline_names.append([x for x in self.bitcell_array.get_wordline_names(1) if not x.startswith("dummy")][1:])
self.driver_wordline_outputs.append([x + "i" for x in self.wordline_names[-1]])
self.array_wordline_inputs.append([x + "i" if not x.startswith("dummy") else "gnd" for x in self.bitcell_array.get_wordline_names(1)])
self.all_driver_wordline_inputs = [x for x in self.bitcell_array.get_wordline_names() if not x.startswith("dummy")]
self.replica_names = self.bitcell_array.get_rbl_wordline_names() self.replica_names = self.bitcell_array.get_rbl_wordline_names()
self.add_pin_list(self.replica_names, "INPUT")
self.bitline_names = self.bitcell_array.get_inouts() 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([self.bitcell_array.get_rbl_wordline_names(x) for x in self.all_ports])
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_wordline_names()]
self.bitline_names = self.bitcell_array.bitline_names
# Arrays are always:
# word lines (bottom to top)
# bit lines (left to right)
# vdd
# gnd
for port in self.all_ports:
self.add_pin_list(self.wordline_names[port], "INPUT")
for port in self.all_ports:
self.add_pin_list(self.bitline_names[port], "INOUT")
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_wordline_inputs + self.bitline_names + ["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))
@ -142,10 +180,11 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
for (x, y) in zip(self.bitline_names, self.bitcell_array.get_inouts()): for (x, y) in zip(self.bitline_names, self.bitcell_array.get_inouts()):
self.copy_layout_pin(self.bitcell_array_inst, y, x) self.copy_layout_pin(self.bitcell_array_inst, y, x)
for (x, y) in zip(self.driver_wordline_inputs, self.wl_array.get_inputs()): for port in self.all_ports:
self.copy_layout_pin(self.wl_inst, y, x) for (x, y) in zip(self.wordline_names[port], self.wl_array.get_inputs()):
self.copy_layout_pin(self.wl_insts[port], y, x)
supply_insts = [self.wl_inst, self.bitcell_array_inst] supply_insts = [*self.wl_insts, self.bitcell_array_inst]
for pin_name in ["vdd", "gnd"]: for 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)
@ -155,12 +194,28 @@ 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) if port == 0:
in_pin = self.bitcell_array_inst.get_pin(array_name) array_names = [x for x in self.bitcell_array.get_wordline_names(port) if not x.startswith("dummy")]
mid_loc = self.wl_inst.rx() + 1.5 * self.m3_pitch if len(self.all_ports) > 1:
self.add_path(out_pin.layer, [out_pin.rc(), vector(mid_loc, out_pin.cy()), in_pin.lc()]) # Drop off the RBL for port 1
array_names = array_names[:-1]
else:
array_names = [x for x in self.bitcell_array.get_wordline_names(port) if not x.startswith("dummy")][1:]
for (driver_name, array_name) in zip(self.wl_array.get_outputs(), array_names):
out_pin = self.wl_insts[port].get_pin(driver_name)
in_pin = self.bitcell_array_inst.get_pin(array_name)
if port == 0:
out_loc = out_pin.rc()
mid_loc = vector(self.wl_insts[port].rx() + 1.5 * self.m3_pitch, out_loc.y)
in_loc = in_pin.lc()
else:
out_loc = out_pin.lc()
mid_loc = vector(self.wl_insts[port].lx() - 1.5 * self.m3_pitch, out_loc.y)
in_loc = in_pin.rc()
self.add_path(out_pin.layer, [out_loc, mid_loc, in_loc])
self.route_unused_wordlines() 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):

View File

@ -164,101 +164,103 @@ 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.all_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]
self.dummy_row_wordline_names.append(wordline_names)
self.all_dummy_row_wordline_names = [x for sl in self.dummy_row_wordline_names for x in sl]
# These are the non-indexed names
dummy_cell_wl_names = ["dummy_" + x for x in self.cell.get_all_wl_names()]
# Create the full WL names include dummy, replica, and regular bit cells
self.wordline_names = []
self.dummy_wordline_names["bot"] = ["{0}_bot".format(x) for x in dummy_cell_wl_names]
self.wordline_names.extend(self.dummy_wordline_names["bot"])
# Left port WLs
for port in range(self.left_rbl):
# Make names for all RBLs
wl_names=["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()]
# Keep track of the pin that is the RBL
self.replica_wordline_names[port] = wl_names
self.wordline_names.extend(wl_names)
# Regular WLs
self.wordline_names.extend(self.bitcell_array_wordline_names)
# Right port WLs
for port in range(self.left_rbl, self.left_rbl + self.right_rbl):
# Make names for all RBLs
wl_names=["rbl_{0}_{1}".format(x, port) for x in self.cell.get_all_wl_names()]
# Keep track of the pin that is the RBL
self.replica_wordline_names[port] = wl_names
self.wordline_names.extend(wl_names)
self.dummy_wordline_names["top"] = ["{0}_top".format(x) for x in dummy_cell_wl_names]
self.wordline_names.extend(self.dummy_wordline_names["top"])
# 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]
self.add_pin_list(self.wordline_names, "INPUT") 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)
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")
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """
@ -271,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):
@ -338,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):
@ -363,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),
@ -419,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),
@ -429,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(),
@ -446,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)
@ -457,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):
@ -466,32 +459,39 @@ 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 BL for the given RBL port """
return self.wordline_names if port == None:
return self.all_bitline_names
else:
return self.bitline_names[port]
def get_bitline_names(self): def get_dummy_wordline_names(self, port=None):
""" Return the bitline names """ """
return self.bitline_names 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."""

View File

@ -60,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")
@ -153,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(),
@ -173,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,
@ -190,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")
@ -210,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

@ -32,7 +32,15 @@ class replica_bitcell_array_1rw_1r_test(openram_test):
add_rbl=[0, 0]) add_rbl=[0, 0])
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",
cols=4,
rows=4,
rbl=[1, 1],
add_rbl=[1, 0])
self.local_check(a)
debug.info(2, "Testing 4x4 array left and right replica for cell_1rw_1r")
a = factory.create(module_type="replica_bitcell_array", a = factory.create(module_type="replica_bitcell_array",
cols=4, cols=4,
rows=4, rows=4,
@ -42,11 +50,12 @@ class replica_bitcell_array_1rw_1r_test(openram_test):
# 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,
rbl=[2, 0]) rbl=[1, 1],
add_rbl=[0, 1])
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,46 @@
#!/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=[0, 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):

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()