Improvements to power routing.

Improved the route horizontal and vertical pin functions to
create a single pin at the end.
Swapped A and B on wordline driver input for cleaner routing
in most technologies.
Fixed vertical supply routing in port_address.
This commit is contained in:
mrg 2022-03-04 15:44:07 -08:00
parent 10bec414e8
commit 8b3c10ae79
5 changed files with 92 additions and 59 deletions

View File

@ -74,24 +74,30 @@ class layout():
############################################################ ############################################################
# GDS layout # GDS layout
############################################################ ############################################################
def offset_all_coordinates(self): def offset_all_coordinates(self, offset=None):
""" """
This function is called after everything is placed to This function is called after everything is placed to
shift the origin in the lowest left corner shift the origin in the lowest left corner
""" """
offset = self.find_lowest_coords() if not offset:
self.translate_all(offset) offset = vector(0, 0)
return offset ll = self.find_lowest_coords()
real_offset = ll + offset
self.translate_all(real_offset)
return real_offset
def offset_x_coordinates(self): def offset_x_coordinates(self, offset=None):
""" """
This function is called after everything is placed to This function is called after everything is placed to
shift the origin to the furthest left point. shift the origin to the furthest left point.
Y offset is unchanged. Y offset is unchanged.
""" """
offset = self.find_lowest_coords() if not offset:
self.translate_all(offset.scale(1, 0)) offset = vector(0, 0)
return offset ll = self.find_lowest_coords()
real_offset = ll.scale(1, 0) + offset
self.translate_all(real_offset)
return real_offset
def get_gate_offset(self, x_offset, height, inv_num): def get_gate_offset(self, x_offset, height, inv_num):
""" """
@ -422,7 +428,7 @@ 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, side=None): def route_vertical_pins(self, name, insts=None, layer=None, xside="cx", yside="cy"):
""" """
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.
@ -437,19 +443,17 @@ class layout():
for inst in insts: for inst in insts:
for pin in inst.get_pins(name): for pin in inst.get_pins(name):
if side == "right": x = getattr(pin, xside)()
x = pin.rx()
elif side == "left":
x = pin.lx()
else:
x = pin.cx()
try: try:
bins[x].append((inst,pin)) bins[x].append((inst,pin))
except KeyError: except KeyError:
bins[x] = [(inst,pin)] bins[x] = [(inst,pin)]
for x, v in bins.items(): for x, v in bins.items():
# Not enough to route a pin
if len(v) < 2:
continue
bot_y = min([inst.by() for (inst,pin) in v]) bot_y = min([inst.by() for (inst,pin) in v])
top_y = max([inst.uy() for (inst,pin) in v]) top_y = max([inst.uy() for (inst,pin) in v])
@ -459,9 +463,12 @@ class layout():
pin_layer = layer pin_layer = layer
else: else:
pin_layer = self.supply_stack[2] pin_layer = self.supply_stack[2]
y = getattr(pin, yside)()
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(x, pin.cy()), offset=vector(x, y),
min_area=True) min_area=True)
if last_via: if last_via:
@ -469,13 +476,22 @@ class layout():
else: else:
via_width=None via_width=None
self.add_layout_pin_segment_center(text=name, top_pos = vector(x, top_y)
layer=pin_layer, bot_pos = vector(x, bot_y)
start=vector(x, bot_y), self.add_segment_center(layer=pin_layer,
end=vector(x, top_y), start=bot_pos,
width=via_width) end=top_pos,
width=via_width)
def route_horizontal_pins(self, name, insts=None, layer=None, side=None): self.add_layout_pin_rect_center(text=name,
layer=pin_layer,
offset=top_pos)
# self.add_layout_pin_rect_center(text=name,
# layer=pin_layer,
# offset=bot_pos)
def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy"):
""" """
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.
@ -489,19 +505,20 @@ class layout():
for inst in insts: for inst in insts:
for pin in inst.get_pins(name): for pin in inst.get_pins(name):
if side == "top":
y = pin.uy()
elif side == "bottom":
y = pin.by()
else:
y = pin.cy()
y = getattr(pin, yside)()
try: try:
bins[y].append((inst,pin)) bins[y].append((inst,pin))
except KeyError: except KeyError:
bins[y] = [(inst,pin)] bins[y] = [(inst,pin)]
# Filter the small bins
for y, v in bins.items(): for y, v in bins.items():
# Not enough to route a pin
if len(v) < 2:
continue
left_x = min([inst.lx() for (inst,pin) in v]) left_x = min([inst.lx() for (inst,pin) in v])
right_x = max([inst.rx() for (inst,pin) in v]) right_x = max([inst.rx() for (inst,pin) in v])
@ -511,6 +528,9 @@ class layout():
pin_layer = layer pin_layer = layer
else: else:
pin_layer = self.supply_stack[0] pin_layer = self.supply_stack[0]
x = getattr(pin, xside)()
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(pin.cx(), y),
@ -521,11 +541,19 @@ class layout():
else: else:
via_height=None via_height=None
self.add_layout_pin_segment_center(text=name, left_pos = vector(left_x, y)
layer=pin_layer, right_pos = vector(right_x, y)
start=vector(left_x, y), self.add_segment_center(layer=pin_layer,
end=vector(right_x, y), start=left_pos,
width=via_height) end=right_pos,
width=via_height)
self.add_layout_pin_rect_center(text=name,
layer=pin_layer,
offset=left_pos)
# self.add_layout_pin_rect_center(text=name,
# layer=pin_layer,
# offset=right_pos)
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):
""" """

View File

@ -596,10 +596,10 @@ class hierarchical_decoder(design.design):
""" """
if layer_props.hierarchical_decoder.vertical_supply: if layer_props.hierarchical_decoder.vertical_supply:
pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
self.route_vertical_pins("vdd", insts=pre_insts) self.route_vertical_pins("vdd", insts=pre_insts, yside="by")
self.route_vertical_pins("gnd", insts=pre_insts) self.route_vertical_pins("gnd", insts=pre_insts, yside="by")
self.route_vertical_pins("vdd", insts=self.and_inst) self.route_vertical_pins("vdd", insts=self.and_inst, yside="by")
self.route_vertical_pins("gnd", insts=self.and_inst) self.route_vertical_pins("gnd", insts=self.and_inst, yside="by")
return return
for n in ["vdd", "gnd"]: for n in ["vdd", "gnd"]:
pins = self.and_inst[0].get_pins(n) pins = self.and_inst[0].get_pins(n)
@ -622,8 +622,8 @@ class hierarchical_decoder(design.design):
pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
self.route_vertical_pins("vdd", insts=pre_insts) self.route_vertical_pins("vdd", insts=pre_insts)
self.route_vertical_pins("gnd", insts=pre_insts) self.route_vertical_pins("gnd", insts=pre_insts)
self.route_vertical_pins("vdd", insts=self.and_inst, side="right") self.route_vertical_pins("vdd", insts=self.and_inst, xside="rx")
self.route_vertical_pins("gnd", insts=self.and_inst, side="left") self.route_vertical_pins("gnd", insts=self.and_inst, xside="lx")
# Widen the rails to cover any gap # Widen the rails to cover any gap
for inst in self.and_inst: for inst in self.and_inst:

View File

@ -228,17 +228,15 @@ class port_address(design.design):
wordline_driver_array_offset = vector(self.row_decoder_inst.rx(), 0) wordline_driver_array_offset = vector(self.row_decoder_inst.rx(), 0)
self.wordline_driver_array_inst.place(wordline_driver_array_offset) self.wordline_driver_array_inst.place(wordline_driver_array_offset)
# The wordline driver also had an extra gap on the right, so use this offset # This m4_pitch corresponds to the offset space for jog routing in the
well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active") # wordline_driver_array
x_offset = self.wordline_driver_array_inst.rx() - well_gap - self.rbl_driver.width rbl_driver_offset = wordline_driver_array_offset + vector(self.m4_pitch, 0)
if self.port == 0: if self.port == 0:
rbl_driver_offset = vector(x_offset,
0)
self.rbl_driver_inst.place(rbl_driver_offset, "MX") self.rbl_driver_inst.place(rbl_driver_offset, "MX")
else: else:
rbl_driver_offset = vector(x_offset, rbl_driver_offset += vector(0,
self.wordline_driver_array.height) self.wordline_driver_array.height)
self.rbl_driver_inst.place(rbl_driver_offset) self.rbl_driver_inst.place(rbl_driver_offset)
# Pass this up # Pass this up

View File

