mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'wlbuffer' into dev
This commit is contained in:
commit
4a987bef9a
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,12 +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.num_rbl = len(self.all_ports)
|
||||
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])
|
||||
|
||||
try:
|
||||
local_array_size = OPTS.local_array_size
|
||||
|
|
@ -420,13 +421,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 +484,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)
|
||||
|
||||
|
|
@ -845,35 +845,51 @@ class bank(design.design):
|
|||
self.route_port_address_in(port)
|
||||
|
||||
if port % 2:
|
||||
self.route_port_address_right(port)
|
||||
self.route_port_address_out(port, "right")
|
||||
else:
|
||||
self.route_port_address_left(port)
|
||||
self.route_port_address_out(port, "left")
|
||||
|
||||
def route_port_address_left(self, port):
|
||||
def route_port_address_out(self, port, side="left"):
|
||||
""" 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()
|
||||
if side == "left":
|
||||
driver_wl_pos = driver_wl_pin.rc()
|
||||
else:
|
||||
driver_wl_pos = driver_wl_pin.lc()
|
||||
bitcell_wl_pin = self.bitcell_array_inst.get_pin(array_name)
|
||||
bitcell_wl_pos = bitcell_wl_pin.lc()
|
||||
mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * self.port_address_inst[port].rx() + 0.5 * self.bitcell_array_inst.lx(), 0)
|
||||
mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0.5, 1)
|
||||
self.add_path(driver_wl_pin.layer, [driver_wl_pos, mid1, mid2])
|
||||
# Via is non-preferred direction because mid1->mid2 is non-preferred direction
|
||||
self.add_via_stack_center(from_layer=driver_wl_pin.layer,
|
||||
to_layer=bitcell_wl_pin.layer,
|
||||
offset=mid2,
|
||||
directions="nonpref")
|
||||
self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos])
|
||||
|
||||
if side == "left":
|
||||
bitcell_wl_pos = bitcell_wl_pin.lc()
|
||||
port_address_pos = self.port_address_inst[port].rx()
|
||||
bitcell_array_pos = self.bitcell_array_inst.lx()
|
||||
else:
|
||||
bitcell_wl_pos = bitcell_wl_pin.rc()
|
||||
port_address_pos = self.port_address_inst[port].lx()
|
||||
bitcell_array_pos = self.bitcell_array_inst.rx()
|
||||
|
||||
mid1 = driver_wl_pos.scale(0, 1) + vector(0.5 * port_address_pos + 0.5 * bitcell_array_pos, 0)
|
||||
mid2 = mid1.scale(1, 0) + bitcell_wl_pos.scale(0, 1)
|
||||
if driver_wl_pin.layer != bitcell_wl_pin.layer:
|
||||
self.add_path(driver_wl_pin.layer, [driver_wl_pos, mid1, mid2])
|
||||
self.add_via_stack_center(from_layer=driver_wl_pin.layer,
|
||||
to_layer=bitcell_wl_pin.layer,
|
||||
offset=mid2)
|
||||
self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos])
|
||||
else:
|
||||
self.add_path(bitcell_wl_pin.layer, [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
|
||||
|
||||
|
||||
def route_port_address_right(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.lc()
|
||||
|
|
@ -886,6 +902,7 @@ class bank(design.design):
|
|||
to_layer=bitcell_wl_pin.layer,
|
||||
offset=mid2)
|
||||
self.add_path(bitcell_wl_pin.layer, [mid2, bitcell_wl_pos])
|
||||
|
||||
|
||||
def route_column_address_lines(self, port):
|
||||
""" Connecting the select lines of column mux to the address bus """
|
||||
|
|
@ -1021,10 +1038,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 +1058,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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -263,3 +267,4 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
|
|||
for inst in self.local_insts:
|
||||
offsets.extend(inst.lx() + x for x in inst.mod.get_column_offsets())
|
||||
return offsets
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -207,9 +207,9 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
|
|||
|
||||
y_offset = in_pin.cy()
|
||||
if port == 0:
|
||||
y_offset -= 1.5 * self.m3_pitch
|
||||
y_offset -= 2 * self.m3_pitch
|
||||
else:
|
||||
y_offset += 1.5 * self.m3_pitch
|
||||
y_offset += 2 * self.m3_pitch
|
||||
|
||||
self.add_layout_pin_segment_center(text=wl_name,
|
||||
layer="m3",
|
||||
|
|
|
|||
|
|
@ -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,13 @@ 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")
|
||||
|
||||
rbl_vdd_pin = self.rbl_driver_inst.get_pin("vdd")
|
||||
self.add_power_pin("vdd", rbl_vdd_pin.lc())
|
||||
|
||||
def route_pins(self):
|
||||
for row in range(self.addr_size):
|
||||
decoder_name = "addr_{}".format(row)
|
||||
|
|
@ -82,16 +89,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 +109,26 @@ 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")
|
||||
if self.port == 0:
|
||||
en_pos = en_pin.bc()
|
||||
else:
|
||||
en_pos = en_pin.uc()
|
||||
rbl_in_pin = self.rbl_driver_inst.get_pin("A")
|
||||
rbl_in_pos = rbl_in_pin.center()
|
||||
|
||||
self.add_via_stack_center(from_layer=rbl_in_pin.layer,
|
||||
to_layer=en_pin.layer,
|
||||
offset=rbl_in_pos)
|
||||
self.add_zjog(layer=en_pin.layer,
|
||||
start=rbl_in_pos,
|
||||
end=en_pos,
|
||||
first_direction="V")
|
||||
self.add_layout_pin_rect_center(text="wl_en",
|
||||
layer=en_pin.layer,
|
||||
offset=rbl_in_pos)
|
||||
|
||||
def add_modules(self):
|
||||
|
||||
|
|
@ -109,10 +136,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 = max(int(self.num_cols / local_array_size), 1)
|
||||
except AttributeError:
|
||||
local_array_size = 0
|
||||
# Defautl to FO4
|
||||
driver_size = max(int(self.num_cols / 4), 1)
|
||||
|
||||
# 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 +178,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 +213,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()
|
||||
|
|
|
|||
|
|
@ -305,14 +305,21 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
|
|||
|
||||
def create_layout(self):
|
||||
|
||||
# We will need unused wordlines grounded, so we need to know their layer
|
||||
pin = self.cell.get_pin(self.cell.get_all_wl_names()[0])
|
||||
pin_layer = pin.layer
|
||||
self.unused_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer))
|
||||
self.unused_offset = vector(self.unused_pitch, 0)
|
||||
|
||||
# Add extra width on the left and right for the unused WLs
|
||||
self.height = (self.row_size + self.extra_rows) * self.dummy_row.height
|
||||
self.width = (self.column_size + self.extra_cols) * self.cell.width
|
||||
self.width = (self.column_size + self.extra_cols) * self.cell.width + 2 * self.unused_pitch
|
||||
|
||||
# This is a bitcell x bitcell offset to scale
|
||||
self.bitcell_offset = vector(self.cell.width, self.cell.height)
|
||||
|
||||
# Everything is computed with the main array at (0, 0) to start
|
||||
self.bitcell_array_inst.place(offset=[0, 0])
|
||||
# Everything is computed with the main array at (self.unused_pitch, 0) to start
|
||||
self.bitcell_array_inst.place(offset=self.unused_offset)
|
||||
|
||||
self.add_replica_columns()
|
||||
|
||||
|
|
@ -356,7 +363,7 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
|
|||
|
||||
# Grow from left to right, toward the array
|
||||
for bit, port in enumerate(self.left_rbl):
|
||||
offset = self.bitcell_offset.scale(-len(self.left_rbl) + bit, -self.rbl[0] - 1)
|
||||
offset = self.bitcell_offset.scale(-len(self.left_rbl) + bit, -self.rbl[0] - 1) + self.unused_offset
|
||||
self.replica_col_insts[port].place(offset)
|
||||
# Grow to the right of the bitcell array, array outward
|
||||
for bit, port in enumerate(self.right_rbl):
|
||||
|
|
@ -367,11 +374,13 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
|
|||
# Add the dummy rows even if we aren't adding the replica column to this bitcell array
|
||||
# These grow up, toward the array
|
||||
for bit in range(self.rbl[0]):
|
||||
self.dummy_row_replica_insts[bit].place(offset=self.bitcell_offset.scale(0, -self.rbl[0] + bit + (-self.rbl[0] + bit) % 2),
|
||||
dummy_offset = self.bitcell_offset.scale(0, -self.rbl[0] + bit + (-self.rbl[0] + bit) % 2) + self.unused_offset
|
||||
self.dummy_row_replica_insts[bit].place(offset=dummy_offset,
|
||||
mirror="MX" if (-self.rbl[0] + bit) % 2 else "R0")
|
||||
# These grow up, away from the array
|
||||
for bit in range(self.rbl[1]):
|
||||
self.dummy_row_replica_insts[self.rbl[0] + bit].place(offset=self.bitcell_offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul(),
|
||||
dummy_offset = self.bitcell_offset.scale(0, bit + bit % 2) + self.bitcell_array_inst.ul()
|
||||
self.dummy_row_replica_insts[self.rbl[0] + bit].place(offset=dummy_offset,
|
||||
mirror="MX" if bit % 2 else "R0")
|
||||
|
||||
def add_end_caps(self):
|
||||
|
|
@ -386,12 +395,12 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
|
|||
# FIXME: These depend on the array size itself
|
||||
# Far bottom dummy row (first row below array IS flipped)
|
||||
flip_dummy = (self.rbl[0] + 1) % 2
|
||||
dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - 1 + flip_dummy)
|
||||
dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - 1 + flip_dummy) + self.unused_offset
|
||||
self.dummy_row_insts[0].place(offset=dummy_row_offset,
|
||||
mirror="MX" if flip_dummy else "R0")
|
||||
# Far left dummy col
|
||||
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array
|
||||
dummy_col_offset = self.bitcell_offset.scale(-len(self.left_rbl) - 1, -self.rbl[0] - 1)
|
||||
dummy_col_offset = self.bitcell_offset.scale(-len(self.left_rbl) - 1, -self.rbl[0] - 1) + self.unused_offset
|
||||
self.dummy_col_insts[0].place(offset=dummy_col_offset)
|
||||
# Far right dummy col
|
||||
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array
|
||||
|
|
@ -495,13 +504,13 @@ class replica_bitcell_array(bitcell_base_array.bitcell_base_array):
|
|||
def ground_pin(self, inst, name):
|
||||
pin = inst.get_pin(name)
|
||||
pin_layer = pin.layer
|
||||
layer_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer))
|
||||
|
||||
left_pin_loc = vector(self.dummy_col_insts[0].lx(), pin.cy())
|
||||
right_pin_loc = vector(self.dummy_col_insts[1].rx(), pin.cy())
|
||||
|
||||
# Place the pins a track outside of the array
|
||||
left_loc = left_pin_loc - vector(layer_pitch, 0)
|
||||
right_loc = right_pin_loc + vector(layer_pitch, 0)
|
||||
left_loc = left_pin_loc - vector(self.unused_pitch, 0)
|
||||
right_loc = right_pin_loc + vector(self.unused_pitch, 0)
|
||||
self.add_power_pin("gnd", left_loc, directions=("H", "H"))
|
||||
self.add_power_pin("gnd", right_loc, directions=("H", "H"))
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ class options(optparse.Values):
|
|||
num_r_ports = 0
|
||||
num_w_ports = 0
|
||||
|
||||
# By default, use local arrays with a max fanout of 16
|
||||
#local_array_size = 16
|
||||
|
||||
# Write mask size, default will be overwritten with word_size if not user specified
|
||||
write_size = None
|
||||
|
||||
|
|
@ -139,6 +142,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"
|
||||
|
|
|
|||
|
|
@ -96,4 +96,4 @@ class pbuf(pgate.pgate):
|
|||
offset=a_pin.center(),
|
||||
width=a_pin.width(),
|
||||
height=a_pin.height())
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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, 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 = max(int(self.cols / local_array_size), 1)
|
||||
except AttributeError:
|
||||
local_array_size = 0
|
||||
# Defautl to FO4
|
||||
driver_size = max(int(self.cols / 4), 1)
|
||||
|
||||
# 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)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class wordline_driver_test(openram_test):
|
|||
|
||||
# check wordline driver for single port
|
||||
debug.info(2, "Checking driver")
|
||||
tx = factory.create(module_type="wordline_driver")
|
||||
tx = factory.create(module_type="wordline_driver", cols=8)
|
||||
self.local_check(tx)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -27,11 +27,11 @@ class port_address_1rw_1r_test(openram_test):
|
|||
globals.setup_bitcell()
|
||||
|
||||
debug.info(1, "Port address 16 rows")
|
||||
a = factory.create("port_address", cols=16, rows=16)
|
||||
a = factory.create("port_address", cols=16, rows=16, port=0)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Port address 256 rows")
|
||||
a = factory.create("port_address", cols=256, rows=256)
|
||||
a = factory.create("port_address", cols=256, rows=256, port=1)
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ class port_address_test(openram_test):
|
|||
globals.init_openram(config_file)
|
||||
|
||||
debug.info(1, "Port address 16 rows")
|
||||
a = factory.create("port_address", cols=16, rows=16)
|
||||
a = factory.create("port_address", cols=16, rows=16, port=0)
|
||||
self.local_check(a)
|
||||
|
||||
debug.info(1, "Port address 512 rows")
|
||||
a = factory.create("port_address", cols=256, rows=512)
|
||||
a = factory.create("port_address", cols=256, rows=512, port=0)
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
|
|
|||
Loading…
Reference in New Issue