updata io_pin_placer

This commit is contained in:
FriedrichWu 2024-10-30 13:24:53 +01:00
parent ee6be23cfa
commit 61f5ff6ec4
1 changed files with 369 additions and 24 deletions

View File

@ -13,9 +13,6 @@ from .router import router
import re import re
class io_pin_placer(router): class io_pin_placer(router):
"""
This is the signal escape router that uses the Hanan grid graph method.
"""
def __init__(self, layers, design, bbox=None): def __init__(self, layers, design, bbox=None):
@ -30,6 +27,9 @@ class io_pin_placer(router):
self.io_pins_added_right = [] self.io_pins_added_right = []
self.io_pins_added_up = [] self.io_pins_added_up = []
self.io_pins_added_down = [] self.io_pins_added_down = []
# fake_pins, use for rename
self.io_pins_fake =[]
def get_closest_edge(self, point): def get_closest_edge(self, point):
@ -51,8 +51,162 @@ class io_pin_placer(router):
if min_diff == ur_diff_x: if min_diff == ur_diff_x:
return "right", True return "right", True
return "top", False return "top", False
def initial_position(self, pins): # pins is list []
""" Set the IO pin center at the perimeter """
pattern_clk = r'^clk'
pattern_addr0 = r'^addr0'
pattern_addr1 = r'^addr1'
pattern_dout0 = r'^dout0'
pattern_dout1 = r'^dout1'
pattern_din = r'^din'
pattern_wmask = r'^wmask'
pattern_spare_wen = r'^spare_wen'
pattern_web = r'^web'
pattern_csb = r'^csb'
for pin in pins:
c = pin.center()
# Find the closest edge
edge, vertical = self.get_closest_edge(c)
if re.match(pattern_clk, pin.name):# clk, should be placed at horizontal edge
if edge == "bottom" or edge == "left":
edge = "bottom"
elif edge == "top" or edge == "right":
edge = "top"
self.store_position(pin, edge, vertical)
if re.match(pattern_addr0, pin.name): # all the addr0[] should be placed at left edge
if edge == "top" or edge == "left":
edge = "left"
vertical = True
elif edge == "bottom": # but for big sram, addr0[] may have pins at bottom, which is allowed
vertical = False
self.store_position(pin, edge, vertical)
if re.match(pattern_addr1, pin.name): # all the addr1[] should be placed at right edge
if edge == "bottom" or edge == "right":
edge = "right"
vertical = True
elif edge == "top": # but for big sram, addr1[] may have pins at top, which is allowed
vertical = False
self.store_position(pin, edge, vertical)
if re.match(pattern_din, pin.name): # din
self.store_position(pin, edge, vertical)
if re.match(pattern_wmask, pin.name): # wmask
self.store_position(pin, edge, vertical)
if re.match(pattern_spare_wen, pin.name): # spare_wen
self.store_position(pin, edge, vertical)
if re.match(pattern_csb, pin.name):# csb
self.store_position(pin, edge, vertical)
if re.match(pattern_web, pin.name): # web
self.store_position(pin, edge, vertical)
# special handle the dout pins, if r/rw ports
for pin in pins:
if re.match(pattern_dout0, pin.name):
edge = "bottom"
vertical = False
self.store_dout_position(pin, edge, vertical)
if re.match(pattern_dout1, pin.name):
edge = "top"
vertical = False
self.store_dout_position(pin, edge, vertical)
def check_overlap(self, pin_position, edge):
""" Return the suggested position to aviod overlap """
ll, ur = self.bbox
c = pin_position # original source pin center
offset = 0.95 + 0.19 # FIX: this is the magic number to overcome the ovetflow problem at the boundary, may need a method
add_distance = 0
if edge == "bottom":
fake_center = vector(c.x, ll.y - self.track_wire * 2 + offset)
pin_to_close = any(abs(pin_added.center().x - fake_center.x) < (0.4 + self.half_wire * 4)for pin_added in self.io_pins_added_down)
via_to_close = False
# if cannot direct place below the source pin, need move towards right, and ensure the min. distance between vias
while pin_to_close or via_to_close:
debug.warning("overlap, changing position")
add_distance = add_distance + 0.1
fake_center = vector(c.x + add_distance, ll.y - self.track_wire * 2 + offset)
pin_to_close = any(abs(pin_added.center().x - fake_center.x) < (0.4 + self.half_wire * 4)for pin_added in self.io_pins_added_down)
via_to_close = abs(fake_center.x - c.x) < 0.6
if edge == "top":
fake_center = vector(c.x, ur.y + self.track_wire * 2 - offset)
pin_to_close = any(abs(pin_added.center().x - fake_center.x) < (0.4 + self.half_wire * 4)for pin_added in self.io_pins_added_up)
via_to_close = False
# if cannot direct place below the source pin, need move towards right, and ensure the min. distance between vias
while pin_to_close or via_to_close:
debug.warning("overlap, changing position")
add_distance = add_distance + 0.1
fake_center = vector(c.x + add_distance, ur.y + self.track_wire * 2 - offset)
pin_to_close = any(abs(pin_added.center().x - fake_center.x) < (0.4 + self.half_wire * 4)for pin_added in self.io_pins_added_up)
via_to_close = abs(fake_center.x - c.x) < 0.6
return fake_center
def store_dout_position(self, pin, edge, vertical):
pin_position = pin.center()
pin_position = self.check_overlap(pin_position, edge)
# store the center position, rect, layer of fake pin, here make sure the pin in the gds will be big enough
layer = self.get_layer(int(not vertical))
half_wire_vector = vector([self.half_wire] * 2)
nll = pin_position - half_wire_vector - half_wire_vector
nur = pin_position + half_wire_vector + half_wire_vector
rect = [nll, nur]
#fake_pin = [pin.name() + "_" + "fake", pin_position, rect, layer]
fake_pin = graph_shape(name=pin.name + "_" + "fake",
rect=rect,
layer_name_pp=layer)
if edge == "left":
self.io_pins_added_left.append(fake_pin)
elif edge == "bottom":
self.io_pins_added_down.append(fake_pin)
elif edge == "right":
self.io_pins_added_right.append(fake_pin)
elif edge == "top":
self.io_pins_added_up.append(fake_pin)
self.io_pins_fake.append(fake_pin)
debug.warning("pin added: {0}".format(fake_pin))
def store_position(self, pin, edge, vertical): # also need to store the source pin
ll, ur = self.bbox
c = pin.center()
offset = 0.95 + 0.19 # FIX: this is the magic number to overcome the ovetflow problem at the boundary, may need a method
if edge == "left":
fake_center = vector(ll.x - self.track_wire * 2 + offset, c.y)
if edge == "bottom":
fake_center = vector(c.x, ll.y - self.track_wire * 2 + offset)
if edge == "right":
fake_center = vector(ur.x + self.track_wire * 2 - offset, c.y)
if edge == "top":
fake_center = vector(c.x, ur.y + self.track_wire * 2 - offset)
# store the center position, rect, layer of fake pin, here make sure the pin in the gds will be big enough
layer = self.get_layer(int(not vertical))
half_wire_vector = vector([self.half_wire] * 2)
nll = fake_center - half_wire_vector - half_wire_vector
nur = fake_center + half_wire_vector + half_wire_vector
rect = [nll, nur]
#fake_pin = [pin.name() + "_" + "fake", fake_center, rect, layer]
fake_pin = graph_shape(name=pin.name + "_" + "fake",
rect=rect,
layer_name_pp=layer)
if edge == "left":
self.io_pins_added_left.append(fake_pin)
elif edge == "bottom":
self.io_pins_added_down.append(fake_pin)
elif edge == "right":
self.io_pins_added_right.append(fake_pin)
elif edge == "top":
self.io_pins_added_up.append(fake_pin)
self.io_pins_fake.append(fake_pin)
debug.warning("pin added: {0}".format(fake_pin))
def create_fake_pin(self, pin): def create_fake_pin(self, pin):
""" Create a fake pin on the perimeter orthogonal to the given pin. """ """ Create a fake pin on the perimeter orthogonal to the given pin. """
@ -63,51 +217,70 @@ class io_pin_placer(router):
print(pin.name) print(pin.name)
# Find the closest edge # Find the closest edge
edge, vertical = self.get_closest_edge(c) edge, vertical = self.get_closest_edge(c)
# Relocate the pin position of addr/dout
pattern_addr = r'^addr'
pattern_dout = r'^dout'
if re.match(pattern_addr, pin.name):# all the addr[] should be placed at vertical edge
if edge == "top" or edge == "left":
edge = "left"
vertical = True
elif edge == "bottom" or edge == "right":
edge = "right"
vertical = True
if re.match(pattern_dout, pin.name):# all the dout[] should be placed at horizontal edge
if edge == "bottom" or edge == "right":
edge = "bottom"
vertical = False
elif edge == "top" or edge == "left":
edge = "top"
vertical = False
offset = 0.95 + 0.19 # FIX: this is the magic number to overcome the ovetflow problem at the boundary, may need a method offset = 0.95 + 0.19 # FIX: this is the magic number to overcome the ovetflow problem at the boundary, may need a method
add_distance = 0 add_distance = 0
# Keep the fake pin out of the SRAM layout are so that they won't be # Keep the fake pin out of the SRAM layout are so that they won't be
# blocked by previous signals if they're on the same orthogonal line # blocked by previous signals if they're on the same orthogonal line
if edge == "left": if edge == "left":
fake_center = vector(ll.x - self.track_wire * 2 + offset, c.y) fake_center = vector(ll.x - self.track_wire * 2 + offset, c.y)
is_too_close = any(abs(pin_added.center().y - fake_center.y) < (0.8 + self.half_wire * 4)for pin_added in self.io_pins_added_left) is_too_close = any(abs(pin_added.center().y - fake_center.y) < (0.4 + self.half_wire * 4)for pin_added in self.io_pins_added_left)
while is_too_close: while is_too_close:
debug.warning("overlap, changing position") debug.warning("overlap, changing position")
add_distance = add_distance + 0.8 + self.half_wire * 4 add_distance = add_distance + 0.1#+ 0.4 + self.half_wire * 4
fake_center = vector(ll.x - self.track_wire * 2 + offset, c.y + add_distance) fake_center = vector(ll.x - self.track_wire * 2 + offset, c.y + add_distance)
is_too_close = any(abs(pin_added.center().y - fake_center.y) < (0.8 + self.half_wire * 4)for pin_added in self.io_pins_added_left) is_too_close = any(abs(pin_added.center().y - fake_center.y) < (0.4 + self.half_wire * 4)for pin_added in self.io_pins_added_left)
if edge == "bottom": if edge == "bottom":
fake_center = vector(c.x, ll.y - self.track_wire * 2 + offset) fake_center = vector(c.x, ll.y - self.track_wire * 2 + offset)
is_too_close = any(abs(pin_added.center().x - fake_center.x) < (0.8 + self.half_wire * 4)for pin_added in self.io_pins_added_down) is_too_close = any(abs(pin_added.center().x - fake_center.x) < (0.4 + self.half_wire * 4)for pin_added in self.io_pins_added_down)
while is_too_close: while is_too_close:
debug.warning("overlap, changing position") debug.warning("overlap, changing position")
add_distance = add_distance + 0.8 + self.half_wire * 4 add_distance = add_distance + 0.1#0.4 + self.half_wire * 4
fake_center = vector(c.x + add_distance, ll.y - self.track_wire * 2 + offset) fake_center = vector(c.x + add_distance, ll.y - self.track_wire * 2 + offset)
is_too_close = any(abs(pin_added.center().x - fake_center.x) < (0.8 + self.half_wire * 4)for pin_added in self.io_pins_added_down) is_too_close = any(abs(pin_added.center().x - fake_center.x) < (0.4 + self.half_wire * 4)for pin_added in self.io_pins_added_down)
if edge == "right": if edge == "right":
fake_center = vector(ur.x + self.track_wire * 2 - offset, c.y) fake_center = vector(ur.x + self.track_wire * 2 - offset, c.y)
is_too_close = any(abs(pin_added.center().y - fake_center.y) < (0.8 + self.half_wire * 4)for pin_added in self.io_pins_added_right) is_too_close = any(abs(pin_added.center().y - fake_center.y) < (0.4 + self.half_wire * 4)for pin_added in self.io_pins_added_right)
while is_too_close: while is_too_close:
debug.warning("overlap, changing position") debug.warning("overlap, changing position")
add_distance = add_distance + 0.8 + self.half_wire * 4 add_distance = add_distance + 0.1#0.4 + self.half_wire * 4
fake_center = vector(ur.x + self.track_wire * 2 - offset, c.y + add_distance) fake_center = vector(ur.x + self.track_wire * 2 - offset, c.y + add_distance)
# debug # debug
for pin_added in self.io_pins_added_right: for pin_added in self.io_pins_added_right:
dis = abs(pin_added.center().y - fake_center.y) dis = abs(pin_added.center().y - fake_center.y)
debug.warning("current position is {0}".format(fake_center)) debug.warning("current position is {0}".format(fake_center))
debug.warning("distance from {0} is {1}".format(pin_added, dis)) debug.warning("distance from {0} is {1}".format(pin_added, dis))
debug.warning("must disrance is {0}".format(0.8 + self.half_wire * 4)) debug.warning("must disrance is {0}".format(0.4 + self.half_wire * 4))
is_too_close = any(abs(pin_added.center().y - fake_center.y) < (0.8 + self.half_wire * 4)for pin_added in self.io_pins_added_right) is_too_close = any(abs(pin_added.center().y - fake_center.y) < (0.4 + self.half_wire * 4)for pin_added in self.io_pins_added_right)
if edge == "top": if edge == "top":
fake_center = vector(c.x, ur.y + self.track_wire * 2 - offset) fake_center = vector(c.x, ur.y + self.track_wire * 2 - offset)
is_too_close = any(abs(pin_added.center().x - fake_center.x) < (0.8 + self.half_wire * 4)for pin_added in self.io_pins_added_up) is_too_close = any(abs(pin_added.center().x - fake_center.x) < (0.4 + self.half_wire * 4)for pin_added in self.io_pins_added_up)
while is_too_close: while is_too_close:
debug.warning("overlap, changing position") debug.warning("overlap, changing position")
add_distance = add_distance + 0.8 + self.half_wire * 4 add_distance = add_distance + 0.1#0.4 + self.half_wire * 4
fake_center = vector(c.x + add_distance, ur.y + self.track_wire * 2 - offset) fake_center = vector(c.x + add_distance, ur.y + self.track_wire * 2 - offset)
is_too_close = any(abs(pin_added.center().x - fake_center.x) < (0.8 + self.half_wire * 4)for pin_added in self.io_pins_added_up) is_too_close = any(abs(pin_added.center().x - fake_center.x) < (0.4 + self.half_wire * 4)for pin_added in self.io_pins_added_up)
# Create the fake pin shape, here make sure the pin in the gds will be big enough # Create the fake pin shape, here make sure the pin in the gds will be big enough
layer = self.get_layer(int(not vertical)) layer = self.get_layer(int(not vertical))
@ -133,11 +306,11 @@ class io_pin_placer(router):
self.io_pins_added_up.append(pin) self.io_pins_added_up.append(pin)
debug.warning("pin added: {0}".format(pin)) debug.warning("pin added: {0}".format(pin))
return pin return pin, vertical, add_distance
def add_io_pins(self, pin_names): def add_io_pins(self, pin_names):
""" Add IO pins on the edges without routing them. """ """ Add IO pins on the edges WITHOUT routing them. """
debug.info(1, "Adding IO pins on the perimeter...") debug.info(1, "Adding IO pins on the perimeter...")
# Prepare GDS reader (if necessary for pin/blockage identification) # Prepare GDS reader (if necessary for pin/blockage identification)
@ -147,16 +320,188 @@ class io_pin_placer(router):
for name in pin_names: for name in pin_names:
self.find_pins(name)# this will add the pins to the self.pins self.find_pins(name)# this will add the pins to the self.pins
# Replace layout pins with those on the perimeter # inital position
pin_list = []
for name in self.pins: for name in self.pins:
pin = next(iter(self.pins[name])) pin = next(iter(self.pins[name]))
fake_pin = self.create_fake_pin(pin) pin_list.append(pin)
self.design.replace_layout_pin(name, fake_pin) # if do not have replace_layout_pin, final gds won't have io pins
self.initial_position(pin_list)
# Change IO pin names, which means "internal name" will be used, and internal io pins will not have label such as "dout0[0]"
self.replace_layout_pins(pin_names)
def add_io_pins_connected(self, pin_names):
""" Add IO pins on the edges WITH routing them. """
debug.info(1, "Adding IO pins on the perimeter...")
# Prepare GDS reader (if necessary for pin/blockage identification)
self.prepare_gds_reader()
# Find pins to be added (without routing)
for name in pin_names:
self.find_pins(name)# this will add the pins to the self.pins
debug.warning("the pins in pin_name -> {0}".format(name))
# inital position
pin_list = []
for name in self.pins:
pin = next(iter(self.pins[name]))
pin_list.append(pin)
debug.warning("the pins in self.pins -> {0}".format(name))
self.initial_position(pin_list)
# add fake io pins at the perimeter, which will be used for routing
for fake_pin in self.io_pins_fake:
self.design.add_layout_pin(text=fake_pin.name,
layer=fake_pin.layer,
offset=fake_pin.ll(),
width=fake_pin.width(),
height=fake_pin.height())
# connect the source_pin and io_pin(target)
self.connect_pins(pin_names)
# remove the fake pin before change the name, in order to avoid possible problem
for fake_pin in self.io_pins_fake:
self.remove_io_pins(fake_pin.name)
# Change IO pin names, which means "internal name" will be used, and internal io pins will not have label such as "dout0[0]"
self.replace_layout_pins(pin_names)
def connect_pins(self, pin_names): # pin_names should be a list
""" Add IO pins on the edges, and connect them to the internal one, not-graph like process """
debug.info(1, "connecting to io pins...")
pattern_dout = r'^dout'
for pin_name in pin_names:
# get pin pairs ready
source_pin = next(iter(self.pins[pin_name]))
for fake_pin in self.io_pins_fake:
if pin_name + "_" + "fake" == fake_pin.name:
target_pin = fake_pin
break
# special hanlde dout pins
if re.match(pattern_dout, pin_name):
number_str = re.findall(r'\[(\d+)\]', pin_name)
if number_str:
number = int(number_str[0])
if number % 2 == 0:
is_up = True
else:
is_up = False
point_list = self.decide_point(source_pin, target_pin, is_up)
self.add_wire(point_list)
# other pins
else:
debug.warning("source{0}".format(source_pin.center()))
debug.warning("target{0}".format(target_pin.center()))
point_list = self.decide_point(source_pin, target_pin)
debug.warning("point_list->{0}".format(point_list))
self.add_wire(point_list)
def add_wire(self, point_list):
if len(point_list) == 2:
# direct connect
self.add_line(point_list[0], point_list[1])
elif len(point_list) == 4:
# intermediate points
self.add_line(point_list[0], point_list[1])
self.add_via(point_list[1])
self.add_line(point_list[1], point_list[2])
self.add_via(point_list[2])
self.add_line(point_list[2], point_list[3])
def add_line(self, point_1, point_2):
if round(point_1.y, 3) == round(point_2.y, 3):
# horizontal m3
self.design.add_path(self.get_layer(False), [point_1, point_2])
else:
# vertical m4
self.design.add_path(self.get_layer(True), [point_1, point_2])
def add_via(self, point):
# currently only m3-m4 vias are supported in this method
# usd in order to make "z" shape routing only
self.design.add_via_stack_center(from_layer=self.get_layer(False),
to_layer=self.get_layer(True),
offset=point)
def add_start_via(self, point):
# currently only m3-m4 vias are supported in this method
# used in source_pin only
self.design.add_via_stack_center(from_layer=self.get_layer(False),
to_layer=self.get_layer(True),
offset=point)
def decide_point(self, source_pin, target_pin, is_up=False):
ll, ur = self.bbox
offset = 0.95 + 0.19 # FIX: this is the magic number to overcome the ovetflow problem at the boundary, may need a method
# internal -> left
if round(target_pin.center().x, 3) == round(ll.x - self.track_wire * 2 + offset, 3):
# direct connect possible
return [source_pin.rc(), target_pin.lc()] # FIX: not sure if shape overlap in met3 allowed, but seems OK
# internal -> right
if round(target_pin.center().x, 3) == round(ur.x + self.track_wire * 2 - offset, 3):
# direct connect possible
return [source_pin.lc(), target_pin.rc()]
# internal -> top, need to add start_via m3->m4
if round(target_pin.center().y, 3) == round(ur.y + self.track_wire * 2 - offset, 3):
self.add_start_via(source_pin.center())
if round(target_pin.center().x, 3) == round(source_pin.center().x, 3):
# direct connect possible
return [source_pin.bc(), target_pin.uc()]
else:
# need intermediate point
via_basic_y = self.design.bank.height + 3 # 3 is magic number, make sure out of bank area
is_up = not is_up# Be attention, for channel at the top, the is_up should be inverted! Otherwise will cause overlap!
if is_up:
via_basic_y = via_basic_y + 0.5
else:
via_basic_y = via_basic_y - 0.5
point_1 = vector(source_pin.center().x, via_basic_y)
point_2 = vector(target_pin.center().x, via_basic_y)
return [source_pin.bc(), point_1, point_2, target_pin.uc()]
# internal -> bottom, need to add start_via m3->m4
if round(target_pin.center().y, 3) == round(ll.y - self.track_wire * 2 + offset, 3):
self.add_start_via(source_pin.center())
if round(target_pin.center().x, 3) == round(source_pin.center().x, 3):
# direct connect possible
return [source_pin.uc(), target_pin.bc()]
else:
# need intermediate point
via_basic_y = ll.y + 21 # 21 is magic number, make sure out of dff area
if is_up:
via_basic_y = via_basic_y + 0.5
else:
via_basic_y = via_basic_y - 0.5
point_1 = vector(source_pin.center().x, via_basic_y)
point_2 = vector(target_pin.center().x, via_basic_y)
return [source_pin.uc(), point_1, point_2, target_pin.bc()]
def remove_io_pins(self, pin_name): def remove_io_pins(self, pin_name):
# remove io pin in gds, so we could reroute # remove io pin in gds, so we could reroute
self.design.remove_layout_pin(pin_name) self.design.remove_layout_pin(pin_name)
def replace_layout_pins(self, pin_names):
""" Change the IO pin names with new ones around the perimeter. """
for pin_name in pin_names:
perimeter_pin_name = pin_name + "_" + "fake"
for pin in self.io_pins_fake:
if pin.name == perimeter_pin_name:
perimeter_pin = pin
self.design.replace_layout_pin(pin_name, perimeter_pin)
break