Create RBL wordline buffer with correct polarity.

This commit is contained in:
mrg 2020-09-17 14:45:49 -07:00
parent 392afd4d4b
commit c7d32089f3
10 changed files with 156 additions and 56 deletions

View File

@ -63,6 +63,16 @@ class layout():
self.translate_all(offset)
return offset
def offset_x_coordinates(self):
"""
This function is called after everything is placed to
shift the origin to the furthest left point.
Y offset is unchanged.
"""
offset = self.find_lowest_coords()
self.translate_all(offset.scale(1, 0))
return offset
def get_gate_offset(self, x_offset, height, inv_num):
"""
Gets the base offset and y orientation of stacked rows of gates

View File

@ -223,10 +223,10 @@ class bank(design.design):
# UPPER LEFT QUADRANT
# To the left of the bitcell array above the predecoders and control logic
x_offset = self.m2_gap + self.port_address.width
x_offset = self.m2_gap + self.port_address[port].width
self.port_address_offsets[port] = vector(-x_offset,
self.main_bitcell_array_bottom)
self.predecoder_height = self.port_address.predecoder_height + self.port_address_offsets[port].y
self.predecoder_height = self.port_address[port].predecoder_height + self.port_address_offsets[port].y
# LOWER LEFT QUADRANT
# Place the col decoder left aligned with wordline driver
@ -234,7 +234,7 @@ class bank(design.design):
# control logic to allow control signals to easily pass over in M3
# by placing 1 1/4 a cell pitch down because both power connections and inputs/outputs
# may be routed in M3 or M4
x_offset = self.central_bus_width[port] + self.port_address.wordline_driver.width
x_offset = self.central_bus_width[port] + self.port_address[port].wordline_driver_array.width
if self.col_addr_size > 0:
x_offset += self.column_decoder.width + self.col_addr_bus_width
y_offset = 1.25 * self.dff.height + self.column_decoder.height
@ -267,7 +267,7 @@ class bank(design.design):
# LOWER RIGHT QUADRANT
# To the right of the bitcell array
x_offset = self.bitcell_array_right + self.port_address.width + self.m2_gap
x_offset = self.bitcell_array_right + self.port_address[port].width + self.m2_gap
self.port_address_offsets[port] = vector(x_offset,
self.main_bitcell_array_bottom)
@ -278,7 +278,7 @@ class bank(design.design):
# control logic to allow control signals to easily pass over in M3
# by placing 1 1/4 a cell pitch down because both power connections and inputs/outputs
# may be routed in M3 or M4
x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.port_address.wordline_driver.width
x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.port_address[port].wordline_driver_array.width
if self.col_addr_size > 0:
x_offset += self.column_decoder.width + self.col_addr_bus_width
y_offset = self.bitcell_array_top + 1.25 * self.dff.height + self.column_decoder.height
@ -366,10 +366,13 @@ class bank(design.design):
def add_modules(self):
""" Add all the modules using the class loader """
self.port_address = factory.create(module_type="port_address",
cols=self.num_cols + self.num_spare_cols,
rows=self.num_rows)
self.add_mod(self.port_address)
self.port_address = []
for port in self.all_ports:
self.port_address.append(factory.create(module_type="port_address",
cols=self.num_cols + self.num_spare_cols,
rows=self.num_rows,
port=port))
self.add_mod(self.port_address[port])
self.num_rbl = len(self.all_ports)
@ -420,13 +423,10 @@ class bank(design.design):
# gnd
temp = self.bitcell_array.get_inouts()
wordline_names = self.bitcell_array.get_inputs()
# Rename the RBL WL to the enable name
for port in self.all_ports:
rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)[port]
wordline_names = [x.replace(rbl_wl_name, "wl_en{0}".format(port)) for x in wordline_names]
temp.extend(wordline_names)
temp.append("rbl_wl0")
temp.extend(self.bitcell_array.get_wordline_names())
if len(self.all_ports) > 1:
temp.append("rbl_wl1")
temp.append("vdd")
temp.append("gnd")
@ -486,13 +486,15 @@ class bank(design.design):
self.port_address_inst = [None] * len(self.all_ports)
for port in self.all_ports:
self.port_address_inst[port] = self.add_inst(name="port_address{}".format(port),
mod=self.port_address)
mod=self.port_address[port])
temp = []
for bit in range(self.row_addr_size):
temp.append("addr{0}_{1}".format(port, bit + self.col_addr_size))
temp.append("wl_en{}".format(port))
temp.extend(self.bitcell_array.get_wordline_names(port))
wordline_names = self.bitcell_array.get_wordline_names(port)
temp.extend(wordline_names)
temp.append("rbl_wl{}".format(port))
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
@ -852,8 +854,9 @@ class bank(design.design):
def route_port_address_left(self, port):
""" Connecting Wordline driver output to Bitcell WL connection """
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)):
driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] + ["rbl_wl"]
rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)[port]
for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port) + [rbl_wl_name]):
# The mid guarantees we exit the input cell to the right.
driver_wl_pin = self.port_address_inst[port].get_pin(driver_name)
driver_wl_pos = driver_wl_pin.rc()
@ -1021,10 +1024,6 @@ class bank(design.design):
connection.append((self.prefix + "p_en_bar{}".format(port),
self.port_data_inst[port].get_pin("p_en_bar")))
rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)
connection.append((self.prefix + "wl_en{}".format(port),
self.bitcell_array_inst.get_pin(rbl_wl_name[port])))
if port in self.write_ports:
connection.append((self.prefix + "w_en{}".format(port),
self.port_data_inst[port].get_pin("w_en")))
@ -1045,7 +1044,7 @@ class bank(design.design):
self.add_via_stack_center(from_layer=pin.layer,
to_layer="m2",
offset=control_pos)
# clk to wordline_driver
control_signal = self.prefix + "wl_en{}".format(port)
if port % 2:

View File

@ -54,6 +54,8 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
""" Add the modules used in this design """
self.local_mods = []
# Special case of a single local array
# so it should contain the left and possibly right RBL
if len(self.column_sizes) == 1:
la = factory.create(module_type="local_bitcell_array",
rows=self.row_size,
@ -66,19 +68,21 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
return
for i, cols in enumerate(self.column_sizes):
# Always add the left RBLs to the first subarray and the right RBLs to the last subarray
# Always add the left RBLs to the first subarray
if i == 0:
la = factory.create(module_type="local_bitcell_array",
rows=self.row_size,
cols=cols,
rbl=self.rbl,
left_rbl=[0])
# Add the right RBL to the last subarray
elif i == len(self.column_sizes) - 1 and len(self.all_ports) > 1:
la = factory.create(module_type="local_bitcell_array",
rows=self.row_size,
cols=cols,
rbl=self.rbl,
right_rbl=[1])
# Middle subarrays do not have any RBLs
else:
la = factory.create(module_type="local_bitcell_array",
rows=self.row_size,

View File

@ -55,9 +55,9 @@ class hierarchical_decoder(design.design):
self.route_decoder_bus()
self.route_vdd_gnd()
self.offset_all_coordinates()
self.offset_x_coordinates()
self.width = self.and_inst[0].rx() + self.m1_space
self.width = self.and_inst[0].rx() + 0.5 * self.m1_width
self.add_boundary()
self.DRC_LVS()

View File

@ -17,10 +17,11 @@ class port_address(design.design):
Create the address port (row decoder and wordline driver)..
"""
def __init__(self, cols, rows, name=""):
def __init__(self, cols, rows, port, name=""):
self.num_cols = cols
self.num_rows = rows
self.port = port
self.addr_size = ceil(log(self.num_rows, 2))
if name == "":
@ -39,6 +40,7 @@ class port_address(design.design):
self.add_modules()
self.create_row_decoder()
self.create_wordline_driver()
self.create_rbl_driver()
def create_layout(self):
if "li" in layer:
@ -59,6 +61,8 @@ class port_address(design.design):
for bit in range(self.num_rows):
self.add_pin("wl_{0}".format(bit), "OUTPUT")
self.add_pin("rbl_wl", "OUTPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
@ -71,10 +75,12 @@ class port_address(design.design):
def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
for inst in self.insts:
for inst in [self.wordline_driver_array_inst, self.row_decoder_inst]:
self.copy_power_pins(inst, "vdd")
self.copy_power_pins(inst, "gnd")
self.copy_power_pins(self.rbl_driver_inst, "vdd")
def route_pins(self):
for row in range(self.addr_size):
decoder_name = "addr_{}".format(row)
@ -82,16 +88,16 @@ class port_address(design.design):
for row in range(self.num_rows):
driver_name = "wl_{}".format(row)
self.copy_layout_pin(self.wordline_driver_inst, driver_name)
self.copy_layout_pin(self.wordline_driver_array_inst, driver_name)
self.copy_layout_pin(self.wordline_driver_inst, "en", "wl_en")
self.copy_layout_pin(self.rbl_driver_inst, "Z", "rbl_wl")
def route_internal(self):
for row in range(self.num_rows):
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
decoder_out_pin = self.row_decoder_inst.get_pin("decode_{}".format(row))
decoder_out_pos = decoder_out_pin.rc()
driver_in_pin = self.wordline_driver_inst.get_pin("in_{}".format(row))
driver_in_pin = self.wordline_driver_array_inst.get_pin("in_{}".format(row))
driver_in_pos = driver_in_pin.lc()
self.add_zjog(self.route_layer, decoder_out_pos, driver_in_pos, var_offset=0.3)
@ -102,6 +108,20 @@ class port_address(design.design):
self.add_via_stack_center(from_layer=driver_in_pin.layer,
to_layer=self.route_layer,
offset=driver_in_pos)
# Route the RBL from the enable input
en_pin = self.wordline_driver_array_inst.get_pin("en")
rbl_in_pin = self.rbl_driver_inst.get_pin("A")
rbl_in_pos = rbl_in_pin.center()
mid_pos = vector(en_pin.cx(), rbl_in_pin.cy())
self.add_path(rbl_in_pin.layer, [rbl_in_pos, mid_pos])
self.add_via_stack_center(from_layer=rbl_in_pin.layer,
to_layer=en_pin.layer,
offset=mid_pos)
self.add_layout_pin_segment_center(text="wl_en",
layer=en_pin.layer,
start=mid_pos,
end=en_pin.center())
def add_modules(self):
@ -109,10 +129,33 @@ class port_address(design.design):
num_outputs=self.num_rows)
self.add_mod(self.row_decoder)
self.wordline_driver = factory.create(module_type="wordline_driver_array",
rows=self.num_rows,
cols=self.num_cols)
self.add_mod(self.wordline_driver)
self.wordline_driver_array = factory.create(module_type="wordline_driver_array",
rows=self.num_rows,
cols=self.num_cols)
self.add_mod(self.wordline_driver_array)
try:
local_array_size = OPTS.local_array_size
driver_size = int(self.num_cols / local_array_size)
except AttributeError:
local_array_size = 0
# Defautl to FO4
driver_size = int(self.num_cols / 4)
# The polarity must be switched if we have a hierarchical wordline
# to compensate for the local array inverters
b = factory.create(module_type="bitcell")
if local_array_size > 0:
self.rbl_driver = factory.create(module_type="inv_dec",
size=driver_size,
height=b.height)
else:
self.rbl_driver = factory.create(module_type="buf_dec",
size=driver_size,
height=b.height)
self.add_mod(self.rbl_driver)
def create_row_decoder(self):
""" Create the hierarchical row decoder """
@ -128,11 +171,24 @@ class port_address(design.design):
temp.extend(["vdd", "gnd"])
self.connect_inst(temp)
def create_rbl_driver(self):
""" Create the RBL Wordline Driver """
self.rbl_driver_inst = self.add_inst(name="rbl_driver",
mod=self.rbl_driver)
temp = []
temp.append("wl_en")
temp.append("rbl_wl")
temp.append("vdd")
temp.append("gnd")
self.connect_inst(temp)
def create_wordline_driver(self):
""" Create the Wordline Driver """
self.wordline_driver_inst = self.add_inst(name="wordline_driver",
mod=self.wordline_driver)
self.wordline_driver_array_inst = self.add_inst(name="wordline_driver",
mod=self.wordline_driver_array)
temp = []
for row in range(self.num_rows):
@ -150,11 +206,23 @@ class port_address(design.design):
"""
row_decoder_offset = vector(0, 0)
wordline_driver_offset = vector(self.row_decoder.width, 0)
self.wordline_driver_inst.place(wordline_driver_offset)
self.row_decoder_inst.place(row_decoder_offset)
wordline_driver_array_offset = vector(self.row_decoder_inst.rx(), 0)
self.wordline_driver_array_inst.place(wordline_driver_array_offset)
x_offset = self.wordline_driver_array_inst.rx() - self.rbl_driver.width - self.m1_pitch
if self.port == 0:
rbl_driver_offset = vector(x_offset,
0)
self.rbl_driver_inst.place(rbl_driver_offset, "MX")
else:
rbl_driver_offset = vector(x_offset,
self.wordline_driver_array.height)
self.rbl_driver_inst.place(rbl_driver_offset)
# Pass this up
self.predecoder_height = self.row_decoder.predecoder_height
self.height = self.row_decoder.height
self.width = self.wordline_driver_inst.rx()
self.width = self.wordline_driver_array_inst.rx()

View File

@ -109,12 +109,13 @@ class wordline_buffer_array(design.design):
def place_drivers(self):
for row in range(self.rows):
# These are flipped since we always start with an RBL on the bottom
if (row % 2):
y_offset = self.wl_driver.height * (row + 1)
inst_mirror = "MX"
else:
y_offset = self.wl_driver.height * row
inst_mirror = "R0"
else:
y_offset = self.wl_driver.height * (row + 1)
inst_mirror = "MX"
offset = [0, y_offset]

View File

@ -44,7 +44,7 @@ class wordline_driver_array(design.design):
self.place_drivers()
self.route_layout()
self.route_vdd_gnd()
self.offset_all_coordinates()
self.offset_x_coordinates()
self.add_boundary()
self.DRC_LVS()
@ -60,8 +60,10 @@ class wordline_driver_array(design.design):
self.add_pin("gnd", "GROUND")
def add_modules(self):
self.wl_driver = factory.create(module_type="wordline_driver",
size=self.cols)
cols=self.cols)
self.add_mod(self.wl_driver)
def route_vdd_gnd(self):

View File

@ -139,6 +139,7 @@ class options(optparse.Values):
bank_select = "bank_select"
bitcell_array = "bitcell_array"
bitcell = "bitcell"
buf_dec = "pbuf"
column_mux_array = "single_level_column_mux_array"
control_logic = "control_logic"
decoder = "hierarchical_decoder"

View File

@ -96,4 +96,4 @@ class pbuf(pgate.pgate):
offset=a_pin.center(),
width=a_pin.width(),
height=a_pin.height())

View File

@ -18,9 +18,9 @@ class wordline_driver(design.design):
This is an AND (or NAND) with configurable drive strength to drive the wordlines.
It is matched to the bitcell height.
"""
def __init__(self, name, size=1, height=None):
def __init__(self, name, cols=1, height=None):
debug.info(1, "Creating wordline_driver {}".format(name))
self.add_comment("size: {}".format(size))
self.add_comment("cols: {}".format(cols))
super().__init__(name)
if height is None:
@ -28,7 +28,7 @@ class wordline_driver(design.design):
self.height = b.height
else:
self.height = height
self.size = size
self.cols = cols
self.create_netlist()
if not OPTS.netlist_only:
@ -42,10 +42,25 @@ class wordline_driver(design.design):
def create_modules(self):
self.nand = factory.create(module_type="nand2_dec",
height=self.height)
self.driver = factory.create(module_type="inv_dec",
size=self.size,
height=self.nand.height)
try:
local_array_size = OPTS.local_array_size
driver_size = int(self.cols / local_array_size)
except AttributeError:
local_array_size = 0
# Defautl to FO4
driver_size = int(self.cols / 4)
# The polarity must be switched if we have a hierarchical wordline
# to compensate for the local array inverters
if local_array_size > 0:
self.driver = factory.create(module_type="buf_dec",
size=driver_size,
height=self.nand.height)
else:
self.driver = factory.create(module_type="inv_dec",
size=driver_size,
height=self.nand.height)
self.add_mod(self.nand)
self.add_mod(self.driver)