@ -463,6 +463,11 @@ class replica_bitcell_array(bitcell_base_array):
supply_insts = self.dummy_col_insts + self.dummy_row_insts supply_insts = self.dummy_col_insts + self.dummy_row_insts
for pin_name in self.supplies: for pin_name in self.supplies:
#self.route_vertical_pins(name=pin_name, insts=supply_insts)
self.route_horizontal_pins(name=pin_name, insts=supply_insts)
#self.route_vertical_pins(name=pin_name, insts=self.replica_col_insts)
#self.route_horizontal_pins(name=pin_name, insts=self.replica_col_insts)
for inst in supply_insts: for inst in supply_insts:
pin_list = inst.get_pins(pin_name) pin_list = inst.get_pins(pin_name)
for pin in pin_list: for pin in pin_list:

View File

@ -42,9 +42,16 @@ class wordline_driver_array(design.design):
self.route_layer = "li" self.route_layer = "li"
else: else:
self.route_layer = "m1" self.route_layer = "m1"
self.place_drivers() self.place_drivers()
self.route_layout() self.route_layout()
self.offset_x_coordinates() self.offset_x_coordinates(vector(-self.m4_pitch, 0))
# Leave a well gap to separate the bitcell array well from this well
well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active")
self.width = self.wld_inst[-1].rx() + well_gap
self.height = self.wld_inst[-1].uy()
self.add_boundary() self.add_boundary()
self.route_vdd_gnd() self.route_vdd_gnd()
self.DRC_LVS() self.DRC_LVS()
@ -73,8 +80,8 @@ class wordline_driver_array(design.design):
self.route_vertical_pins("vdd", insts=self.wld_inst) self.route_vertical_pins("vdd", insts=self.wld_inst)
self.route_vertical_pins("gnd", insts=self.wld_inst) self.route_vertical_pins("gnd", insts=self.wld_inst)
else: else:
self.route_vertical_pins("vdd", insts=self.wld_inst, side="left") self.route_vertical_pins("vdd", insts=self.wld_inst, xside="lx")
self.route_vertical_pins("gnd", insts=self.wld_inst, side="right") self.route_vertical_pins("gnd", insts=self.wld_inst, xside="rx")
# Widen the rails to cover any gap # Widen the rails to cover any gap
for num in range(self.rows): for num in range(self.rows):
@ -93,8 +100,8 @@ class wordline_driver_array(design.design):
# add and2 # add and2
self.wld_inst.append(self.add_inst(name=name_and, self.wld_inst.append(self.add_inst(name=name_and,
mod=self.wl_driver)) mod=self.wl_driver))
self.connect_inst(["en", self.connect_inst(["in_{0}".format(row),
"in_{0}".format(row), "en",
"wl_{0}".format(row), "wl_{0}".format(row),
"vdd", "gnd"]) "vdd", "gnd"])
@ -114,18 +121,13 @@ class wordline_driver_array(design.design):
self.wld_inst[row].place(offset=and2_offset, self.wld_inst[row].place(offset=and2_offset,
mirror=inst_mirror) mirror=inst_mirror)
# Leave a well gap to separate the bitcell array well from this well
well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active")
self.width = self.wl_driver.width + well_gap
self.height = self.wl_driver.height * self.rows
def route_layout(self): def route_layout(self):
""" Route all of the signals """ """ Route all of the signals """
# Wordline enable connection # Wordline enable connection
en_pin = self.wld_inst[0].get_pin("B") en_pin = self.wld_inst[0].get_pin("B")
en_bottom_pos = vector(en_pin.cx(), 0) en_bottom_pos = vector(en_pin.cx(), 0)
en_top_pos = vector(en_pin.cx(), self.height) en_top_pos = vector(en_pin.cx(), self.wld_inst[-1].uy())
en_pin = self.add_layout_pin_segment_center(text="en", en_pin = self.add_layout_pin_segment_center(text="en",
layer="m2", layer="m2",
start=en_bottom_pos, start=en_bottom_pos,
@ -135,7 +137,7 @@ class wordline_driver_array(design.design):
and_inst = self.wld_inst[row] and_inst = self.wld_inst[row]
# Drop a via # Drop a via
b_pin = and_inst.get_pin("A") b_pin = and_inst.get_pin("B")
self.add_via_stack_center(from_layer=b_pin.layer, self.add_via_stack_center(from_layer=b_pin.layer,
to_layer="m2", to_layer="m2",
offset=b_pin.center()) offset=b_pin.center())