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) self.translate_all(offset)
return 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): def get_gate_offset(self, x_offset, height, inv_num):
""" """
Gets the base offset and y orientation of stacked rows of gates 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 # UPPER LEFT QUADRANT
# To the left of the bitcell array above the predecoders and control logic # 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.port_address_offsets[port] = vector(-x_offset,
self.main_bitcell_array_bottom) 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 # LOWER LEFT QUADRANT
# Place the col decoder left aligned with wordline driver # 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 # 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 # by placing 1 1/4 a cell pitch down because both power connections and inputs/outputs
# may be routed in M3 or M4 # 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: if self.col_addr_size > 0:
x_offset += self.column_decoder.width + self.col_addr_bus_width x_offset += self.column_decoder.width + self.col_addr_bus_width
y_offset = 1.25 * self.dff.height + self.column_decoder.height y_offset = 1.25 * self.dff.height + self.column_decoder.height
@ -267,7 +267,7 @@ class bank(design.design):
# LOWER RIGHT QUADRANT # LOWER RIGHT QUADRANT
# To the right of the bitcell array # 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.port_address_offsets[port] = vector(x_offset,
self.main_bitcell_array_bottom) 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 # 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 # by placing 1 1/4 a cell pitch down because both power connections and inputs/outputs
# may be routed in M3 or M4 # 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: if self.col_addr_size > 0:
x_offset += self.column_decoder.width + self.col_addr_bus_width 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 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): def add_modules(self):
""" Add all the modules using the class loader """ """ Add all the modules using the class loader """
self.port_address = factory.create(module_type="port_address", self.port_address = []
cols=self.num_cols + self.num_spare_cols, for port in self.all_ports:
rows=self.num_rows) self.port_address.append(factory.create(module_type="port_address",
self.add_mod(self.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) self.num_rbl = len(self.all_ports)
@ -420,13 +423,10 @@ class bank(design.design):
# gnd # gnd
temp = self.bitcell_array.get_inouts() temp = self.bitcell_array.get_inouts()
wordline_names = self.bitcell_array.get_inputs() temp.append("rbl_wl0")
temp.extend(self.bitcell_array.get_wordline_names())
# Rename the RBL WL to the enable name if len(self.all_ports) > 1:
for port in self.all_ports: temp.append("rbl_wl1")
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("vdd") temp.append("vdd")
temp.append("gnd") temp.append("gnd")
@ -486,13 +486,15 @@ class bank(design.design):
self.port_address_inst = [None] * len(self.all_ports) self.port_address_inst = [None] * len(self.all_ports)
for port in self.all_ports: for port in self.all_ports:
self.port_address_inst[port] = self.add_inst(name="port_address{}".format(port), self.port_address_inst[port] = self.add_inst(name="port_address{}".format(port),
mod=self.port_address) mod=self.port_address[port])
temp = [] temp = []
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))
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"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) self.connect_inst(temp)
@ -852,8 +854,9 @@ 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 """
driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] + ["rbl_wl"]
for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port)): 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. # 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_pin = self.port_address_inst[port].get_pin(driver_name)
driver_wl_pos = driver_wl_pin.rc() driver_wl_pos = driver_wl_pin.rc()
@ -1021,10 +1024,6 @@ class bank(design.design):
connection.append((self.prefix + "p_en_bar{}".format(port), connection.append((self.prefix + "p_en_bar{}".format(port),
self.port_data_inst[port].get_pin("p_en_bar"))) 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: if port in self.write_ports:
connection.append((self.prefix + "w_en{}".format(port), connection.append((self.prefix + "w_en{}".format(port),
self.port_data_inst[port].get_pin("w_en"))) self.port_data_inst[port].get_pin("w_en")))

View File

@ -54,6 +54,8 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
""" Add the modules used in this design """ """ Add the modules used in this design """
self.local_mods = [] 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: if len(self.column_sizes) == 1:
la = factory.create(module_type="local_bitcell_array", la = factory.create(module_type="local_bitcell_array",
rows=self.row_size, rows=self.row_size,
@ -66,19 +68,21 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
return return
for i, cols in enumerate(self.column_sizes): 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: if i == 0:
la = factory.create(module_type="local_bitcell_array", la = factory.create(module_type="local_bitcell_array",
rows=self.row_size, rows=self.row_size,
cols=cols, cols=cols,
rbl=self.rbl, rbl=self.rbl,
left_rbl=[0]) left_rbl=[0])
# Add the right RBL to the last subarray
elif i == len(self.column_sizes) - 1 and len(self.all_ports) > 1: elif i == len(self.column_sizes) - 1 and len(self.all_ports) > 1:
la = factory.create(module_type="local_bitcell_array", la = factory.create(module_type="local_bitcell_array",
rows=self.row_size, rows=self.row_size,
cols=cols, cols=cols,
rbl=self.rbl, rbl=self.rbl,
right_rbl=[1]) right_rbl=[1])
# Middle subarrays do not have any RBLs
else: else:
la = factory.create(module_type="local_bitcell_array", la = factory.create(module_type="local_bitcell_array",
rows=self.row_size, rows=self.row_size,

View File

@ -55,9 +55,9 @@ class hierarchical_decoder(design.design):
self.route_decoder_bus() self.route_decoder_bus()
self.route_vdd_gnd() 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.add_boundary()
self.DRC_LVS() self.DRC_LVS()

View File

@ -17,10 +17,11 @@ class port_address(design.design):
Create the address port (row decoder and wordline driver).. 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_cols = cols
self.num_rows = rows self.num_rows = rows
self.port = port
self.addr_size = ceil(log(self.num_rows, 2)) self.addr_size = ceil(log(self.num_rows, 2))
if name == "": if name == "":
@ -39,6 +40,7 @@ class port_address(design.design):
self.add_modules() self.add_modules()
self.create_row_decoder() self.create_row_decoder()
self.create_wordline_driver() self.create_wordline_driver()
self.create_rbl_driver()
def create_layout(self): def create_layout(self):
if "li" in layer: if "li" in layer:
@ -60,6 +62,8 @@ class port_address(design.design):
for bit in range(self.num_rows): for bit in range(self.num_rows):
self.add_pin("wl_{0}".format(bit), "OUTPUT") self.add_pin("wl_{0}".format(bit), "OUTPUT")
self.add_pin("rbl_wl", "OUTPUT")
self.add_pin("vdd", "POWER") self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
@ -71,10 +75,12 @@ class port_address(design.design):
def route_supplies(self): def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """ """ 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, "vdd")
self.copy_power_pins(inst, "gnd") self.copy_power_pins(inst, "gnd")
self.copy_power_pins(self.rbl_driver_inst, "vdd")
def route_pins(self): def route_pins(self):
for row in range(self.addr_size): for row in range(self.addr_size):
decoder_name = "addr_{}".format(row) decoder_name = "addr_{}".format(row)
@ -82,16 +88,16 @@ class port_address(design.design):
for row in range(self.num_rows): for row in range(self.num_rows):
driver_name = "wl_{}".format(row) 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): def route_internal(self):
for row in range(self.num_rows): for row in range(self.num_rows):
# The pre/post is to access the pin from "outside" the cell to avoid DRCs # 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_pin = self.row_decoder_inst.get_pin("decode_{}".format(row))
decoder_out_pos = decoder_out_pin.rc() 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() driver_in_pos = driver_in_pin.lc()
self.add_zjog(self.route_layer, decoder_out_pos, driver_in_pos, var_offset=0.3) self.add_zjog(self.route_layer, decoder_out_pos, driver_in_pos, var_offset=0.3)
@ -103,16 +109,53 @@ class port_address(design.design):
to_layer=self.route_layer, to_layer=self.route_layer,
offset=driver_in_pos) 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): def add_modules(self):
self.row_decoder = factory.create(module_type="decoder", self.row_decoder = factory.create(module_type="decoder",
num_outputs=self.num_rows) num_outputs=self.num_rows)
self.add_mod(self.row_decoder) self.add_mod(self.row_decoder)
self.wordline_driver = factory.create(module_type="wordline_driver_array", self.wordline_driver_array = factory.create(module_type="wordline_driver_array",
rows=self.num_rows, rows=self.num_rows,
cols=self.num_cols) cols=self.num_cols)
self.add_mod(self.wordline_driver) 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): def create_row_decoder(self):
""" Create the hierarchical row decoder """ """ Create the hierarchical row decoder """
@ -128,11 +171,24 @@ class port_address(design.design):
temp.extend(["vdd", "gnd"]) temp.extend(["vdd", "gnd"])
self.connect_inst(temp) 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): def create_wordline_driver(self):
""" Create the Wordline Driver """ """ Create the Wordline Driver """
self.wordline_driver_inst = self.add_inst(name="wordline_driver", self.wordline_driver_array_inst = self.add_inst(name="wordline_driver",
mod=self.wordline_driver) mod=self.wordline_driver_array)
temp = [] temp = []
for row in range(self.num_rows): for row in range(self.num_rows):
@ -150,11 +206,23 @@ class port_address(design.design):
""" """
row_decoder_offset = vector(0, 0) 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) 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 # Pass this up
self.predecoder_height = self.row_decoder.predecoder_height self.predecoder_height = self.row_decoder.predecoder_height
self.height = self.row_decoder.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): def place_drivers(self):
for row in range(self.rows): for row in range(self.rows):
# These are flipped since we always start with an RBL on the bottom
if (row % 2): if (row % 2):
y_offset = self.wl_driver.height * (row + 1)
inst_mirror = "MX"
else:
y_offset = self.wl_driver.height * row y_offset = self.wl_driver.height * row
inst_mirror = "R0" inst_mirror = "R0"
else:
y_offset = self.wl_driver.height * (row + 1)
inst_mirror = "MX"
offset = [0, y_offset] offset = [0, y_offset]

View File

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

View File

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

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. This is an AND (or NAND) with configurable drive strength to drive the wordlines.
It is matched to the bitcell height. 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)) debug.info(1, "Creating wordline_driver {}".format(name))
self.add_comment("size: {}".format(size)) self.add_comment("cols: {}".format(cols))
super().__init__(name) super().__init__(name)
if height is None: if height is None:
@ -28,7 +28,7 @@ class wordline_driver(design.design):
self.height = b.height self.height = b.height
else: else:
self.height = height self.height = height
self.size = size self.cols = cols
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -43,9 +43,24 @@ class wordline_driver(design.design):
self.nand = factory.create(module_type="nand2_dec", self.nand = factory.create(module_type="nand2_dec",
height=self.height) height=self.height)
self.driver = factory.create(module_type="inv_dec", try:
size=self.size, local_array_size = OPTS.local_array_size
height=self.nand.height) 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.nand)
self.add_mod(self.driver) self.add_mod(self.driver)