mirror of https://github.com/VLSIDA/OpenRAM.git
New power strapping mostly working.
Each module uses M3/M4 power straps with pins on the ends. Works in all technologies for a single no mux, dual port SRAM.
This commit is contained in:
parent
68d0a56423
commit
5e546ee974
|
|
@ -407,8 +407,8 @@ class layout():
|
||||||
"""
|
"""
|
||||||
pins = instance.get_pins(pin_name)
|
pins = instance.get_pins(pin_name)
|
||||||
|
|
||||||
debug.check(len(pins) > 0,
|
if len(pins) == 0:
|
||||||
"Could not find pin {}".format(pin_name))
|
debug.warning("Could not find pin {0} on {1}".format(pin_name, instance.mod.name))
|
||||||
|
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
if new_name == "":
|
if new_name == "":
|
||||||
|
|
@ -427,11 +427,194 @@ class layout():
|
||||||
for pin_name in self.pin_map.keys():
|
for pin_name in self.pin_map.keys():
|
||||||
self.copy_layout_pin(instance, pin_name, prefix + pin_name)
|
self.copy_layout_pin(instance, pin_name, prefix + pin_name)
|
||||||
|
|
||||||
def route_vertical_pins(self, name, insts=None, layer=None, xside="cx", yside="cy"):
|
def connect_row_locs(self, from_layer, to_layer, locs, name=None, full=False):
|
||||||
|
"""
|
||||||
|
Connects left/right rows that are aligned on the given layer.
|
||||||
|
"""
|
||||||
|
bins = {}
|
||||||
|
for loc in locs:
|
||||||
|
y = pin.y
|
||||||
|
try:
|
||||||
|
bins[y].append(loc)
|
||||||
|
except KeyError:
|
||||||
|
bins[y] = [loc]
|
||||||
|
|
||||||
|
for y, v in bins.items():
|
||||||
|
# Not enough to route a pin, so just copy them
|
||||||
|
if len(v) < 2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if full:
|
||||||
|
left_x = 0
|
||||||
|
right_x = self.width
|
||||||
|
else:
|
||||||
|
left_x = min([loc.x for loc in v])
|
||||||
|
right_x = max([loc.x for loc in v])
|
||||||
|
|
||||||
|
left_pos = vector(left_x, y)
|
||||||
|
right_pos = vector(right_x, y)
|
||||||
|
|
||||||
|
# Make sure to add vias to the new route
|
||||||
|
for loc in v:
|
||||||
|
self.add_via_stack_center(from_layer=from_layer,
|
||||||
|
to_layer=to_layer,
|
||||||
|
offset=loc,
|
||||||
|
min_area=True)
|
||||||
|
|
||||||
|
if name:
|
||||||
|
self.add_layout_pin_segment_center(text=name,
|
||||||
|
layer=to_layer,
|
||||||
|
start=left_pos,
|
||||||
|
end=right_pos)
|
||||||
|
else:
|
||||||
|
self.add_segment_center(layer=to_layer,
|
||||||
|
start=left_pos,
|
||||||
|
end=right_pos)
|
||||||
|
|
||||||
|
def connect_row_pins(self, layer, pins, name=None, full=False):
|
||||||
|
"""
|
||||||
|
Connects left/right rows that are aligned.
|
||||||
|
"""
|
||||||
|
bins = {}
|
||||||
|
for pin in pins:
|
||||||
|
y = pin.cy()
|
||||||
|
try:
|
||||||
|
bins[y].append(pin)
|
||||||
|
except KeyError:
|
||||||
|
bins[y] = [pin]
|
||||||
|
|
||||||
|
for y, v in bins.items():
|
||||||
|
# Not enough to route a pin, so just copy them
|
||||||
|
if len(v) < 2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if full:
|
||||||
|
left_x = 0
|
||||||
|
right_x = self.width
|
||||||
|
else:
|
||||||
|
left_x = min([pin.lx() for pin in v])
|
||||||
|
right_x = max([pin.rx() for pin in v])
|
||||||
|
|
||||||
|
left_pos = vector(left_x, y)
|
||||||
|
right_pos = vector(right_x, y)
|
||||||
|
|
||||||
|
# Make sure to add vias to the new route
|
||||||
|
for pin in v:
|
||||||
|
self.add_via_stack_center(from_layer=pin.layer,
|
||||||
|
to_layer=layer,
|
||||||
|
offset=pin.center(),
|
||||||
|
min_area=True)
|
||||||
|
|
||||||
|
if name:
|
||||||
|
self.add_layout_pin_segment_center(text=name,
|
||||||
|
layer=layer,
|
||||||
|
start=left_pos,
|
||||||
|
end=right_pos)
|
||||||
|
else:
|
||||||
|
self.add_segment_center(layer=layer,
|
||||||
|
start=left_pos,
|
||||||
|
end=right_pos)
|
||||||
|
|
||||||
|
def connect_col_locs(self, from_layer, to_layer, locs, name=None, full=False):
|
||||||
|
"""
|
||||||
|
Connects top/bot columns that are aligned.
|
||||||
|
"""
|
||||||
|
bins = {}
|
||||||
|
for loc in locs:
|
||||||
|
x = loc.x
|
||||||
|
try:
|
||||||
|
bins[x].append(loc)
|
||||||
|
except KeyError:
|
||||||
|
bins[x] = [loc]
|
||||||
|
|
||||||
|
for x, v in bins.items():
|
||||||
|
# Not enough to route a pin, so just copy them
|
||||||
|
if len(v) < 2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if full:
|
||||||
|
bot_y = 0
|
||||||
|
top_y = self.height
|
||||||
|
else:
|
||||||
|
bot_y = min([loc.y for loc in v])
|
||||||
|
top_y = max([loc.y for loc in v])
|
||||||
|
|
||||||
|
top_pos = vector(x, top_y)
|
||||||
|
bot_pos = vector(x, bot_y)
|
||||||
|
|
||||||
|
# Make sure to add vias to the new route
|
||||||
|
for loc in v:
|
||||||
|
self.add_via_stack_center(from_layer=from_layer,
|
||||||
|
to_layer=to_layer,
|
||||||
|
offset=loc,
|
||||||
|
min_area=True)
|
||||||
|
|
||||||
|
if name:
|
||||||
|
self.add_layout_pin_segment_center(text=name,
|
||||||
|
layer=to_layer,
|
||||||
|
start=top_pos,
|
||||||
|
end=bot_pos)
|
||||||
|
else:
|
||||||
|
self.add_segment_center(layer=to_layer,
|
||||||
|
start=top_pos,
|
||||||
|
end=bot_pos)
|
||||||
|
|
||||||
|
|
||||||
|
def connect_col_pins(self, layer, pins, name=None, full=False):
|
||||||
|
"""
|
||||||
|
Connects top/bot columns that are aligned.
|
||||||
|
"""
|
||||||
|
bins = {}
|
||||||
|
for pin in pins:
|
||||||
|
x = pin.cx()
|
||||||
|
try:
|
||||||
|
bins[x].append(pin)
|
||||||
|
except KeyError:
|
||||||
|
bins[x] = [pin]
|
||||||
|
|
||||||
|
for x, v in bins.items():
|
||||||
|
# Not enough to route a pin, so just copy them
|
||||||
|
if len(v) < 2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if full:
|
||||||
|
bot_y = 0
|
||||||
|
top_y = self.height
|
||||||
|
else:
|
||||||
|
bot_y = min([pin.by() for pin in v])
|
||||||
|
top_y = max([pin.uy() for pin in v])
|
||||||
|
|
||||||
|
top_pos = vector(x, top_y)
|
||||||
|
bot_pos = vector(x, bot_y)
|
||||||
|
|
||||||
|
# Make sure to add vias to the new route
|
||||||
|
for pin in v:
|
||||||
|
self.add_via_stack_center(from_layer=pin.layer,
|
||||||
|
to_layer=layer,
|
||||||
|
offset=pin.center(),
|
||||||
|
min_area=True)
|
||||||
|
|
||||||
|
if name:
|
||||||
|
self.add_layout_pin_segment_center(text=name,
|
||||||
|
layer=layer,
|
||||||
|
start=top_pos,
|
||||||
|
end=bot_pos)
|
||||||
|
else:
|
||||||
|
self.add_segment_center(layer=layer,
|
||||||
|
start=top_pos,
|
||||||
|
end=bot_pos)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def route_vertical_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", num_pins=2, full_width=True):
|
||||||
"""
|
"""
|
||||||
Route together all of the pins of a given name that vertically align.
|
Route together all of the pins of a given name that vertically align.
|
||||||
Uses local_insts if insts not specified.
|
Uses local_insts if insts not specified.
|
||||||
Uses center of pin by default, or right or left if specified.
|
Uses center of pin by default, or right or left if specified.
|
||||||
|
num_pins specifies whether to add a single pin or multiple pins (equally spaced)
|
||||||
|
TODO: Add equally spaced option for IR drop min, right now just 2
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -451,7 +634,7 @@ class layout():
|
||||||
for x, v in bins.items():
|
for x, v in bins.items():
|
||||||
# Not enough to route a pin, so just copy them
|
# Not enough to route a pin, so just copy them
|
||||||
if len(v) < 2:
|
if len(v) < 2:
|
||||||
debug.warning("Copying pins instead of connecting with pin.")
|
debug.warning("Pins don't align well so copying pins instead of connecting with pin.")
|
||||||
for inst,pin in v:
|
for inst,pin in v:
|
||||||
self.add_layout_pin(pin.name,
|
self.add_layout_pin(pin.name,
|
||||||
pin.layer,
|
pin.layer,
|
||||||
|
|
@ -460,10 +643,8 @@ class layout():
|
||||||
pin.height())
|
pin.height())
|
||||||
continue
|
continue
|
||||||
|
|
||||||
bot_y = min([pin.by() for (inst,pin) in v])
|
|
||||||
top_y = max([pin.uy() for (inst,pin) in v])
|
|
||||||
|
|
||||||
last_via = None
|
last_via = None
|
||||||
|
pin_layer = None
|
||||||
for inst,pin in v:
|
for inst,pin in v:
|
||||||
if layer:
|
if layer:
|
||||||
pin_layer = layer
|
pin_layer = layer
|
||||||
|
|
@ -482,31 +663,57 @@ class layout():
|
||||||
else:
|
else:
|
||||||
via_width=None
|
via_width=None
|
||||||
|
|
||||||
|
if full_width:
|
||||||
|
bot_y = 0
|
||||||
|
top_y = self.height
|
||||||
|
else:
|
||||||
|
bot_y = min([pin.by() for (inst,pin) in v])
|
||||||
|
top_y = max([pin.uy() for (inst,pin) in v])
|
||||||
top_pos = vector(x, top_y)
|
top_pos = vector(x, top_y)
|
||||||
bot_pos = vector(x, bot_y)
|
bot_pos = vector(x, bot_y)
|
||||||
# top_rect = self.add_layout_pin_rect_center(text=name,
|
|
||||||
# layer=pin_layer,
|
if num_pins==2:
|
||||||
# offset=top_pos)
|
self.add_layout_pin_rect_ends(name=name,
|
||||||
#bot_rect = self.add_layout_pin_rect_center(text=name,
|
layer=pin_layer,
|
||||||
# layer=pin_layer,
|
start=top_pos,
|
||||||
# offset=bot_pos)
|
end=bot_pos,
|
||||||
# self.add_segment_center(layer=pin_layer,
|
width=via_width)
|
||||||
# start=vector(top_rect.cx(), bot_pos.y),
|
else:
|
||||||
# end=top_rect.bc(),
|
self.add_layout_pin_segment_center(text=name,
|
||||||
# width=via_width)
|
layer=pin_layer,
|
||||||
self.add_layout_pin_segment_center(text=name,
|
start=top_pos,
|
||||||
layer=pin_layer,
|
end=bot_pos,
|
||||||
start=top_pos,
|
width=via_width)
|
||||||
end=bot_pos,
|
|
||||||
width=via_width)
|
|
||||||
|
|
||||||
|
|
||||||
|
def add_layout_pin_rect_ends(self, name, layer, start, end, width=None):
|
||||||
|
|
||||||
def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy"):
|
# This adds pins on the end connected by a segment
|
||||||
|
top_rect = self.add_layout_pin_rect_center(text=name,
|
||||||
|
layer=layer,
|
||||||
|
offset=start)
|
||||||
|
bot_rect = self.add_layout_pin_rect_center(text=name,
|
||||||
|
layer=layer,
|
||||||
|
offset=end)
|
||||||
|
# This is made to not overlap with the pin above
|
||||||
|
# so that the power router will only select a small pin.
|
||||||
|
# Otherwise it adds big blockages over the rails.
|
||||||
|
if start.y != end.y:
|
||||||
|
self.add_segment_center(layer=layer,
|
||||||
|
start=bot_rect.uc(),
|
||||||
|
end=top_rect.bc())
|
||||||
|
else:
|
||||||
|
self.add_segment_center(layer=layer,
|
||||||
|
start=bot_rect.rc(),
|
||||||
|
end=top_rect.lc())
|
||||||
|
|
||||||
|
def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", num_pins=2, full_width=True):
|
||||||
"""
|
"""
|
||||||
Route together all of the pins of a given name that horizontally align.
|
Route together all of the pins of a given name that horizontally align.
|
||||||
Uses local_insts if insts not specified.
|
Uses local_insts if insts not specified.
|
||||||
Uses center of pin by default, or top or botom if specified.
|
Uses center of pin by default, or top or botom if specified.
|
||||||
|
num_pins specifies whether to add a single pin or multiple pins (equally spaced)
|
||||||
|
TODO: Add equally spaced option for IR drop min, right now just 2
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -527,7 +734,7 @@ class layout():
|
||||||
|
|
||||||
for y, v in bins.items():
|
for y, v in bins.items():
|
||||||
if len(v) < 2:
|
if len(v) < 2:
|
||||||
debug.warning("Copying pins instead of connecting with pin.")
|
debug.warning("Pins don't align well so copying pins instead of connecting with pin.")
|
||||||
for inst,pin in v:
|
for inst,pin in v:
|
||||||
self.add_layout_pin(pin.name,
|
self.add_layout_pin(pin.name,
|
||||||
pin.layer,
|
pin.layer,
|
||||||
|
|
@ -536,10 +743,8 @@ class layout():
|
||||||
pin.height())
|
pin.height())
|
||||||
continue
|
continue
|
||||||
|
|
||||||
left_x = min([pin.lx() for (inst,pin) in v])
|
|
||||||
right_x = max([pin.rx() for (inst,pin) in v])
|
|
||||||
|
|
||||||
last_via = None
|
last_via = None
|
||||||
|
pin_layer = None
|
||||||
for inst,pin in v:
|
for inst,pin in v:
|
||||||
if layer:
|
if layer:
|
||||||
pin_layer = layer
|
pin_layer = layer
|
||||||
|
|
@ -550,7 +755,7 @@ class layout():
|
||||||
|
|
||||||
last_via = self.add_via_stack_center(from_layer=pin.layer,
|
last_via = self.add_via_stack_center(from_layer=pin.layer,
|
||||||
to_layer=pin_layer,
|
to_layer=pin_layer,
|
||||||
offset=vector(pin.cx(), y),
|
offset=vector(x, y),
|
||||||
min_area=True)
|
min_area=True)
|
||||||
|
|
||||||
if last_via:
|
if last_via:
|
||||||
|
|
@ -558,28 +763,55 @@ class layout():
|
||||||
else:
|
else:
|
||||||
via_height=None
|
via_height=None
|
||||||
|
|
||||||
|
if full_width:
|
||||||
|
left_x = 0
|
||||||
|
right_x = self.width
|
||||||
|
else:
|
||||||
|
left_x = min([pin.lx() for (inst,pin) in v])
|
||||||
|
right_x = max([pin.rx() for (inst,pin) in v])
|
||||||
left_pos = vector(left_x, y)
|
left_pos = vector(left_x, y)
|
||||||
right_pos = vector(right_x, y)
|
right_pos = vector(right_x, y)
|
||||||
|
|
||||||
# left_rect = self.add_layout_pin_rect_center(text=name,
|
if num_pins==2:
|
||||||
# layer=pin_layer,
|
self.add_layout_pin_rect_ends(name=name,
|
||||||
# offset=left_pos)
|
layer=pin_layer,
|
||||||
#right_rect = self.add_layout_pin_rect_center(text=name,
|
start=left_pos,
|
||||||
# layer=pin_layer,
|
end=right_pos,
|
||||||
# offset=right_pos)
|
width=via_height)
|
||||||
# This is made to not overlap with the pin above
|
else:
|
||||||
# so that the power router will only select a small pin.
|
# This adds a single big pin
|
||||||
# Otherwise it adds big blockages over the rails.
|
self.add_layout_pin_segment_center(text=name,
|
||||||
# self.add_segment_center(layer=pin_layer,
|
layer=pin_layer,
|
||||||
# start=left_rect.rc(),
|
start=left_pos,
|
||||||
# end=vector(right_pos.x, left_rect.cy()),
|
end=right_pos,
|
||||||
# width=via_height)
|
width=via_height)
|
||||||
|
|
||||||
self.add_layout_pin_segment_center(text=name,
|
def add_layout_end_pin_segment_center(self, text, layer, start, end):
|
||||||
layer=pin_layer,
|
"""
|
||||||
start=left_pos,
|
Creates a path with two pins on the end that don't overlap.
|
||||||
end=right_pos,
|
"""
|
||||||
width=via_height)
|
|
||||||
|
start_pin = self.add_layout_pin_rect_center(text=text,
|
||||||
|
layer=layer,
|
||||||
|
offset=start)
|
||||||
|
end_pin = self.add_layout_pin_rect_center(text=text,
|
||||||
|
layer=layer,
|
||||||
|
offset=end)
|
||||||
|
|
||||||
|
if start.x != end.x and start.y != end.y:
|
||||||
|
file_name = "non_rectilinear.gds"
|
||||||
|
self.gds_write(file_name)
|
||||||
|
debug.error("Cannot have a non-manhatten layout pin: {}".format(file_name), -1)
|
||||||
|
elif start.x != end.x:
|
||||||
|
self.add_segment_center(layer=layer,
|
||||||
|
start=start_pin.rc(),
|
||||||
|
end=end_pin.lc())
|
||||||
|
elif start.y != end.y:
|
||||||
|
self.add_segment_center(layer=layer,
|
||||||
|
start=start_pin.uc(),
|
||||||
|
end=end_pin.bc())
|
||||||
|
else:
|
||||||
|
debug.error("Cannot have a point pin.", -1)
|
||||||
|
|
||||||
|
|
||||||
def add_layout_pin_segment_center(self, text, layer, start, end, width=None):
|
def add_layout_pin_segment_center(self, text, layer, start, end, width=None):
|
||||||
|
|
@ -1447,12 +1679,13 @@ class layout():
|
||||||
width = None
|
width = None
|
||||||
height = None
|
height = None
|
||||||
|
|
||||||
|
pin = None
|
||||||
if start_layer in self.pwr_grid_layers:
|
if start_layer in self.pwr_grid_layers:
|
||||||
self.add_layout_pin_rect_center(text=name,
|
pin = self.add_layout_pin_rect_center(text=name,
|
||||||
layer=start_layer,
|
layer=start_layer,
|
||||||
offset=loc,
|
offset=loc,
|
||||||
width=width,
|
width=width,
|
||||||
height=height)
|
height=height)
|
||||||
else:
|
else:
|
||||||
via = self.add_via_stack_center(from_layer=start_layer,
|
via = self.add_via_stack_center(from_layer=start_layer,
|
||||||
to_layer=self.pwr_grid_layers[0],
|
to_layer=self.pwr_grid_layers[0],
|
||||||
|
|
@ -1463,11 +1696,13 @@ class layout():
|
||||||
width = via.width
|
width = via.width
|
||||||
if not height:
|
if not height:
|
||||||
height = via.height
|
height = via.height
|
||||||
self.add_layout_pin_rect_center(text=name,
|
pin = self.add_layout_pin_rect_center(text=name,
|
||||||
layer=self.pwr_grid_layers[0],
|
layer=self.pwr_grid_layers[0],
|
||||||
offset=loc,
|
offset=loc,
|
||||||
width=width,
|
width=width,
|
||||||
height=height)
|
height=height)
|
||||||
|
|
||||||
|
return pin
|
||||||
|
|
||||||
def copy_power_pin(self, pin, loc=None, directions=None, new_name=""):
|
def copy_power_pin(self, pin, loc=None, directions=None, new_name=""):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ class bitcell_array(bitcell_base_array):
|
||||||
|
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
|
|
||||||
|
self.route_supplies()
|
||||||
|
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
|
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
|
||||||
|
|
@ -156,18 +156,15 @@ class bitcell_base_array(design.design):
|
||||||
width=self.width,
|
width=self.width,
|
||||||
height=wl_pin.height())
|
height=wl_pin.height())
|
||||||
|
|
||||||
def add_supply_pins(self):
|
def route_supplies(self):
|
||||||
for row in range(self.row_size):
|
for inst in self.cell_inst.values():
|
||||||
for col in range(self.column_size):
|
for pin_name in ["vdd", "gnd"]:
|
||||||
inst = self.cell_inst[row, col]
|
self.copy_layout_pin(inst, pin_name)
|
||||||
for pin_name in ["vdd", "gnd"]:
|
|
||||||
self.copy_layout_pin(inst, pin_name)
|
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
""" Add the layout pins """
|
""" Add the layout pins """
|
||||||
self.add_bitline_pins()
|
self.add_bitline_pins()
|
||||||
self.add_wl_pins()
|
self.add_wl_pins()
|
||||||
self.add_supply_pins()
|
|
||||||
|
|
||||||
def _adjust_x_offset(self, xoffset, col, col_offset):
|
def _adjust_x_offset(self, xoffset, col, col_offset):
|
||||||
tempx = xoffset
|
tempx = xoffset
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,8 @@ class control_logic(design.design):
|
||||||
def route_rails(self):
|
def route_rails(self):
|
||||||
""" Add the input signal inverted tracks """
|
""" Add the input signal inverted tracks """
|
||||||
height = self.control_logic_center.y - self.m2_pitch
|
height = self.control_logic_center.y - self.m2_pitch
|
||||||
offset = vector(self.ctrl_dff_array.width, 0)
|
# DFF spacing plus the power routing
|
||||||
|
offset = vector(self.ctrl_dff_array.width + self.m4_pitch, 0)
|
||||||
|
|
||||||
self.input_bus = self.create_vertical_bus("m2",
|
self.input_bus = self.create_vertical_bus("m2",
|
||||||
offset,
|
offset,
|
||||||
|
|
@ -312,7 +313,8 @@ class control_logic(design.design):
|
||||||
self.place_dffs()
|
self.place_dffs()
|
||||||
|
|
||||||
# All of the control logic is placed to the right of the DFFs and bus
|
# All of the control logic is placed to the right of the DFFs and bus
|
||||||
self.control_x_offset = self.ctrl_dff_array.width + self.internal_bus_width
|
# as well as the power supply stripe
|
||||||
|
self.control_x_offset = self.ctrl_dff_array.width + self.internal_bus_width + self.m4_pitch
|
||||||
|
|
||||||
row = 0
|
row = 0
|
||||||
# Add the logic on the right of the bus
|
# Add the logic on the right of the bus
|
||||||
|
|
@ -368,7 +370,7 @@ class control_logic(design.design):
|
||||||
self.route_clk_buf()
|
self.route_clk_buf()
|
||||||
self.route_gated_clk_bar()
|
self.route_gated_clk_bar()
|
||||||
self.route_gated_clk_buf()
|
self.route_gated_clk_buf()
|
||||||
self.route_supply()
|
self.route_supplies()
|
||||||
|
|
||||||
def create_delay(self):
|
def create_delay(self):
|
||||||
""" Create the replica bitline """
|
""" Create the replica bitline """
|
||||||
|
|
@ -707,28 +709,60 @@ class control_logic(design.design):
|
||||||
start=out_pos,
|
start=out_pos,
|
||||||
end=right_pos)
|
end=right_pos)
|
||||||
|
|
||||||
def route_supply(self):
|
def route_supplies(self):
|
||||||
""" Add vdd and gnd to the instance cells """
|
""" Add vdd and gnd to the instance cells """
|
||||||
|
|
||||||
supply_layer = self.dff.get_pin("vdd").layer
|
pin_layer = self.dff.get_pin("vdd").layer
|
||||||
|
supply_layer = self.supply_stack[2]
|
||||||
|
|
||||||
max_row_x_loc = max([inst.rx() for inst in self.row_end_inst])
|
max_row_x_loc = max([inst.rx() for inst in self.row_end_inst])
|
||||||
|
min_row_x_loc = self.control_x_offset
|
||||||
|
|
||||||
|
vdd_pin_locs = []
|
||||||
|
gnd_pin_locs = []
|
||||||
|
|
||||||
for inst in self.row_end_inst:
|
for inst in self.row_end_inst:
|
||||||
pins = inst.get_pins("vdd")
|
pins = inst.get_pins("vdd")
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
if pin.layer == supply_layer:
|
if pin.layer == pin_layer:
|
||||||
row_loc = pin.rc()
|
row_loc = pin.rc()
|
||||||
pin_loc = vector(max_row_x_loc, pin.rc().y)
|
pin_loc = vector(max_row_x_loc, pin.rc().y)
|
||||||
self.add_power_pin("vdd", pin_loc, start_layer=pin.layer)
|
vdd_pin_locs.append(pin_loc)
|
||||||
self.add_path(supply_layer, [row_loc, pin_loc])
|
self.add_via_stack_center(from_layer=pin_layer,
|
||||||
|
to_layer=supply_layer,
|
||||||
|
offset=pin_loc,
|
||||||
|
min_area=True)
|
||||||
|
self.add_path(pin_layer, [row_loc, pin_loc])
|
||||||
|
|
||||||
pins = inst.get_pins("gnd")
|
pins = inst.get_pins("gnd")
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
if pin.layer == supply_layer:
|
if pin.layer == pin_layer:
|
||||||
row_loc = pin.rc()
|
row_loc = pin.rc()
|
||||||
pin_loc = vector(max_row_x_loc, pin.rc().y)
|
pin_loc = vector(min_row_x_loc, pin.rc().y)
|
||||||
self.add_power_pin("gnd", pin_loc, start_layer=pin.layer)
|
gnd_pin_locs.append(pin_loc)
|
||||||
self.add_path(supply_layer, [row_loc, pin_loc])
|
self.add_via_stack_center(from_layer=pin_layer,
|
||||||
|
to_layer=supply_layer,
|
||||||
|
offset=pin_loc,
|
||||||
|
min_area=True)
|
||||||
|
self.add_path(pin_layer, [row_loc, pin_loc])
|
||||||
|
|
||||||
|
min_y = min([x.y for x in vdd_pin_locs])
|
||||||
|
max_y = max([x.y for x in vdd_pin_locs])
|
||||||
|
bot_pos = vector(max_row_x_loc, min_y)
|
||||||
|
top_pos = vector(max_row_x_loc, max_y)
|
||||||
|
self.add_layout_pin_segment_center(text="vdd",
|
||||||
|
layer=supply_layer,
|
||||||
|
start=bot_pos,
|
||||||
|
end=top_pos)
|
||||||
|
|
||||||
|
min_y = min([x.y for x in gnd_pin_locs])
|
||||||
|
max_y = max([x.y for x in gnd_pin_locs])
|
||||||
|
bot_pos = vector(min_row_x_loc, min_y)
|
||||||
|
top_pos = vector(min_row_x_loc, max_y)
|
||||||
|
self.add_layout_pin_segment_center(text="gnd",
|
||||||
|
layer=supply_layer,
|
||||||
|
start=bot_pos,
|
||||||
|
end=top_pos)
|
||||||
|
|
||||||
self.copy_layout_pin(self.delay_inst, "gnd")
|
self.copy_layout_pin(self.delay_inst, "gnd")
|
||||||
self.copy_layout_pin(self.delay_inst, "vdd")
|
self.copy_layout_pin(self.delay_inst, "vdd")
|
||||||
|
|
@ -781,7 +815,7 @@ class control_logic(design.design):
|
||||||
# Connect this at the bottom of the buffer
|
# Connect this at the bottom of the buffer
|
||||||
out_pin = inst.get_pin("Z")
|
out_pin = inst.get_pin("Z")
|
||||||
out_pos = out_pin.center()
|
out_pos = out_pin.center()
|
||||||
mid1 = vector(out_pos.x, out_pos.y - 0.4 * inst.mod.height)
|
mid1 = vector(out_pos.x, out_pos.y - 0.3 * inst.mod.height)
|
||||||
mid2 = vector(self.input_bus[name].cx(), mid1.y)
|
mid2 = vector(self.input_bus[name].cx(), mid1.y)
|
||||||
bus_pos = self.input_bus[name].center()
|
bus_pos = self.input_bus[name].center()
|
||||||
self.add_wire(self.m2_stack[::-1], [out_pos, mid1, mid2, bus_pos])
|
self.add_wire(self.m2_stack[::-1], [out_pos, mid1, mid2, bus_pos])
|
||||||
|
|
|
||||||
|
|
@ -177,9 +177,11 @@ class delay_chain(design.design):
|
||||||
# The routing to connect the loads is over the first and last cells
|
# The routing to connect the loads is over the first and last cells
|
||||||
# We have an even number of drivers and must only do every other
|
# We have an even number of drivers and must only do every other
|
||||||
# supply rail
|
# supply rail
|
||||||
if OPTS.experimental_power:
|
if True or OPTS.experimental_power:
|
||||||
self.route_horizontal_pins("vdd")
|
left_load_insts = [self.load_inst_map[x][0] for x in self.driver_inst_list]
|
||||||
self.route_horizontal_pins("gnd")
|
right_load_insts = [self.load_inst_map[x][-1] for x in self.driver_inst_list]
|
||||||
|
self.route_vertical_pins("vdd", left_load_insts, xside="lx")
|
||||||
|
self.route_vertical_pins("gnd", right_load_insts, xside="rx")
|
||||||
else:
|
else:
|
||||||
for inst in self.driver_inst_list:
|
for inst in self.driver_inst_list:
|
||||||
load_list = self.load_inst_map[inst]
|
load_list = self.load_inst_map[inst]
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ class dff_array(design.design):
|
||||||
self.height = self.rows * self.dff.height
|
self.height = self.rows * self.dff.height
|
||||||
|
|
||||||
self.place_dff_array()
|
self.place_dff_array()
|
||||||
|
self.route_supplies()
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
@ -106,17 +107,25 @@ class dff_array(design.design):
|
||||||
|
|
||||||
return dout_name
|
return dout_name
|
||||||
|
|
||||||
|
def route_supplies(self):
|
||||||
|
if OPTS.experimental_power and self.rows > 1:
|
||||||
|
# Vertical straps on ends if multiple rows
|
||||||
|
left_dff_insts = [self.dff_insts[x, 0] for x in range(self.rows)]
|
||||||
|
right_dff_insts = [self.dff_insts[x, self.columns-1] for x in range(self.rows)]
|
||||||
|
self.route_vertical_pins("vdd", left_dff_insts, xside="lx", yside="cy")
|
||||||
|
self.route_vertical_pins("gnd", right_dff_insts, xside="rx", yside="cy")
|
||||||
|
else:
|
||||||
|
for row in range(self.rows):
|
||||||
|
for col in range(self.columns):
|
||||||
|
# Continous vdd rail along with label.
|
||||||
|
vdd_pin=self.dff_insts[row, col].get_pin("vdd")
|
||||||
|
self.copy_power_pin(vdd_pin)
|
||||||
|
|
||||||
|
# Continous gnd rail along with label.
|
||||||
|
gnd_pin=self.dff_insts[row, col].get_pin("gnd")
|
||||||
|
self.copy_power_pin(gnd_pin)
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
for row in range(self.rows):
|
|
||||||
for col in range(self.columns):
|
|
||||||
# Continous vdd rail along with label.
|
|
||||||
vdd_pin=self.dff_insts[row, col].get_pin("vdd")
|
|
||||||
self.copy_power_pin(vdd_pin)
|
|
||||||
|
|
||||||
# Continous gnd rail along with label.
|
|
||||||
gnd_pin=self.dff_insts[row, col].get_pin("gnd")
|
|
||||||
self.copy_power_pin(gnd_pin)
|
|
||||||
|
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
for col in range(self.columns):
|
for col in range(self.columns):
|
||||||
din_pin = self.dff_insts[row, col].get_pin("D")
|
din_pin = self.dff_insts[row, col].get_pin("D")
|
||||||
|
|
|
||||||
|
|
@ -145,24 +145,23 @@ class dff_buf_array(design.design):
|
||||||
return dout_bar_name
|
return dout_bar_name
|
||||||
|
|
||||||
def route_supplies(self):
|
def route_supplies(self):
|
||||||
for row in range(self.rows):
|
if OPTS.experimental_power and self.rows > 1:
|
||||||
vdd0_pin=self.dff_insts[row, 0].get_pin("vdd")
|
# Vertical straps on ends if multiple rows
|
||||||
vddn_pin=self.dff_insts[row, self.columns - 1].get_pin("vdd")
|
left_dff_insts = [self.dff_insts[x, 0] for x in range(self.rows)]
|
||||||
self.add_path(vdd0_pin.layer, [vdd0_pin.lc(), vddn_pin.rc()], width=vdd0_pin.height())
|
right_dff_insts = [self.dff_insts[x, self.columns-1] for x in range(self.rows)]
|
||||||
|
self.route_vertical_pins("vdd", left_dff_insts, xside="lx", yside="cy")
|
||||||
|
self.route_vertical_pins("gnd", right_dff_insts, xside="rx", yside="cy")
|
||||||
|
else:
|
||||||
|
for row in range(self.rows):
|
||||||
|
for col in range(self.columns):
|
||||||
|
# Continous vdd rail along with label.
|
||||||
|
vdd_pin=self.dff_insts[row, col].get_pin("vdd")
|
||||||
|
self.copy_power_pin(vdd_pin)
|
||||||
|
|
||||||
gnd0_pin=self.dff_insts[row, 0].get_pin("gnd")
|
# Continous gnd rail along with label.
|
||||||
gndn_pin=self.dff_insts[row, self.columns - 1].get_pin("gnd")
|
gnd_pin=self.dff_insts[row, col].get_pin("gnd")
|
||||||
self.add_path(gnd0_pin.layer, [gnd0_pin.lc(), gndn_pin.rc()], width=gnd0_pin.height())
|
self.copy_power_pin(gnd_pin)
|
||||||
|
|
||||||
for row in range(self.rows):
|
|
||||||
for col in range(self.columns):
|
|
||||||
# Continous vdd rail along with label.
|
|
||||||
vdd_pin=self.dff_insts[row, col].get_pin("vdd")
|
|
||||||
self.copy_power_pin(vdd_pin, loc=vdd_pin.lc())
|
|
||||||
|
|
||||||
# Continous gnd rail along with label.
|
|
||||||
gnd_pin=self.dff_insts[row, col].get_pin("gnd")
|
|
||||||
self.copy_power_pin(gnd_pin, loc=gnd_pin.lc())
|
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,8 @@ class dummy_array(bitcell_base_array):
|
||||||
|
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
|
|
||||||
|
self.route_supplies()
|
||||||
|
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
|
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
@ -98,6 +100,8 @@ class dummy_array(bitcell_base_array):
|
||||||
width=self.width,
|
width=self.width,
|
||||||
height=wl_pin.height())
|
height=wl_pin.height())
|
||||||
|
|
||||||
|
def route_supplies(self):
|
||||||
|
|
||||||
# Copy a vdd/gnd layout pin from every cell
|
# Copy a vdd/gnd layout pin from every cell
|
||||||
for row in range(self.row_size):
|
for row in range(self.row_size):
|
||||||
for col in range(self.column_size):
|
for col in range(self.column_size):
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ class hierarchical_decoder(design.design):
|
||||||
self.pre2x4_inst = []
|
self.pre2x4_inst = []
|
||||||
self.pre3x8_inst = []
|
self.pre3x8_inst = []
|
||||||
self.pre4x16_inst = []
|
self.pre4x16_inst = []
|
||||||
self.local_insts = []
|
|
||||||
|
|
||||||
b = factory.create(module_type=OPTS.bitcell)
|
b = factory.create(module_type=OPTS.bitcell)
|
||||||
self.cell_height = b.height
|
self.cell_height = b.height
|
||||||
|
|
@ -591,65 +590,20 @@ class hierarchical_decoder(design.design):
|
||||||
|
|
||||||
def route_supplies(self):
|
def route_supplies(self):
|
||||||
"""
|
"""
|
||||||
Add a pin for each row of vdd/gnd which are
|
|
||||||
must-connects next level up.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# This is an experiment with power rails
|
# Leave these to route in the port_address
|
||||||
if OPTS.tech_name=="sky130" or OPTS.experimental_power:
|
all_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
|
||||||
if layer_props.hierarchical_decoder.vertical_supply:
|
for inst in all_insts:
|
||||||
pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
|
self.copy_layout_pin(inst, "vdd")
|
||||||
self.route_vertical_pins("vdd", insts=pre_insts, yside="by")
|
self.copy_layout_pin(inst, "gnd")
|
||||||
self.route_vertical_pins("gnd", insts=pre_insts, yside="by")
|
|
||||||
self.route_vertical_pins("vdd", insts=self.and_inst, yside="by")
|
|
||||||
self.route_vertical_pins("gnd", insts=self.and_inst, yside="by")
|
|
||||||
else:
|
|
||||||
pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
|
|
||||||
self.route_vertical_pins("vdd", insts=pre_insts)
|
|
||||||
self.route_vertical_pins("gnd", insts=pre_insts)
|
|
||||||
self.route_vertical_pins("vdd", insts=self.and_inst, xside="rx")
|
|
||||||
self.route_vertical_pins("gnd", insts=self.and_inst, xside="lx")
|
|
||||||
|
|
||||||
# Widen the rails to cover any gap
|
for inst in self.and_inst:
|
||||||
for inst in self.and_inst:
|
for pin in inst.get_pins("vdd"):
|
||||||
for name in ["vdd", "gnd"]:
|
self.add_power_pin("vdd", pin.rc())
|
||||||
supply_pin = inst.get_pin(name)
|
for pin in inst.get_pins("gnd"):
|
||||||
self.add_segment_center(layer=supply_pin.layer,
|
self.add_power_pin("gnd", pin.lc())
|
||||||
start=vector(0, supply_pin.cy()),
|
|
||||||
end=vector(self.width, supply_pin.cy()))
|
|
||||||
else:
|
|
||||||
if layer_props.hierarchical_decoder.vertical_supply:
|
|
||||||
for n in ["vdd", "gnd"]:
|
|
||||||
pins = self.and_inst[0].get_pins(n)
|
|
||||||
for pin in pins:
|
|
||||||
self.add_rect(layer=pin.layer,
|
|
||||||
offset=pin.ll() + vector(0, self.bus_space),
|
|
||||||
width=pin.width(),
|
|
||||||
height=self.height - 2 * self.bus_space)
|
|
||||||
|
|
||||||
# This adds power vias at the top of each cell
|
|
||||||
# (except the last to keep them inside the boundary)
|
|
||||||
for i in self.and_inst[:-1]:
|
|
||||||
pins = i.get_pins(n)
|
|
||||||
for pin in pins:
|
|
||||||
self.copy_power_pin(pin, loc=pin.uc())
|
|
||||||
|
|
||||||
for i in self.pre2x4_inst + self.pre3x8_inst:
|
|
||||||
self.copy_layout_pin(i, n)
|
|
||||||
else:
|
|
||||||
# The vias will be placed at the right of the cells.
|
|
||||||
xoffset = max(x.rx() for x in self.and_inst) + 0.5 * self.m1_space
|
|
||||||
for row in range(0, self.num_outputs):
|
|
||||||
for pin_name in ["vdd", "gnd"]:
|
|
||||||
# The nand and inv are the same height rows...
|
|
||||||
supply_pin = self.and_inst[row].get_pin(pin_name)
|
|
||||||
pin_pos = vector(xoffset, supply_pin.cy())
|
|
||||||
self.copy_power_pin(supply_pin, loc=pin_pos)
|
|
||||||
|
|
||||||
# Copy the pins from the predecoders
|
|
||||||
for pre in self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst:
|
|
||||||
for pin_name in ["vdd", "gnd"]:
|
|
||||||
self.copy_layout_pin(pre, pin_name)
|
|
||||||
|
|
||||||
def route_predecode_bus_outputs(self, rail_name, pin, row):
|
def route_predecode_bus_outputs(self, rail_name, pin, row):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -381,7 +381,7 @@ class hierarchical_predecode(design.design):
|
||||||
def route_supplies(self):
|
def route_supplies(self):
|
||||||
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """
|
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """
|
||||||
|
|
||||||
# We may ahve vertical power supply rails
|
# We may have vertical power supply rails
|
||||||
if layer_props.hierarchical_predecode.vertical_supply and not self.column_decoder:
|
if layer_props.hierarchical_predecode.vertical_supply and not self.column_decoder:
|
||||||
for n in ["vdd", "gnd"]:
|
for n in ["vdd", "gnd"]:
|
||||||
# This makes a wire from top to bottom for both inv and and gates
|
# This makes a wire from top to bottom for both inv and and gates
|
||||||
|
|
@ -403,8 +403,6 @@ class hierarchical_predecode(design.design):
|
||||||
# In other techs, we are using standard cell decoder cells with horizontal power
|
# In other techs, we are using standard cell decoder cells with horizontal power
|
||||||
else:
|
else:
|
||||||
for num in range(0, self.number_of_outputs):
|
for num in range(0, self.number_of_outputs):
|
||||||
|
|
||||||
# Route both supplies
|
|
||||||
for n in ["vdd", "gnd"]:
|
for n in ["vdd", "gnd"]:
|
||||||
and_pins = self.and_inst[num].get_pins(n)
|
and_pins = self.and_inst[num].get_pins(n)
|
||||||
for and_pin in and_pins:
|
for and_pin in and_pins:
|
||||||
|
|
@ -418,4 +416,4 @@ class hierarchical_predecode(design.design):
|
||||||
else:
|
else:
|
||||||
xoffset = self.inv_inst[0].lx() - self.bus_space
|
xoffset = self.inv_inst[0].lx() - self.bus_space
|
||||||
pin_pos = vector(xoffset, and_pin.cy())
|
pin_pos = vector(xoffset, and_pin.cy())
|
||||||
self.copy_power_pin(and_pin, loc=pin_pos)
|
self.add_power_pin(n, pin_pos)
|
||||||
|
|
|
||||||
|
|
@ -76,15 +76,21 @@ 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.wordline_driver_array_inst, self.row_decoder_inst]:
|
self.route_vertical_pins("vdd", [self.row_decoder_inst])
|
||||||
self.copy_layout_pin(inst, "vdd")
|
self.route_vertical_pins("gnd", [self.row_decoder_inst])
|
||||||
self.copy_layout_pin(inst, "gnd")
|
self.route_vertical_pins("vdd", [self.wordline_driver_array_inst])
|
||||||
|
if layer_props.wordline_driver.vertical_supply:
|
||||||
|
self.route_vertical_pins("gnd", [self.wordline_driver_array_inst])
|
||||||
|
self.copy_layout_pin(self.rbl_driver_inst, "vdd")
|
||||||
|
else:
|
||||||
|
rbl_pos = self.rbl_driver_inst.get_pin("vdd").rc()
|
||||||
|
self.add_power_pin("vdd", rbl_pos)
|
||||||
|
self.add_path("m4", [rbl_pos, self.wordline_driver_array_inst.get_pins("vdd")[0].rc()])
|
||||||
|
|
||||||
for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"):
|
vdd_pins = self.row_decoder_inst.get_pins("vdd") + self.wordline_driver_array_inst.get_pins("vdd")
|
||||||
if layer_props.port_address.supply_offset:
|
self.connect_row_pins(self.route_layer, vdd_pins)
|
||||||
self.copy_power_pin(rbl_vdd_pin)
|
gnd_pins = self.row_decoder_inst.get_pins("gnd") + self.wordline_driver_array_inst.get_pins("gnd")
|
||||||
else:
|
self.connect_row_pins(self.route_layer, gnd_pins)
|
||||||
self.copy_power_pin(rbl_vdd_pin, loc=rbl_vdd_pin.lc())
|
|
||||||
|
|
||||||
# Also connect the B input of the RBL and_dec to vdd
|
# Also connect the B input of the RBL and_dec to vdd
|
||||||
if OPTS.local_array_size == 0:
|
if OPTS.local_array_size == 0:
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ class precharge_array(design.design):
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
|
|
||||||
en_pin = self.pc_cell.get_pin("en_bar")
|
en_pin = self.pc_cell.get_pin("en_bar")
|
||||||
self.route_horizontal_pins("en_bar", layer=self.en_bar_layer)
|
self.route_horizontal_pins("en_bar", layer=self.en_bar_layer, num_pins=1)
|
||||||
for inst in self.local_insts:
|
for inst in self.local_insts:
|
||||||
self.add_via_stack_center(from_layer=en_pin.layer,
|
self.add_via_stack_center(from_layer=en_pin.layer,
|
||||||
to_layer=self.en_bar_layer,
|
to_layer=self.en_bar_layer,
|
||||||
|
|
@ -95,11 +95,7 @@ class precharge_array(design.design):
|
||||||
self.copy_layout_pin(inst, "br", "br_{0}".format(i))
|
self.copy_layout_pin(inst, "br", "br_{0}".format(i))
|
||||||
|
|
||||||
def route_supplies(self):
|
def route_supplies(self):
|
||||||
if OPTS.tech_name=="sky130" or OPTS.experimental_power:
|
self.route_horizontal_pins("vdd")
|
||||||
self.route_horizontal_pins("vdd")
|
|
||||||
else:
|
|
||||||
for inst in self.local_insts:
|
|
||||||
self.copy_layout_pin(inst, "vdd")
|
|
||||||
|
|
||||||
def create_insts(self):
|
def create_insts(self):
|
||||||
"""Creates a precharge array by horizontally tiling the precharge cell"""
|
"""Creates a precharge array by horizontally tiling the precharge cell"""
|
||||||
|
|
|
||||||
|
|
@ -305,19 +305,18 @@ class replica_bitcell_array(bitcell_base_array):
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
|
|
||||||
# We will need unused wordlines grounded, so we need to know their layer
|
# This creates space for the unused wordline connections as well as the
|
||||||
# and create a space on the left and right for the vias to connect to ground
|
# row-based or column based power and ground lines.
|
||||||
pin = self.cell.get_pin(self.cell.get_all_wl_names()[0])
|
self.vertical_pitch = getattr(self, "{}_pitch".format(self.supply_stack[0]))
|
||||||
pin_layer = pin.layer
|
self.horizontal_pitch = getattr(self, "{}_pitch".format(self.supply_stack[2]))
|
||||||
self.unused_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer))
|
self.unused_offset = vector(2 * self.horizontal_pitch, 2 * self.vertical_pitch)
|
||||||
self.unused_offset = vector(self.unused_pitch, 0)
|
|
||||||
|
|
||||||
# This is a bitcell x bitcell offset to scale
|
# This is a bitcell x bitcell offset to scale
|
||||||
self.bitcell_offset = vector(self.cell.width, self.cell.height)
|
self.bitcell_offset = vector(self.cell.width, self.cell.height)
|
||||||
self.col_end_offset = vector(self.cell.width, self.cell.height)
|
self.col_end_offset = vector(self.cell.width, self.cell.height)
|
||||||
self.row_end_offset = vector(self.cell.width, self.cell.height)
|
self.row_end_offset = vector(self.cell.width, self.cell.height)
|
||||||
|
|
||||||
# Everything is computed with the main array at (self.unused_pitch, 0) to start
|
# Everything is computed with the main array
|
||||||
self.bitcell_array_inst.place(offset=self.unused_offset)
|
self.bitcell_array_inst.place(offset=self.unused_offset)
|
||||||
|
|
||||||
self.add_replica_columns()
|
self.add_replica_columns()
|
||||||
|
|
@ -336,6 +335,8 @@ class replica_bitcell_array(bitcell_base_array):
|
||||||
|
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
|
|
||||||
|
self.route_supplies()
|
||||||
|
|
||||||
self.route_unused_wordlines()
|
self.route_unused_wordlines()
|
||||||
|
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
|
|
@ -458,23 +459,82 @@ class replica_bitcell_array(bitcell_base_array):
|
||||||
width=pin.width(),
|
width=pin.width(),
|
||||||
height=self.height)
|
height=self.height)
|
||||||
|
|
||||||
if OPTS.tech_name=="sky130" or OPTS.experimental_power:
|
def route_supplies(self):
|
||||||
self.route_vertical_pins(name="gnd", insts=self.replica_col_insts)
|
|
||||||
self.route_horizontal_pins(name="vdd", insts=self.dummy_row_insts)
|
|
||||||
else:
|
|
||||||
# vdd/gnd are only connected in the perimeter cells
|
|
||||||
# replica column should only have a vdd/gnd in the dummy cell on top/bottom
|
|
||||||
supply_insts = self.dummy_col_insts + self.dummy_row_insts
|
|
||||||
|
|
||||||
for pin_name in self.supplies:
|
# vdd/gnd are only connected in the perimeter cells
|
||||||
for inst in supply_insts:
|
# replica column should only have a vdd/gnd in the dummy cell on top/bottom
|
||||||
pin_list = inst.get_pins(pin_name)
|
supply_insts = self.dummy_col_insts + self.dummy_row_insts
|
||||||
for pin in pin_list:
|
|
||||||
self.copy_power_pin(pin)
|
vdd_leftx = 0
|
||||||
|
vdd_rightx = 0
|
||||||
|
gnd_leftx = 0
|
||||||
|
gnd_rightx = 0
|
||||||
|
|
||||||
|
for inst in supply_insts:
|
||||||
|
for pin in inst.get_pins("vdd"):
|
||||||
|
(vdd_leftx, vdd_rightx) = self.connect_pin(pin, 2.5)
|
||||||
|
for pin in inst.get_pins("gnd"):
|
||||||
|
(gnd_leftx, gnd_rightx) = self.connect_pin(pin)
|
||||||
|
|
||||||
|
|
||||||
|
self.add_layout_end_pin_segment_center(text="vdd",
|
||||||
|
layer=self.supply_stack[2],
|
||||||
|
start=vector(vdd_leftx, 0),
|
||||||
|
end=vector(vdd_leftx, self.height))
|
||||||
|
self.add_layout_end_pin_segment_center(text="vdd",
|
||||||
|
layer=self.supply_stack[2],
|
||||||
|
start=vector(vdd_rightx, 0),
|
||||||
|
end=vector(vdd_rightx, self.height))
|
||||||
|
self.add_layout_end_pin_segment_center(text="gnd",
|
||||||
|
layer=self.supply_stack[2],
|
||||||
|
start=vector(gnd_leftx, 0),
|
||||||
|
end=vector(gnd_leftx, self.height))
|
||||||
|
self.add_layout_end_pin_segment_center(text="gnd",
|
||||||
|
layer=self.supply_stack[2],
|
||||||
|
start=vector(gnd_rightx, 0),
|
||||||
|
end=vector(gnd_rightx, self.height))
|
||||||
|
|
||||||
|
|
||||||
|
def route_unused_wordlines(self):
|
||||||
|
""" Connect the unused RBL and dummy wordlines to gnd """
|
||||||
|
# This grounds all the dummy row word lines
|
||||||
|
for inst in self.dummy_row_insts:
|
||||||
|
for wl_name in self.col_cap_top.get_wordline_names():
|
||||||
|
pin = inst.get_pin(wl_name)
|
||||||
|
self.connect_pin(pin)
|
||||||
|
|
||||||
|
# Ground the unused replica wordlines
|
||||||
|
for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts):
|
||||||
|
for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()):
|
||||||
|
if wl_name in self.gnd_wordline_names:
|
||||||
|
pin = inst.get_pin(pin_name)
|
||||||
|
self.connect_pin(pin)
|
||||||
|
|
||||||
|
|
||||||
|
def connect_pin(self, pin, offset_multiple=1):
|
||||||
|
|
||||||
|
pin_layer = 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(offset_multiple * self.horizontal_pitch, 0)
|
||||||
|
right_loc = right_pin_loc + vector(offset_multiple * self.horizontal_pitch, 0)
|
||||||
|
self.add_via_stack_center(offset=left_loc,
|
||||||
|
from_layer=pin_layer,
|
||||||
|
to_layer=self.supply_stack[2],
|
||||||
|
directions=("H", "H"))
|
||||||
|
self.add_via_stack_center(offset=right_loc,
|
||||||
|
from_layer=pin_layer,
|
||||||
|
to_layer=self.supply_stack[2],
|
||||||
|
directions=("H", "H"))
|
||||||
|
|
||||||
|
# Add a path to connect to the array
|
||||||
|
self.add_path(pin_layer, [left_loc, right_loc])
|
||||||
|
|
||||||
|
return (left_loc.x, right_loc.x)
|
||||||
|
|
||||||
for inst in self.replica_col_insts:
|
|
||||||
if inst:
|
|
||||||
self.copy_layout_pin(inst, pin_name)
|
|
||||||
|
|
||||||
|
|
||||||
def analytical_power(self, corner, load):
|
def analytical_power(self, corner, load):
|
||||||
|
|
@ -494,34 +554,6 @@ class replica_bitcell_array(bitcell_base_array):
|
||||||
cell_power.leakage * self.column_size * self.row_size)
|
cell_power.leakage * self.column_size * self.row_size)
|
||||||
return total_power
|
return total_power
|
||||||
|
|
||||||
def route_unused_wordlines(self):
|
|
||||||
""" Connect the unused RBL and dummy wordlines to gnd """
|
|
||||||
# This grounds all the dummy row word lines
|
|
||||||
for inst in self.dummy_row_insts:
|
|
||||||
for wl_name in self.col_cap_top.get_wordline_names():
|
|
||||||
self.ground_pin(inst, wl_name)
|
|
||||||
|
|
||||||
# Ground the unused replica wordlines
|
|
||||||
for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts):
|
|
||||||
for (wl_name, pin_name) in zip(names, self.dummy_row.get_wordline_names()):
|
|
||||||
if wl_name in self.gnd_wordline_names:
|
|
||||||
self.ground_pin(inst, pin_name)
|
|
||||||
|
|
||||||
def ground_pin(self, inst, name):
|
|
||||||
pin = inst.get_pin(name)
|
|
||||||
pin_layer = 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(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"))
|
|
||||||
|
|
||||||
# Add a path to connect to the array
|
|
||||||
self.add_path(pin_layer, [left_loc, right_loc], width=pin.height())
|
|
||||||
|
|
||||||
def gen_bl_wire(self):
|
def gen_bl_wire(self):
|
||||||
if OPTS.netlist_only:
|
if OPTS.netlist_only:
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,8 @@ class replica_column(bitcell_base_array):
|
||||||
|
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
|
|
||||||
|
self.route_supplies()
|
||||||
|
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
|
@ -185,15 +187,11 @@ class replica_column(bitcell_base_array):
|
||||||
width=self.width,
|
width=self.width,
|
||||||
height=wl_pin.height())
|
height=wl_pin.height())
|
||||||
|
|
||||||
# Supplies are only connected in the ends
|
def route_supplies(self):
|
||||||
for (index, inst) in enumerate(self.cell_inst):
|
|
||||||
|
for inst in self.cell_inst:
|
||||||
for pin_name in ["vdd", "gnd"]:
|
for pin_name in ["vdd", "gnd"]:
|
||||||
if inst in [self.cell_inst[0], self.cell_inst[self.total_size - 1]]:
|
self.copy_layout_pin(inst, pin_name)
|
||||||
#for pin in inst.get_pins(pin_name):
|
|
||||||
# self.copy_power_pin(pin)
|
|
||||||
self.copy_power_pins(inst, pin_name)
|
|
||||||
else:
|
|
||||||
self.copy_layout_pin(inst, pin_name)
|
|
||||||
|
|
||||||
def get_bitline_names(self, port=None):
|
def get_bitline_names(self, port=None):
|
||||||
if port == None:
|
if port == None:
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ class wordline_driver_array(design.design):
|
||||||
self.height = self.wld_inst[-1].uy()
|
self.height = self.wld_inst[-1].uy()
|
||||||
|
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.route_vdd_gnd()
|
self.route_supplies()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
|
|
@ -72,54 +72,16 @@ class wordline_driver_array(design.design):
|
||||||
self.wl_driver = factory.create(module_type="wordline_driver",
|
self.wl_driver = factory.create(module_type="wordline_driver",
|
||||||
cols=self.cols)
|
cols=self.cols)
|
||||||
|
|
||||||
def route_vdd_gnd(self):
|
def route_supplies(self):
|
||||||
"""
|
"""
|
||||||
Add vertical power rails.
|
Add vertical power rails.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Experiment with power straps
|
for inst in self.wld_inst:
|
||||||
if OPTS.tech_name=="sky130" or OPTS.experimental_power:
|
for pin in inst.get_pins("vdd"):
|
||||||
if layer_props.wordline_driver.vertical_supply:
|
self.add_power_pin("vdd", pin.rc())
|
||||||
self.route_vertical_pins("vdd", insts=self.wld_inst)
|
#self.copy_layout_pin(inst, "vdd")
|
||||||
self.route_vertical_pins("gnd", insts=self.wld_inst)
|
self.copy_layout_pin(inst, "gnd")
|
||||||
else:
|
|
||||||
self.route_vertical_pins("vdd", insts=self.wld_inst, xside="lx")
|
|
||||||
self.route_vertical_pins("gnd", insts=self.wld_inst, xside="rx")
|
|
||||||
|
|
||||||
# Widen the rails to cover any gap
|
|
||||||
for num in range(self.rows):
|
|
||||||
for name in ["vdd", "gnd"]:
|
|
||||||
supply_pin = self.wld_inst[num].get_pin(name)
|
|
||||||
self.add_segment_center(layer=supply_pin.layer,
|
|
||||||
start=vector(0, supply_pin.cy()),
|
|
||||||
end=vector(self.width, supply_pin.cy()))
|
|
||||||
else:
|
|
||||||
if layer_props.wordline_driver.vertical_supply:
|
|
||||||
for name in ["vdd", "gnd"]:
|
|
||||||
supply_pins = self.wld_inst[0].get_pins(name)
|
|
||||||
for pin in supply_pins:
|
|
||||||
self.add_layout_pin_segment_center(text=name,
|
|
||||||
layer=pin.layer,
|
|
||||||
start=pin.bc(),
|
|
||||||
end=vector(pin.cx(), self.height))
|
|
||||||
else:
|
|
||||||
# Find the x offsets for where the vias/pins should be placed
|
|
||||||
xoffset_list = [self.wld_inst[0].rx()]
|
|
||||||
for num in range(self.rows):
|
|
||||||
# this will result in duplicate polygons for rails, but who cares
|
|
||||||
|
|
||||||
# use the inverter offset even though it will be the and's too
|
|
||||||
(gate_offset, y_dir) = self.get_gate_offset(0,
|
|
||||||
self.wl_driver.height,
|
|
||||||
num)
|
|
||||||
# Route both supplies
|
|
||||||
for name in ["vdd", "gnd"]:
|
|
||||||
supply_pin = self.wld_inst[num].get_pin(name)
|
|
||||||
|
|
||||||
# Add pins in two locations
|
|
||||||
for xoffset in xoffset_list:
|
|
||||||
pin_pos = vector(xoffset, supply_pin.cy())
|
|
||||||
self.copy_power_pin(supply_pin, loc=pin_pos)
|
|
||||||
|
|
||||||
|
|
||||||
def create_drivers(self):
|
def create_drivers(self):
|
||||||
|
|
|
||||||
|
|
@ -195,4 +195,4 @@ class options(optparse.Values):
|
||||||
write_mask_and_array = "write_mask_and_array"
|
write_mask_and_array = "write_mask_and_array"
|
||||||
|
|
||||||
# Non-public options
|
# Non-public options
|
||||||
experimental_power = False
|
experimental_power = True
|
||||||
|
|
|
||||||
|
|
@ -349,8 +349,6 @@ class sram_1bank(sram_base):
|
||||||
if OPTS.perimeter_pins:
|
if OPTS.perimeter_pins:
|
||||||
# We now route the escape routes far enough out so that they will
|
# We now route the escape routes far enough out so that they will
|
||||||
# reach past the power ring or stripes on the sides
|
# reach past the power ring or stripes on the sides
|
||||||
# The power rings are 4 tracks wide with 2 tracks spacing, so space it
|
|
||||||
# 11 tracks out
|
|
||||||
bbox = self.get_bbox(side="ring",
|
bbox = self.get_bbox(side="ring",
|
||||||
margin=11*rt.track_width)
|
margin=11*rt.track_width)
|
||||||
self.route_escape_pins(bbox)
|
self.route_escape_pins(bbox)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue