add route_outside, remove unused methods

This commit is contained in:
FriedrichWu 2024-11-20 16:24:26 +01:00
parent 86588619fd
commit 4fe635a05f
6 changed files with 611 additions and 102 deletions

View File

@ -1913,8 +1913,8 @@ class layout():
# Just use the power pin function for now to save code
self.add_power_pin(new_name, pin.center(), start_layer=start_layer, directions=directions)
def add_power_pin_no_via(self, name, loc, directions=None, start_layer="m1"):
# same function like normal one, but do not add via to the gird layer
def add_power_pin_m2(self, name, loc, directions=None, start_layer="m1"):
# same function like normal one, but add power pin at m2
# Hack for min area
if OPTS.tech_name == "sky130":
min_area = drc["minarea_{}".format(self.pwr_grid_layers[1])]
@ -1925,7 +1925,7 @@ class layout():
height = None
pin = None
if start_layer in self.pwr_grid_layers:
if start_layer == "m2":
pin = self.add_layout_pin_rect_center(text=name,
layer=start_layer,
offset=loc,
@ -1933,7 +1933,7 @@ class layout():
height=height)
else:
via = self.add_via_stack_center(from_layer=start_layer,
to_layer=start_layer,# so only enclosure shape will be added
to_layer="m2",
offset=loc,
directions=directions)
@ -1942,7 +1942,7 @@ class layout():
if not height:
height = via.height
pin = self.add_layout_pin_rect_center(text=name,
layer=start_layer,
layer="m2",
offset=loc,
width=width,
height=height)
@ -2063,7 +2063,7 @@ class layout():
layer=layer,
offset=peri_pin_loc)
def add_dnwell(self, bbox=None, inflate=1, add_vias=True):
def add_dnwell(self, bbox=None, inflate=1, route_option="classic"):
""" Create a dnwell, along with nwell moat at border. """
if "dnwell" not in tech_layer:
@ -2108,9 +2108,9 @@ class layout():
tap_spacing = 2
nwell_offset = vector(self.nwell_width, self.nwell_width)
# Every nth tap is connected to gnd
# Every nth tap is connected to vdd
period = 5
moat_pins = []
# BOTTOM
count = 0
loc = ll + nwell_offset.scale(tap_spacing, 0)
@ -2125,14 +2125,10 @@ class layout():
to_layer="m1",
offset=loc)
else:
if add_vias:
self.add_power_pin(name="vdd",
loc=loc,
start_layer="li")
else:
self.add_power_pin_no_via(name="vdd",
loc=loc,
start_layer="li")
pin = self.add_power_pin(name="vdd",
loc=loc,
start_layer="li")
moat_pins.append(pin)
count += 1
loc += nwell_offset.scale(tap_spacing, 0)
@ -2150,14 +2146,10 @@ class layout():
to_layer="m1",
offset=loc)
else:
if add_vias:
self.add_power_pin(name="vdd",
loc=loc,
start_layer="li")
else:
self.add_power_pin_no_via(name="vdd",
loc=loc,
start_layer="li")
pin = self.add_power_pin(name="vdd",
loc=loc,
start_layer="li")
moat_pins.append(pin)
count += 1
loc += nwell_offset.scale(tap_spacing, 0)
@ -2175,14 +2167,15 @@ class layout():
to_layer="m2",
offset=loc)
else:
if add_vias:
self.add_power_pin(name="vdd",
loc=loc,
start_layer="li")
else:
self.add_power_pin_no_via(name="vdd",
loc=loc,
start_layer="li")
if route_option == "classic":
pin = self.add_power_pin(name="vdd",
loc=loc,
start_layer="li")
elif route_option == "fast":
pin = self.add_power_pin_m2(name="vdd",
loc=loc,
start_layer="li")
moat_pins.append(pin)
count += 1
loc += nwell_offset.scale(0, tap_spacing)
@ -2200,19 +2193,21 @@ class layout():
to_layer="m2",
offset=loc)
else:
if add_vias:
self.add_power_pin(name="vdd",
loc=loc,
start_layer="li")
else:
self.add_power_pin_no_via(name="vdd",
loc=loc,
start_layer="li")
if route_option == "classic":
pin = self.add_power_pin(name="vdd",
loc=loc,
start_layer="li")
elif route_option == "fast":
pin = self.add_power_pin_m2(name="vdd",
loc=loc,
start_layer="li")
moat_pins.append(pin)
count += 1
loc += nwell_offset.scale(0, tap_spacing)
# Add the gnd ring
# Add the vdd ring
self.add_ring([ll, ur])
return moat_pins
def add_ring(self, bbox=None, width_mult=8, offset=0):
"""

View File

@ -53,8 +53,10 @@ class sram_1bank(design, verilog, lef):
# delay control logic does not have RBLs
self.has_rbl = OPTS.control_logic != "control_logic_delay"
# IO pins, except power, list of pin names
# IO pins, except power, list of pin names
self.pins_to_route = []
# vdd pins on moat, list of pins
self.moat_pins = []
def add_pins(self):
""" Add pins for entire SRAM. """
@ -248,6 +250,7 @@ class sram_1bank(design, verilog, lef):
debug.error("Must override pure virtual function.", -1)
def route_supplies_constructive(self, bbox=None):
""" Corresponding supply router for io_pin_placer """
# prepare the "router"
from openram.router.supply_placer import supply_placer as router
rtr = router(layers=self.supply_stack,
@ -255,22 +258,32 @@ class sram_1bank(design, verilog, lef):
bbox=bbox,
pin_type=OPTS.supply_pin_type,
ext_vdd_name=self.vdd_name,
ext_gnd_name=self.gnd_name)
ext_gnd_name=self.gnd_name,
moat_pins=self.moat_pins)
# add power rings / side pins
if OPTS.supply_pin_type in ["top", "bottom", "right", "left"]:
rtr.add_side_pin(self.vdd_name)
rtr.add_side_pin(self.gnd_name)
rtr.add_side_pin("vdd")
rtr.add_side_pin("gnd")# noraml gnd name
elif OPTS.supply_pin_type == "ring":
rtr.add_ring_pin(self.vdd_name)# ring vdd name
rtr.add_ring_pin(self.gnd_name)
rtr.add_ring_pin("vdd")
rtr.add_ring_pin("gnd")# normal gnd name
else:
debug.warning("Side supply pins aren't created.")
# maze router the bank power pins
# Prepare the inside power pins (all power pins of submodules), at m3
for pin_name in ["vdd", "gnd"]:
for inst in self.bank_insts:
for inst in self.insts:
self.copy_power_pins(inst, pin_name)
rtr.route_bank()
# Route all the power pins
#rtr.route_inside() # only connecting the power pins of inside submodules with each other, moat pins will connect to the ring
rtr.route_outside(io_pin_names=self.pins_to_route)
# route moat vdds
#rtr.route_moat(self.pins_to_route)
# route to the outside
#rtr.prepare_escape_pins()
def route_supplies(self, bbox=None):
""" Route the supply grid and connect the pins to them. """
@ -1114,7 +1127,7 @@ class sram_1bank(design, verilog, lef):
self.add_layout_pins()
# Some technologies have an isolation
self.add_dnwell(inflate=2.5, add_vias=False)
self.moat_pins = self.add_dnwell(inflate=2.5, route_option=route_option)
init_bbox = self.get_bbox()
# Route the supplies together and/or to the ring/stripes.

View File

@ -112,10 +112,10 @@ class router(router_tech):
def find_pins_inside(self, pin_name):
# find pins except moat, power ring, the moat pins will be store as list and return
# find pins except moat, power ring, the moat pins will be store as set and return
""" Find the pins with the given name. """
debug.info(4, "Finding all pins for {}".format(pin_name))
moat_pins = []
shape_list = self.layout.getAllPinShapes(str(pin_name))
pin_set = set()
for shape in shape_list:
@ -130,7 +130,6 @@ class router(router_tech):
continue
# skip the moat pin
if self.check_pin_on_moat(new_pin):
moat_pins.append(new_pin)
continue
# Merge previous pins into this one if possible
self.merge_shapes(new_pin, pin_set)
@ -138,7 +137,6 @@ class router(router_tech):
# Add these pins to the 'pins' dict
self.pins[pin_name] = pin_set
self.all_pins.update(pin_set)
return moat_pins
def check_pin_on_moat(self, pin_shape):

View File

@ -89,6 +89,8 @@ class router_tech:
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
self.layer_widths = [self.track_wire, 1, self.track_wire]
# via2 to via3 distance requirements
self.via2_via3_pitch = 0.5 * drc("minwidth_{}".format("via2")) + 0.5 * drc("minwidth_{}".format("via3")) + drc["via3_to_via2"]
def same_lpp(self, lpp1, lpp2):
"""

View File

@ -12,7 +12,7 @@ from .router import router
class supply_placer(router):
def __init__(self, layers, design, bbox=None, pin_type=None, ext_vdd_name="vccd1", ext_gnd_name="vssd1"):
def __init__(self, layers, design, bbox=None, pin_type=None, ext_vdd_name="vccd1", ext_gnd_name="vssd1", moat_pins=None):
# `router` is the base router class
router.__init__(self, layers, design, bbox)
@ -28,14 +28,23 @@ class supply_placer(router):
# instances
self.insts = self.design.insts
# moat pins
self.moat_pins = []
self.moat_pins = moat_pins
# store a graphshape of intermediate points(if shift)/source points(if no shift) when connecting moat_pins to outside
# trick: since in the creation of dnwell, these pins are "ordered" added, so they'are also ordered here
# order inside list: left -> right or bottom -> up
self.moat_pins_left = []
self.moat_pins_right = []
self.moat_pins_top = []
self.moat_pins_bottom = []
# io pins
self.io_pins_left = []
self.io_pins_right = []
self.io_pins_top = []
self.io_pins_bottom = []
def route_bank(self, vdd_name="vdd", gnd_name="gnd"):
def route_outside(self, vdd_name="vdd", gnd_name="gnd", io_pin_names=None):
# only connect supply with inside submodules, not connecting to the power ring
debug.info(1, "Running router for {} and {}...".format(vdd_name, gnd_name))
# Save pin names
@ -46,7 +55,75 @@ class supply_placer(router):
self.prepare_gds_reader()
# Find vdd/gnd pins of bank, to be routed
self.moat_pins = self.find_pins_inside(vdd_name)
self.find_pins_inside(vdd_name)
self.find_pins_inside(gnd_name)
self.route_moat(io_pin_names)
# Find blockages and vias
self.find_blockages()
self.find_vias()
# Convert blockages and vias if they overlap a pin
self.convert_vias()
self.convert_blockages()
# Add vdd and gnd pins as blockages as well
# NOTE: This is done to make vdd and gnd pins DRC-safe
for pin in self.all_pins:
self.blockages.append(self.inflate_shape(pin))
# Prepare the selected moat pins
selected_moat_pins = self.prepare_selected_moat_pins()
# Route vdd and gnd
routed_count = 0
routed_max = len(self.pins[vdd_name]) + len(self.pins[gnd_name])
for pin_name in [vdd_name, gnd_name]:
if pin_name == gnd_name: # otherwise will not recognaize the moat blocakge
self.prepare_gds_reader()
# Find blockages and vias
self.find_blockages()
self.find_vias()
# Convert blockages and vias if they overlap a pin
self.convert_vias()
self.convert_blockages()
pins = self.pins[pin_name]
# Route closest pins according to the minimum spanning tree
for source, target in self.get_mst_with_ring(list(pins), selected_moat_pins, pin_name):
# Create the graph
g = graph(self)
g.create_graph(source, target)
# Find the shortest path from source to target
path = g.find_shortest_path()
# If no path is found, throw an error
if path is None:
self.write_debug_gds(gds_name="{}error.gds".format(OPTS.openram_temp), g=g, source=source, target=target)
debug.error("Couldn't route from {} to {}.".format(source, target), -1)
# Create the path shapes on layout
new_wires, new_vias = self.add_path(path)
# Find the recently added shapes
self.find_blockages(pin_name, new_wires)
self.find_vias(new_vias)
# Report routed count
routed_count += 1
debug.info(2, "Routed {} of {} supply pins".format(routed_count, routed_max))
# finsih
self.replace_layout_pins()
def route_inside(self, vdd_name="vdd", gnd_name="gnd"):
# only connect supply with inside submodules, not connecting to the power ring
debug.info(1, "Running router for {} and {}...".format(vdd_name, gnd_name))
# Save pin names
self.vdd_name = vdd_name
self.gnd_name = gnd_name
# Prepare gdsMill to find pins and blockages
self.prepare_gds_reader()
# Find vdd/gnd pins of bank, to be routed
self.find_pins_inside(vdd_name)
self.find_pins_inside(gnd_name)
# Find blockages and vias
@ -86,14 +163,152 @@ class supply_placer(router):
# Report routed count
routed_count += 1
debug.info(2, "Routed {} of {} supply pins".format(routed_count, routed_max))
# finsih
self.replace_layout_pins()
#def route_moat(self):
def route_moat(self, io_pin_names):
# route the vdd pins at the moat
# io_pin_names is a list
# the moat vdd shape will also be created and stored in the list
for moat_pin in self.moat_pins:
self.check_overlap(moat_pin, io_pin_names)
def replace_layout_pins(self):
# clear all the inside "vdd " "gnd" at sram module level
# Copy the pin shape(s) to rectangles
for pin_name in ["vdd", "gnd"]:
# Copy the pin shape(s) to rectangles
for pin in self.design.get_pins(pin_name):
self.design.add_rect(pin.layer,
pin.ll(),
pin.width(),
pin.height())
# Remove the pin shape(s)
self.design.remove_layout_pin(pin_name)
#def route_other(self):
# Get new pins, change the name of ring to extern supply name
# vccd1 ring
pins = self.get_new_pins("vdd")
for pin in pins:
self.design.add_layout_pin(self.ext_vdd_name,
pin.layer,
pin.ll(),
pin.width(),
pin.height())
# vssd1 ring
pins = self.get_new_pins("gnd")
for pin in pins:
self.design.add_layout_pin(self.ext_gnd_name,
pin.layer,
pin.ll(),
pin.width(),
pin.height())
def prepare_selected_moat_pins(self):
""" Selcet the possibe moat pins, feed into the MST, where will decide which of these pin should be connected to which pin """
if len(self.design.all_ports) > 1:
# in order to save runtime
# top -> moat pins all
# bottom -> moat pins all
# left -> moat pins near control logic
# right -> moat pins near control logic
# expected connection for control logic
# for port 0 -> left
start_y = self.design.control_logic_insts[0].by()# bottom edge y value
end_y = self.design.control_logic_insts[0].uy()# up edge y value
# filter the pin in the range
filtered_moat_pins_left = [pin for pin in self.moat_pins_left if start_y <= pin.center().y <= end_y]
# for port 1 -> right
start_y = self.design.control_logic_insts[1].by()# bottom edge y value
end_y = self.design.control_logic_insts[1].uy()# up edge y value
# filter the pin in the range
filtered_moat_pins_right = [pin for pin in self.moat_pins_right if start_y <= pin.center().y <= end_y]
# return the selected moat pins
selected_moat_pins = []
selected_moat_pins.extend(filtered_moat_pins_left)
selected_moat_pins.extend(self.moat_pins_bottom)
selected_moat_pins.extend(filtered_moat_pins_right)
selected_moat_pins.extend(self.moat_pins_top)
return selected_moat_pins
else: # only 1 port
# in order to save runtime
# top -> moat pins all
# bottom -> moat pins all
# left -> moat pins near control logic
# right -> moat pins all
start_y = self.design.control_logic_insts[0].by()# bottom edge y value
end_y = self.design.control_logic_insts[0].uy()# up edge y value
# filter the pin in the range
filtered_moat_pins_left = [pin for pin in self.moat_pins_left if start_y <= pin.center().y <= end_y]
# return the selected moat pins
selected_moat_pins = []
selected_moat_pins.extend(filtered_moat_pins_left)
selected_moat_pins.extend(self.moat_pins_bottom)
selected_moat_pins.extend(self.moat_pins_right)
selected_moat_pins.extend(self.moat_pins_top)
return selected_moat_pins
def prepare_escape_pins(self):
# clear all the inside "vdd " "gnd" at sram module level
# Copy the pin shape(s) to rectangles
for pin_name in ["vdd", "gnd"]:
# Copy the pin shape(s) to rectangles
for pin in self.design.get_pins(pin_name):
self.design.add_rect(pin.layer,
pin.ll(),
pin.width(),
pin.height())
# Remove the pin shape(s)
self.design.remove_layout_pin(pin_name)
# prepare pins for every instances
for pin_name in ["vdd"]:
count =0
for pin in self.design.control_logic_insts[0].get_pins(pin_name):
debug.warning("vdd pin shape -> ll:{0} ur:{1}".format(pin.ll(), pin.ur()))
"""
count = count + 1
new_pin = graph_shape("gnd", pin.rect, pin.layer)
source = new_pin
source_center_x = pin.center().x
target_ur_y = self.new_pins[self.ext_gnd_name][1].center().y + 0.5 * self.new_pins[self.ext_gnd_name][1].height()
ll = vector(source_center_x - 2.6 - 0.5 * self.track_wire, pin.center().y - 0.5 * self.track_wire)#target_ur_y - self.track_wire)
ur = vector(source_center_x - 2.6 + 0.5 * self.track_wire, pin.center().y + 0.5 * self.track_wire)#target_ur_y)
target = graph_shape("fake", [ll,ur], pin.layer)
# Create the graph
g = graph(self)
g.create_graph(source, target)
# Find the shortest path from source to target
path = g.find_shortest_path()
# If no path is found, throw an error
if path is None:
self.write_debug_gds(gds_name="{}error.gds".format(OPTS.openram_temp), g=g, source=source, target=target)
debug.error("Couldn't route from {} to {}.".format(source, target), -1)
# Create the path shapes on layout
new_wires, new_vias = self.add_path(path)
# Find the recently added shapes
self.find_blockages(pin_name, new_wires)
self.find_vias(new_vias)
"""
debug.warning("vdd of wmask number -> {0}".format(count))
debug.warning("instance postion -> {0} {1}".format(self.design.control_logic_insts[0].lx(), self.design.control_logic_insts[0].by()))
# print pins_all
for pin in self.all_pins:
debug.warning("all_pins -> {0}".format(pin))
def check_overlap(self, moat_pin, io_pin_names):
# use all the IO pins(at correspoding edge) to check overlap, check 1 moat vdd pin, give the corresponding target/source position as list, and pull the source up to m3
# use all the IO pins(at correspoding edge) to check overlap, check 1 moat vdd pin, give the corresponding target/source position as list, and connect them
add_distance = 0
direction = 1
self.prepare_io_pins(io_pin_names)
@ -101,36 +316,294 @@ class supply_placer(router):
edge = self.get_closest_edge(moat_pin)
source_center = moat_pin.center()
if edge == "bottom":
add_distance = self.via2_via3_pitch # if shift, need to fulfill via2-via3 spacing, top/bottom only
pin_too_close = any(abs(io_pin.center().x - source_center.x) < self.track_width for io_pin in self.io_pins_bottom)
tmp_center = source_center
tmp_center = vector(source_center.x, source_center.y)
while pin_too_close:
tmp_center = source_center
tmp_center = vector(source_center.x, source_center.y)
add_distance = add_distance + 0.1
if direction == 1: # right shift
tmp_center = tmp_center + add_distance
tmp_center = vector((tmp_center.x + add_distance), tmp_center.y)
else: # left shift
tmp_center = tmp_center - add_distance
tmp_center = vector((tmp_center.x - add_distance), tmp_center.y)
pin_too_close = any(abs(io_pin.center().x - tmp_center.x) < self.track_width for io_pin in self.io_pins_bottom)
direction = - direction
# the nearst vdd ring
vdd_ring = self.new_pins["vdd"][1] # order in list -> "top", "bottom", "right", "left"]
# bottom ring's y position at it's top
target_egde_y = vdd_ring.center().y + 0.5 * vdd_ring.height()
if tmp_center == source_center: # no overlap
# no jog, direct pull to m3
self.design.copy_power_pin(moat_pin, loc=None, directions=None, new_name="")
# no jog, direct return the source/target center position
# the target center position, should consider enought space for via
target_point = vector(tmp_center.x, (target_egde_y - 0.5 * self.track_wire))
source_point = vector(tmp_center.x, tmp_center.y)
point_list = [source_point, target_point]
self.add_wire(point_list, vertical=True)
# store the shape of moat pins, need for route later
ll = vector(source_point.x - 0.5 * self.track_wire, source_point.y - 0.5 * self.track_wire)
ur = vector(source_point.x + 0.5 * self.track_wire, source_point.y + 0.5 * self.track_wire)
rect = [ll, ur]
moat_pin_route = graph_shape("vdd", rect, "m4")
self.moat_pins_bottom.append(moat_pin_route)
else: # need jog
# shift the center
# add rectangle at same layer (original)
self.design.add
intermediate_point = vector(tmp_center.x, tmp_center.y)
source_point = vector(source_center.x, source_center.y)
target_point = vector(tmp_center.x, (target_egde_y - 0.5 * self.track_wire))
point_list = [source_point, intermediate_point, target_point]
self.add_wire(point_list, vertical=True)
# store the shape of moat pins, need for route later
ll = vector(intermediate_point.x - 0.5 * self.track_wire, intermediate_point.y - 0.5 * self.track_wire)
ur = vector(intermediate_point.x + 0.5 * self.track_wire, intermediate_point.y + 0.5 * self.track_wire)
rect = [ll, ur]
moat_pin_route = graph_shape("vdd", rect, "m4")
self.moat_pins_bottom.append(moat_pin_route)
elif edge == "top":
pass
add_distance = self.via2_via3_pitch # if shift, need to fulfill via2-via3 spacing, top/bottom only
pin_too_close = any(abs(io_pin.center().x - source_center.x) < self.track_width for io_pin in self.io_pins_top)
tmp_center = vector(source_center.x, source_center.y)
while pin_too_close:
tmp_center = vector(source_center.x, source_center.y)
add_distance = add_distance + 0.1
if direction == 1: # right shift
tmp_center = vector((tmp_center.x + add_distance), tmp_center.y)
else: # left shift
tmp_center = vector((tmp_center.x - add_distance), tmp_center.y)
pin_too_close = any(abs(io_pin.center().x - tmp_center.x) < self.track_width for io_pin in self.io_pins_top)
direction = - direction
# the nearst vdd ring
vdd_ring = self.new_pins["vdd"][0] # order in list -> "top", "bottom", "right", "left"]
# top ring's y position at it's bottom
target_egde_y = vdd_ring.center().y - 0.5 * vdd_ring.height()
if tmp_center == source_center: # no overlap
# no jog, direct return the source/target center position
# the target center position, should consider enought space for via
target_point = vector(tmp_center.x, (target_egde_y + 0.5 * self.track_wire))
source_point = vector(tmp_center.x, tmp_center.y)
point_list = [source_point, target_point]
self.add_wire(point_list, vertical=True)
# store the shape of moat pins, need for route later
ll = vector(source_point.x - 0.5 * self.track_wire, source_point.y - 0.5 * self.track_wire)
ur = vector(source_point.x + 0.5 * self.track_wire, source_point.y + 0.5 * self.track_wire)
rect = [ll, ur]
moat_pin_route = graph_shape("vdd", rect, "m4")
self.moat_pins_top.append(moat_pin_route)
else: # need jog
# shift the center
# add rectangle at same layer (original)
intermediate_point = vector(tmp_center.x, tmp_center.y)
source_point = vector(source_center.x, source_center.y)
target_point = vector(tmp_center.x, (target_egde_y + 0.5 * self.track_wire))
point_list = [source_point, intermediate_point, target_point]
self.add_wire(point_list, vertical=True)
# store the shape of moat pins, need for route later
ll = vector(intermediate_point.x - 0.5 * self.track_wire, intermediate_point.y - 0.5 * self.track_wire)
ur = vector(intermediate_point.x + 0.5 * self.track_wire, intermediate_point.y + 0.5 * self.track_wire)
rect = [ll, ur]
moat_pin_route = graph_shape("vdd", rect, "m4")
self.moat_pins_top.append(moat_pin_route)
elif edge == "left":
pass
pin_too_close = any(abs(io_pin.center().y - source_center.y) < self.track_width for io_pin in self.io_pins_left)
tmp_center = vector(source_center.x, source_center.y)
while pin_too_close:
tmp_center = vector(source_center.x, source_center.y)
add_distance = add_distance + 0.1
if direction == 1: # up shift
tmp_center = vector(tmp_center.x, (tmp_center.y + add_distance))
else: # down shift
tmp_center = vector(tmp_center.x, (tmp_center.y - add_distance))
pin_too_close = any(abs(io_pin.center().y - tmp_center.y) < self.track_width for io_pin in self.io_pins_left)
direction = - direction
# the nearst vdd ring
vdd_ring = self.new_pins["vdd"][3] # order in list -> "top", "bottom", "right", "left"]
# left ring's x position at it's right
target_egde_x = vdd_ring.center().x + 0.5 * vdd_ring.width()
if tmp_center == source_center: # no overlap
# no jog, direct return the source/target center position
# the target center position, should consider enought space for via
target_point = vector((target_egde_x - 0.5 * self.track_wire), tmp_center.y)
source_point = vector(tmp_center.x, tmp_center.y)
point_list = [source_point, target_point]
self.add_wire(point_list, vertical=False)
# store the shape of moat pins, need for route later
ll = vector(source_point.x - 0.5 * self.track_wire, source_point.y - 0.5 * self.track_wire)
ur = vector(source_point.x + 0.5 * self.track_wire, source_point.y + 0.5 * self.track_wire)
rect = [ll, ur]
moat_pin_route = graph_shape("vdd", rect, "m3")
self.moat_pins_left.append(moat_pin_route)
else: # need jog
# shift the center
# add rectangle at same layer (original)
intermediate_point = vector(tmp_center.x, tmp_center.y)
source_point = vector(source_center.x, source_center.y)
target_point = vector((target_egde_x - 0.5 * self.track_wire), tmp_center.y)
point_list = [source_point, intermediate_point, target_point]
self.add_wire(point_list, vertical=False)
# store the shape of moat pins, need for route later
ll = vector(intermediate_point.x - 0.5 * self.track_wire, intermediate_point.y - 0.5 * self.track_wire)
ur = vector(intermediate_point.x + 0.5 * self.track_wire, intermediate_point.y + 0.5 * self.track_wire)
rect = [ll, ur]
moat_pin_route = graph_shape("vdd", rect, "m3")
self.moat_pins_left.append(moat_pin_route)
else: #right
pass
pin_too_close = any(abs(io_pin.center().y - source_center.y) < self.track_width for io_pin in self.io_pins_right)
tmp_center = vector(source_center.x, source_center.y)
while pin_too_close:
tmp_center = vector(source_center.x, source_center.y)
add_distance = add_distance + 0.1
if direction == 1: # up shift
tmp_center = vector(tmp_center.x, (tmp_center.y + add_distance))
else: # down shift
tmp_center = vector(tmp_center.x, (tmp_center.y - add_distance))
pin_too_close = any(abs(io_pin.center().y - tmp_center.y) < self.track_width for io_pin in self.io_pins_right)
direction = - direction
# the nearst vdd ring
vdd_ring = self.new_pins["vdd"][2] # order in list -> "top", "bottom", "right", "left"]
# right ring's y position at it's left
target_egde_x = vdd_ring.center().x - 0.5 * vdd_ring.width()
if tmp_center == source_center: # no overlap
# no jog, direct return the source/target center position
# the target center position, should consider enought space for via
target_point = vector((target_egde_x + 0.5 * self.track_wire), tmp_center.y)
source_point = vector(tmp_center.x, tmp_center.y)
point_list = [source_point, target_point]
self.add_wire(point_list, vertical=False)
# store the shape of moat pins, need for route later
ll = vector(source_point.x - 0.5 * self.track_wire, source_point.y - 0.5 * self.track_wire)
ur = vector(source_point.x + 0.5 * self.track_wire, source_point.y + 0.5 * self.track_wire)
rect = [ll, ur]
moat_pin_route = graph_shape("vdd", rect, "m3")
self.moat_pins_right.append(moat_pin_route)
else: # need jog
# shift the center
# add rectangle at same layer (original)
intermediate_point = vector(tmp_center.x, tmp_center.y)
source_point = vector(source_center.x, source_center.y)
target_point = vector((target_egde_x + 0.5 * self.track_wire) ,tmp_center.y)
point_list = [source_point, intermediate_point, target_point]
self.add_wire(point_list, vertical=False)
# store the shape of moat pins, need for route later
ll = vector(intermediate_point.x - 0.5 * self.track_wire, intermediate_point.y - 0.5 * self.track_wire)
ur = vector(intermediate_point.x + 0.5 * self.track_wire, intermediate_point.y + 0.5 * self.track_wire)
rect = [ll, ur]
moat_pin_route = graph_shape("vdd", rect, "m3")
self.moat_pins_right.append(moat_pin_route)
def add_wire(self, point_list, vertical=False):
if vertical == True: # m4 line, need start via3(m3 -> m4), end via3(m3 -> m4)
if len(point_list) == 2: # direct connect
# start via
self.add_via(point=point_list[0],
from_layer="m3",
to_layer="m4")
self.add_via(point=point_list[0],
from_layer="m4",
to_layer="m4") # shape
# connection
self.add_line(point_1=point_list[0],
point_2=point_list[1],
layer="m4")
# end via
self.add_via(point=point_list[1],
from_layer="m3",
to_layer="m4")
self.add_via(point=point_list[1],
from_layer="m4",
to_layer="m4") # shape
elif len(point_list) == 3: # need intermediate point
# jog
self.add_line(point_1=point_list[0],
point_2=point_list[1],
layer="m3")
# start_via
self.add_via(point=point_list[1],
from_layer="m3",
to_layer="m4")
self.add_via(point=point_list[1],
from_layer="m3",
to_layer="m3") # shape
# connection
self.add_line(point_1=point_list[1],
point_2=point_list[2],
layer="m4")
# end via
self.add_via(point=point_list[2],
from_layer="m3",
to_layer="m4")
self.add_via(point=point_list[2],
from_layer="m4",
to_layer="m4") # shape
else: # m3 line, need start via2(m2 -> m3), end via3(m3 -> m4)
if len(point_list) == 2: # direct connect
# start via
self.add_via(point=point_list[0],
from_layer="m2",
to_layer="m3")
self.add_via(point=point_list[0],
from_layer="m3",
to_layer="m3") # shape
# connection
self.add_line(point_1=point_list[0],
point_2=point_list[1],
layer="m3")
# end via
self.add_via(point=point_list[1],
from_layer="m3",
to_layer="m4")
self.add_via(point=point_list[1],
from_layer="m3",
to_layer="m3") # shape
elif len(point_list) == 3: # need intermediate point
# jog
self.add_line(point_1=point_list[0],
point_2=point_list[1],
layer="m2")
# start_via
self.add_via(point=point_list[1],
from_layer="m2",
to_layer="m3")
self.add_via(point=point_list[1],
from_layer="m3",
to_layer="m3") # shape
# connection
self.add_line(point_1=point_list[1],
point_2=point_list[2],
layer="m3")
# end via
self.add_via(point=point_list[2],
from_layer="m3",
to_layer="m4")
self.add_via(point=point_list[2],
from_layer="m3",
to_layer="m3") # shape
def add_line(self, point_1, point_2, layer="m3"): # "m2", "m3", "m4"
self.design.add_path(layer, [point_1, point_2], self.track_wire)
def add_via(self, point, from_layer="m3", to_layer="m4"):
# via could be via2(m2 -> m3), via3(m3 -> m4)
# or a shape at same layer
if from_layer == to_layer:
self.design.add_rect_center(layer=from_layer,
offset=point,
width=self.track_wire,
height=self.track_wire)
else:
self.design.add_via_stack_center(from_layer=from_layer,
to_layer=to_layer,
offset=point)
def prepare_io_pins(self, io_pin_names):
# io_pin_names is a list
# find all the io pins
for pin_name in io_pin_names:
self.find_pins(pin_name)# pin now in self.pins
io_pin = self.pins[pin_name]
io_pin = next(iter(self.pins[pin_name]))
self.find_closest_edge(io_pin)
@ -139,6 +612,7 @@ class supply_placer(router):
ll, ur = self.bbox
point = pin.center()
debug.warning("moat pin center -> {0}".format(point))
# Snap the pin to the perimeter and break the iteration
ll_diff_x = abs(point.x - ll.x)
ll_diff_y = abs(point.y - ll.y)
@ -159,6 +633,7 @@ class supply_placer(router):
""" Use to find the edge, where the io pin locats """
ll, ur = self.bbox
#debug.warning("pin -> {0}".format(pin))
point = pin.center()
# Snap the pin to the perimeter and break the iteration
ll_diff_x = abs(point.x - ll.x)
@ -182,7 +657,7 @@ class supply_placer(router):
ll, ur = self.bbox
vertical = side in ["left", "right"]
inner = pin_name == self.ext_vdd_name
inner = pin_name == "vdd"
# Calculate wires' wideness
wideness = self.track_wire * num_vias + self.track_space * (num_vias - 1)
@ -225,29 +700,7 @@ class supply_placer(router):
width=shape_width,
height=shape_height)
# Add fake pins on this new pin evenly
fake_pins = []
if vertical:
space = (shape_height - (2 * wideness) - num_fake_pins * self.track_wire) / (num_fake_pins + 1)
start_offset = vector(offset.x, offset.y + wideness)
else:
space = (shape_width - (2 * wideness) - num_fake_pins * self.track_wire) / (num_fake_pins + 1)
start_offset = vector(offset.x + wideness, offset.y)
for i in range(1, num_fake_pins + 1):
if vertical:
offset = vector(start_offset.x, start_offset.y + i * (space + self.track_wire))
ll = vector(offset.x, offset.y - self.track_wire)
ur = vector(offset.x + wideness, offset.y)
else:
offset = vector(start_offset.x + i * (space + self.track_wire), start_offset.y)
ll = vector(offset.x - self.track_wire, offset.y)
ur = vector(offset.x, offset.y + wideness)
rect = [ll, ur]
fake_pin = graph_shape(name=pin_name,
rect=rect,
layer_name_pp=layer)
fake_pins.append(fake_pin)
return pin, fake_pins
return pin
def add_ring_pin(self, pin_name, num_vias=3, num_fake_pins=4):
@ -256,7 +709,7 @@ class supply_placer(router):
# Add side pins
new_pins = []
for side in ["top", "bottom", "right", "left"]:
new_shape, fake_pins = self.add_side_pin(pin_name, side, num_vias, num_fake_pins)
new_shape = self.add_side_pin(pin_name, side, num_vias, num_fake_pins)
ll, ur = new_shape.rect
rect = [ll, ur]
layer = self.get_layer(side in ["left", "right"])
@ -264,8 +717,6 @@ class supply_placer(router):
rect=rect,
layer_name_pp=layer)
new_pins.append(new_pin)
#self.pins[pin_name].update(fake_pins)
self.fake_pins.extend(fake_pins)
# Add vias to the corners
shift = self.track_wire + self.track_space
@ -338,6 +789,56 @@ class supply_placer(router):
return mst_pairs
def get_mst_with_ring(self, pins, ring_pins, pin_name="vdd"):
"""
Extend the MST logic to connect internal pins to the nearest external ring pins.
"""
# Prepare the pins that are allowed to connect to the moat pins.
# Specical handle gnd ring
candidate_pins = []
max_distance = 13
if pin_name == "gnd":
ring_pins = []
ring_pins = self.new_pins[pin_name]
for pin in pins:
for ring_pin in ring_pins:
dist = pin.distance(ring_pin)
if max_distance is None or dist <= max_distance:
candidate_pins.append(pin)
break
# Compute the MST for internal pins
mst_pairs = self.get_mst_pairs(pins)
# Connect each internal pin to the nearest external ring pin
used_ring_pins = set()
internal_to_ring_pairs = []
for pin in candidate_pins:
min_distance = float("inf")
nearest_ring_pin = None
for ring_pin in ring_pins:
if pin_name == "vdd" and ring_pin in used_ring_pins:
continue
dist = pin.distance(ring_pin)
if dist < min_distance:
min_distance = dist
nearest_ring_pin = ring_pin
# Add the connection to the nearest ring pin
if nearest_ring_pin:
internal_to_ring_pairs.append((pin, nearest_ring_pin))
# Mark the ring pin as used if the pin is VDD
if pin_name == "vdd":
used_ring_pins.add(nearest_ring_pin)
# Combine internal MST pairs and external connections
full_connections = mst_pairs + internal_to_ring_pairs
return full_connections
def get_new_pins(self, name):
""" Return the new supply pins added by this router. """

View File

@ -169,7 +169,7 @@ class sram():
spname = OPTS.output_path + self.s.name + ".sp"
debug.print_raw("SP: Writing to {0}".format(spname))
self.sp_write(spname)
#''' #comment the following state when generating big sram, and then disable drc/lvs, because maigc_ext stuck
''' #comment the following state when generating big sram, and then disable drc/lvs, because maigc_ext stuck
# Save a functional simulation file with default period
functional(self.s,
spname,
@ -191,7 +191,7 @@ class sram():
d.targ_write_ports = [self.s.write_ports[0]]
d.write_delay_stimulus()
print_time("DELAY", datetime.datetime.now(), start_time)
#''' #comment the above when generating big sram, and then disable drc/lvs, bevause magic_ext stuck
''' #comment the above when generating big sram, and then disable drc/lvs, bevause magic_ext stuck
# Save trimmed spice file
temp_trim_sp = "{0}trimmed.sp".format(OPTS.output_path)
self.sp_write(temp_trim_sp, lvs=False, trim=True)