Reimplement off grid pins.

Long pins aren't accessed on end pins anymore.
Fix problem with multiple non-enclosed space causing blockages.
Add partial pin offgrid enclosure algorithm.
This commit is contained in:
mrg 2022-05-02 15:43:14 -07:00
parent 7195d81736
commit b1bb9151c4
17 changed files with 274 additions and 155 deletions

View File

@ -419,13 +419,6 @@ class layout():
pin.width(),
pin.height())
def copy_layout_pins(self, instance, prefix=""):
"""
Create a copied version of the layout pin at the current level.
You can optionally rename the pin to a new name.
"""
for pin_name in self.pin_map.keys():
self.copy_layout_pin(instance, pin_name, prefix + pin_name)
def connect_row_locs(self, from_layer, to_layer, locs, name=None, full=False):
"""
@ -608,12 +601,11 @@ class layout():
def route_vertical_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", num_pins=2, full_width=True):
def route_vertical_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", full_width=True):
"""
Route together all of the pins of a given name that vertically align.
Uses local_insts if insts not 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
"""
@ -660,8 +652,10 @@ class layout():
if last_via:
via_width=last_via.mod.second_layer_width
via_height=last_via.mod.second_layer_height
else:
via_width=None
via_height=0
if full_width:
bot_y = 0
@ -669,21 +663,19 @@ class layout():
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)
bot_pos = vector(x, bot_y)
top_pos = vector(x, top_y + 0.5 * via_height)
bot_pos = vector(x, bot_y - 0.5 * via_height)
if num_pins==2:
self.add_layout_pin_rect_ends(name=name,
layer=pin_layer,
start=top_pos,
end=bot_pos,
width=via_width)
else:
self.add_layout_pin_segment_center(text=name,
layer=pin_layer,
start=top_pos,
end=bot_pos,
width=via_width)
# self.add_layout_pin_rect_ends(name=name,
# layer=pin_layer,
# start=top_pos,
# end=bot_pos,
# width=via_width)
self.add_layout_pin_segment_center(text=name,
layer=pin_layer,
start=top_pos,
end=bot_pos,
width=via_width)
def add_layout_pin_rect_ends(self, name, layer, start, end, width=None):
@ -707,12 +699,13 @@ class layout():
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):
return (bot_rect, top_rect)
def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy", full_width=True):
"""
Route together all of the pins of a given name that horizontally align.
Uses local_insts if insts not 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
"""
@ -760,8 +753,10 @@ class layout():
if last_via:
via_height=last_via.mod.second_layer_height
via_width=last_via.mod.second_layer_width
else:
via_height=None
via_width=0
if full_width:
left_x = 0
@ -769,22 +764,19 @@ class layout():
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)
right_pos = vector(right_x, y)
left_pos = vector(left_x + 0.5 * via_width, y)
right_pos = vector(right_x + 0.5 * via_width, y)
if num_pins==2:
self.add_layout_pin_rect_ends(name=name,
layer=pin_layer,
start=left_pos,
end=right_pos,
width=via_height)
else:
# This adds a single big pin
self.add_layout_pin_segment_center(text=name,
layer=pin_layer,
start=left_pos,
end=right_pos,
width=via_height)
# self.add_layout_pin_rect_ends(name=name,
# layer=pin_layer,
# start=left_pos,
# end=right_pos,
# width=via_height)
self.add_layout_pin_segment_center(text=name,
layer=pin_layer,
start=left_pos,
end=right_pos,
width=via_height)
def add_layout_end_pin_segment_center(self, text, layer, start, end):
"""
@ -1123,7 +1115,6 @@ class layout():
Add a minimum area retcangle at the given point.
Either width or height should be fixed.
"""
min_area = drc("minarea_{}".format(layer))
if min_area == 0:
return

View File

@ -174,6 +174,10 @@ class pin_layout:
def intersection(self, other):
""" Check if a shape overlaps with a rectangle """
if not self.overlaps(other):
return None
(ll, ur) = self.rect
(oll, our) = other.rect
@ -182,6 +186,9 @@ class pin_layout:
min_y = max(ll.y, oll.y)
max_y = min(ur.y, our.y)
if max_x - min_x == 0 or max_y - min_y == 0:
return None
return [vector(min_x, min_y), vector(max_x, max_y)]
def xoverlaps(self, other):

View File

@ -229,7 +229,7 @@ class bank(design.design):
# UPPER LEFT QUADRANT
# To the left of the bitcell array above the predecoders and control logic
x_offset = self.m2_gap + self.port_address[port].width
x_offset = self.decoder_gap + self.port_address[port].width
self.port_address_offsets[port] = vector(-x_offset,
self.main_bitcell_array_bottom)
@ -272,7 +272,7 @@ class bank(design.design):
# LOWER RIGHT QUADRANT
# To the right of the bitcell array
x_offset = self.bitcell_array_right + self.port_address[port].width + self.m2_gap
x_offset = self.bitcell_array_right + self.port_address[port].width + self.decoder_gap
self.port_address_offsets[port] = vector(x_offset,
self.main_bitcell_array_bottom)
@ -364,9 +364,9 @@ class bank(design.design):
self.num_col_addr_lines = 0
self.col_addr_bus_width = self.m2_pitch * self.num_col_addr_lines
# A space for wells or jogging m2
self.m2_gap = max(2 * drc("pwell_to_nwell") + drc("nwell_enclose_active"),
3 * self.m2_pitch,
# Gap between decoder and array
self.decoder_gap = max(2 * drc("pwell_to_nwell") + drc("nwell_enclose_active"),
2 * self.m2_pitch,
drc("nwell_to_nwell"))
def add_modules(self):
@ -400,11 +400,10 @@ class bank(design.design):
self.port_data = []
self.bit_offsets = self.get_column_offsets()
for port in self.all_ports:
temp_pre = factory.create(module_type="port_data",
sram_config=self.sram_config,
port=port,
bit_offsets=self.bit_offsets)
self.port_data.append(temp_pre)
self.port_data.append(factory.create(module_type="port_data",
sram_config=self.sram_config,
port=port,
bit_offsets=self.bit_offsets))
if(self.num_banks > 1):
self.bank_select = factory.create(module_type="bank_select")
@ -606,15 +605,22 @@ class bank(design.design):
def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
# Copy only the power pins already on the power layer
# (this won't add vias to internal bitcell pins, for example)
for inst in self.insts:
self.copy_power_pins(inst, "vdd", add_vias=False)
self.copy_power_pins(inst, "gnd", add_vias=False)
# This avoids getting copy errors on vias and other instances
all_insts = [self.bitcell_array_inst] + self.port_address_inst + self.port_data_inst
if hasattr(self, "column_decoder_inst"):
all_insts += self.column_decoder_inst
for inst in all_insts:
self.copy_layout_pin(inst, "vdd")
self.copy_layout_pin(inst, "gnd")
if 'vpb' in self.bitcell_array_inst.mod.pins and 'vnb' in self.bitcell_array_inst.mod.pins:
for pin_name, supply_name in zip(['vnb','vpb'],['gnd','vdd']):
self.copy_power_pins(self.bitcell_array_inst, pin_name, new_name=supply_name)
self.copy_layout_pin(self.bitcell_array_inst, pin_name, new_name=supply_name)
# If we use the pinvbuf as the decoder, we need to add power pins.
# Other decoders already have them.

View File

@ -715,12 +715,17 @@ class control_logic(design.design):
pin_layer = self.dff.get_pin("vdd").layer
supply_layer = self.supply_stack[2]
# FIXME: We should be able to replace this with route_vertical_pins instead
# but we may have to make the logic gates a separate module so that they
# have row pins of the same width
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 = []
last_via = None
for inst in self.row_end_inst:
pins = inst.get_pins("vdd")
for pin in pins:
@ -728,10 +733,10 @@ class control_logic(design.design):
row_loc = pin.rc()
pin_loc = vector(max_row_x_loc, pin.rc().y)
vdd_pin_locs.append(pin_loc)
self.add_via_stack_center(from_layer=pin_layer,
to_layer=supply_layer,
offset=pin_loc,
min_area=True)
last_via = 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")
@ -740,29 +745,38 @@ class control_logic(design.design):
row_loc = pin.rc()
pin_loc = vector(min_row_x_loc, pin.rc().y)
gnd_pin_locs.append(pin_loc)
self.add_via_stack_center(from_layer=pin_layer,
to_layer=supply_layer,
offset=pin_loc,
min_area=True)
last_via = 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])
if last_via:
via_height=last_via.mod.second_layer_height
via_width=last_via.mod.second_layer_width
else:
via_height=None
via_width=0
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)
bot_pos = vector(max_row_x_loc, min_y - 0.5 * via_height)
top_pos = vector(max_row_x_loc, max_y + 0.5 * via_height)
self.add_layout_pin_segment_center(text="vdd",
layer=supply_layer,
start=bot_pos,
end=top_pos)
end=top_pos,
width=via_width)
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)
bot_pos = vector(min_row_x_loc, min_y - 0.5 * via_height)
top_pos = vector(min_row_x_loc, max_y + 0.5 * via_height)
self.add_layout_pin_segment_center(text="gnd",
layer=supply_layer,
start=bot_pos,
end=top_pos)
end=top_pos,
width=via_width)
self.copy_layout_pin(self.delay_inst, "gnd")
self.copy_layout_pin(self.delay_inst, "vdd")

View File

@ -172,25 +172,9 @@ class delay_chain(design.design):
self.add_path("m2", [z_pin.center(), mid1_point, mid2_point, next_a_pin.center()])
def route_supplies(self):
# Add power and ground to all the cells except:
# the fanout driver, the right-most load
# 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
# supply rail
if True or OPTS.experimental_power:
left_load_insts = [self.load_inst_map[x][0] for x in self.driver_inst_list]
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:
for inst in self.driver_inst_list:
load_list = self.load_inst_map[inst]
for pin_name in ["vdd", "gnd"]:
pin = load_list[0].get_pin(pin_name)
self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0))
pin = load_list[-2].get_pin(pin_name)
self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0))
self.route_vertical_pins("vdd", self.driver_inst_list, xside="lx")
right_load_insts = [self.load_inst_map[x][-1] for x in self.driver_inst_list]
self.route_vertical_pins("gnd", right_load_insts, xside="rx")
def add_layout_pins(self):

View File

@ -595,14 +595,12 @@ class hierarchical_decoder(design.design):
# Leave these to route in the port_address
all_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
for inst in all_insts:
self.copy_layout_pin(inst, "vdd")
self.copy_layout_pin(inst, "gnd")
self.copy_layout_pin(inst, "vdd")
self.copy_layout_pin(inst, "gnd")
self.route_vertical_pins("vdd", self.and_inst, xside="rx",)
self.route_vertical_pins("gnd", self.and_inst, xside="lx",)
for inst in self.and_inst:
for pin in inst.get_pins("vdd"):
self.add_power_pin("vdd", pin.rc())
for pin in inst.get_pins("gnd"):
self.add_power_pin("gnd", pin.lc())
def route_predecode_bus_outputs(self, rail_name, pin, row):

View File

@ -395,7 +395,7 @@ class hierarchical_predecode(design.design):
height=top_pin.uy() - self.bus_pitch)
# This adds power vias at the top of each cell
# (except the last to keep them inside the boundary)
for i in self.inv_inst[:-1:2] + self.and_inst[:-1:2]:
for i in [self.inv_inst[0], self.inv_inst[-2], self.and_inst[0], self.and_inst[-2]]:
pins = i.get_pins(n)
for pin in pins:
self.copy_power_pin(pin, loc=pin.uc())

View File

@ -162,14 +162,15 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
# FIXME: Replace this with a tech specific paramter
driver_to_array_spacing = 3 * self.m3_pitch
self.wl_insts[0].place(vector(0, self.cell.height))
self.wl_insts[0].place(vector(0,
self.bitcell_array.get_replica_bottom() + self.cell.height))
self.bitcell_array_inst.place(vector(self.wl_insts[0].rx() + driver_to_array_spacing,
0))
if len(self.all_ports) > 1:
self.wl_insts[1].place(vector(self.bitcell_array_inst.rx() + self.wl_array.width + driver_to_array_spacing,
2 * self.cell.height + self.wl_array.height),
self.bitcell_array.get_replica_top() + self.cell.height),
mirror="XY")
self.height = self.bitcell_array.height

View File

@ -76,22 +76,19 @@ class port_address(design.design):
def route_supplies(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
self.route_vertical_pins("vdd", [self.row_decoder_inst])
self.route_vertical_pins("gnd", [self.row_decoder_inst])
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()])
vdd_pins = self.row_decoder_inst.get_pins("vdd") + self.wordline_driver_array_inst.get_pins("vdd")
self.connect_row_pins(self.route_layer, vdd_pins)
gnd_pins = self.row_decoder_inst.get_pins("gnd") + self.wordline_driver_array_inst.get_pins("gnd")
self.connect_row_pins(self.route_layer, gnd_pins)
self.copy_layout_pin(self.wordline_driver_array_inst, "vdd")
self.copy_layout_pin(self.wordline_driver_array_inst, "gnd")
self.copy_layout_pin(self.row_decoder_inst, "vdd")
self.copy_layout_pin(self.row_decoder_inst, "gnd")
# Also connect the B input of the RBL and_dec to vdd
if OPTS.local_array_size == 0:
rbl_b_pin = self.rbl_driver_inst.get_pin("B")

View File

@ -83,7 +83,7 @@ class precharge_array(design.design):
def add_layout_pins(self):
en_pin = self.pc_cell.get_pin("en_bar")
self.route_horizontal_pins("en_bar", layer=self.en_bar_layer, num_pins=1)
self.route_horizontal_pins("en_bar", layer=self.en_bar_layer)
for inst in self.local_insts:
self.add_via_stack_center(from_layer=en_pin.layer,
to_layer=self.en_bar_layer,

View File

@ -331,6 +331,7 @@ class replica_bitcell_array(bitcell_base_array):
self.translate_all(array_offset.scale(-1, -1))
# Add extra width on the left and right for the unused WLs
self.width = self.dummy_col_insts[1].rx() + self.unused_offset.x
self.height = self.dummy_row_insts[1].uy()
@ -340,6 +341,12 @@ class replica_bitcell_array(bitcell_base_array):
self.route_unused_wordlines()
lower_left = self.find_lowest_coords()
upper_right = self.find_highest_coords()
self.width = upper_right.x - lower_left.x
self.height = upper_right.y - lower_left.y
self.translate_all(lower_left)
self.add_boundary()
self.DRC_LVS()
@ -356,6 +363,18 @@ class replica_bitcell_array(bitcell_base_array):
def get_main_array_right(self):
return self.bitcell_array_inst.rx()
def get_replica_top(self):
return max([x.uy() for x in self.replica_col_insts if x] + [self.get_main_array_top()])
def get_replica_bottom(self):
return min([x.by() for x in self.replica_col_insts if x] + [self.get_main_array_bottom()])
def get_replica_left(self):
return min([x.lx() for x in self.replica_col_insts if x] + [self.get_main_array_left()])
def get_replica_right(self):
return min([x.rx() for x in self.replica_col_insts if x] + [self.get_main_array_right()])
def get_column_offsets(self):
"""
Return an array of the x offsets of all the regular bits
@ -567,14 +586,15 @@ class replica_bitcell_array(bitcell_base_array):
top_loc = vector(self.width + offset_multiple * self.vertical_pitch, self.height)
layer = self.supply_stack[2]
self.add_path(layer, [bot_loc, top_loc])
self.add_layout_pin_rect_center(text=name,
layer=layer,
offset=top_loc)
self.add_layout_pin_rect_center(text=name,
layer=layer,
offset=bot_loc)
# self.add_layout_pin_rect_ends(text=name,
# layer=layer,
# start=bot_loc,
# end=top_loc)
self.add_layout_pin_segment_center(text=name,
layer=layer,
start=bot_loc,
end=top_loc)
return (bot_loc, top_loc)
@ -590,14 +610,15 @@ class replica_bitcell_array(bitcell_base_array):
right_loc = vector(self.width, self.height + offset_multiple * self.horizontal_pitch)
layer = self.supply_stack[0]
self.add_path(layer, [left_loc, right_loc])
self.add_layout_pin_rect_center(text=name,
layer=layer,
offset=left_loc)
self.add_layout_pin_rect_center(text=name,
layer=layer,
offset=right_loc)
# self.add_layout_pin_rect_ends(text=name,
# layer=layer,
# start=left_loc,
# end=right_loc)
self.add_layout_pin_segment_center(text=name,
layer=layer,
start=left_loc,
end=right_loc)
return (left_loc, right_loc)

View File

@ -77,11 +77,12 @@ class wordline_driver_array(design.design):
Add vertical power rails.
"""
for inst in self.wld_inst:
for pin in inst.get_pins("vdd"):
self.add_power_pin("vdd", pin.rc())
#self.copy_layout_pin(inst, "vdd")
self.copy_layout_pin(inst, "gnd")
if layer_props.wordline_driver.vertical_supply:
self.route_vertical_pins("vdd", self.wld_inst)
self.route_vertical_pins("gnd", self.wld_inst)
else:
self.route_vertical_pins("vdd", self.wld_inst, xside="rx",)
self.route_vertical_pins("gnd", self.wld_inst, xside="lx",)
def create_drivers(self):

View File

@ -158,7 +158,7 @@ class pin_group:
# Now add the right name
for pin in new_pin_list:
pin.name = self.name
debug.check(len(new_pin_list) > 0,
"Did not find any enclosures.")
@ -424,7 +424,7 @@ class pin_group:
debug.check(len(self.grids) > 0, "Cannot seed an grid empty set.")
common_blockages = self.router.get_blocked_grids() & self.grids
# Start with the ll and make the widest row
row = [ll]
# Move in dir1 while we can
@ -641,7 +641,7 @@ class pin_group:
# way than blockages.
blockages = sufficient | insufficient | blockage_in_tracks
self.blockages.update(blockages)
# If we have a blockage, we must remove the grids
# Remember, this excludes the pin blockages already
blocked_grids = self.router.get_blocked_grids()

View File

@ -229,9 +229,9 @@ class router(router_tech):
# Enclose the continguous grid units in a metal
# rectangle to fix some DRCs
start_time = datetime.now()
self.enclose_pins()
print_time("Enclosing pins", datetime.now(), start_time, 4)
#start_time = datetime.now()
#self.enclose_pins()
#print_time("Enclosing pins", datetime.now(), start_time, 4)
# MRG: Removing this code for now. The later compute enclosure code
# assumes that all pins are touching and this may produce sets of pins
@ -670,6 +670,25 @@ class router(router_tech):
return set([best_coord])
def divide_pin_to_tracks(self, pin, tracks):
"""
Return a list of pin shape parts that are in the tracks.
"""
overlap_pins = []
for track in tracks:
track_pin = self.convert_track_to_shape_pin(track)
overlap_rect = track_pin.intersection(pin)
if not overlap_rect:
continue
else:
overlap_pin = pin_layout(pin.name,
overlap_rect,
pin.layer)
overlap_pins.append(overlap_pin)
return overlap_pins
def convert_pin_coord_to_tracks(self, pin, coord):
"""
Return all tracks that an inflated pin overlaps
@ -893,6 +912,8 @@ class router(router_tech):
This will mark the grids for all pin components as a source.
Marking as source or target also clears blockage status.
"""
self.source_name = pin_name
self.source_components = []
for i in range(self.num_pin_components(pin_name)):
self.add_pin_component_source(pin_name, i)
@ -904,6 +925,8 @@ class router(router_tech):
This will mark the grids for all pin components as a target.
Marking as source or target also clears blockage status.
"""
self.target_name = pin_name
self.target_components = []
for i in range(self.num_pin_components(pin_name)):
self.add_pin_component_target(pin_name, i)
@ -1009,6 +1032,8 @@ class router(router_tech):
"""
This will mark all the cells on the perimeter of the original layout as a target.
"""
self.target_name = ""
self.target_components = []
self.rg.add_perimeter_target(side=side)
def num_pin_components(self, pin_name):
@ -1017,6 +1042,15 @@ class router(router_tech):
"""
return len(self.pin_groups[pin_name])
def set_pin_component_source(self, pin_name, index):
"""
Add the pin component but also set it as the exclusive one.
Used by supply routing with multiple components.
"""
self.source_name = pin_name
self.source_components = []
self.add_pin_component_source(pin_name, index)
def add_pin_component_source(self, pin_name, index):
"""
This will mark only the pin tracks
@ -1026,6 +1060,7 @@ class router(router_tech):
debug.check(index<self.num_pin_components(pin_name),
"Pin component index too large.")
self.source_components.append(index)
pin_in_tracks = self.pin_groups[pin_name][index].grids
debug.info(3,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
self.rg.add_source(pin_in_tracks)
@ -1038,6 +1073,15 @@ class router(router_tech):
self.rg.set_target(p)
self.rg.set_blocked(p, False)
def set_pin_component_target(self, pin_name, index):
"""
Add the pin component but also set it as the exclusive one.
Used by supply routing with multiple components.
"""
self.target_name = pin_name
self.target_components = []
self.add_pin_component_target(pin_name, index)
def add_pin_component_target(self, pin_name, index):
"""
This will mark only the pin tracks
@ -1046,6 +1090,7 @@ class router(router_tech):
"""
debug.check(index<self.num_pin_components(pin_name),"Pin component index too large.")
self.target_components.append(index)
pin_in_tracks = self.pin_groups[pin_name][index].grids
debug.info(3, "Set target: " + str(pin_name) + " " + str(pin_in_tracks))
self.rg.add_target(pin_in_tracks)
@ -1093,25 +1138,71 @@ class router(router_tech):
"""
Add the current wire route to the given design instance.
"""
path = self.prepare_path(path)
prepared_path = self.prepare_path(path)
debug.info(4, "Adding route: {}".format(str(path)))
# If it is only a square, add an enclosure to the track
if len(path) == 1:
self.add_single_enclosure(path[0][0])
debug.info(4, "Adding route: {}".format(str(prepared_path)))
# convert the path back to absolute units from tracks
# This assumes 1-track wide again
abs_path = [self.convert_point_to_units(x[0]) for x in prepared_path]
if len(self.layers) > 1:
self.cell.add_route(layers=self.layers,
coordinates=abs_path,
layer_widths=self.layer_widths)
else:
# convert the path back to absolute units from tracks
# This assumes 1-track wide again
abs_path = [self.convert_point_to_units(x[0]) for x in path]
# Otherwise, add the route which includes enclosures
if len(self.layers) > 1:
self.cell.add_route(layers=self.layers,
coordinates=abs_path,
layer_widths=self.layer_widths)
else:
self.cell.add_path(layer=self.layers[0],
coordinates=abs_path,
width=self.layer_widths[0])
self.cell.add_path(layer=self.layers[0],
coordinates=abs_path,
width=self.layer_widths[0])
def create_route_connector(self, path_tracks, pin_name, components):
"""
Find a rectangle to connect the track and the off-grid pin of a component.
"""
if len(path_tracks) == 0 or len(components) == 0:
return
# Convert the off-grid pin into parts in each routing grid
offgrid_pin_parts = []
for component in components:
pg = self.pin_groups[pin_name][component]
for pin in pg.pins:
partial_pin_parts = self.divide_pin_to_tracks(pin, pg.grids)
offgrid_pin_parts.extend(partial_pin_parts)
# Find the track pin
track_pins = [self.convert_tracks_to_pin(x) for x in path_tracks]
# Find closest part
closest_track_pin, closest_part_pin = self.find_closest_pin(track_pins, offgrid_pin_parts)
# Find the bbox of the on-grid track and the off-grid pin part
closest_track_pin.bbox([closest_part_pin])
# Connect to off grid pin to track pin with closest shape
self.cell.add_rect(layer=closest_track_pin.layer,
offset=closest_track_pin.ll(),
width=closest_track_pin.width(),
height=closest_track_pin.height())
def find_closest_pin(self, first_list, second_list):
"""
Find the closest pin in the lists. Does a stupid O(n^2).
"""
min_dist = None
min_item = None
for pin1 in first_list:
for pin2 in second_list:
if pin1.layer != pin2.layer:
continue
new_dist = pin1.distance(pin2)
if not min_item or new_dist < min_dist:
min_item = (pin1, pin2)
min_dist = new_dist
return min_item
def add_single_enclosure(self, track):
"""
@ -1192,7 +1283,15 @@ class router(router_tech):
self.paths.append(grid_utils.flatten_set(path))
self.add_route(path)
self.create_route_connector(path,
self.source_name,
self.source_components)
self.create_route_connector(path,
self.target_name,
self.target_components)
self.path_blockages.append(self.paths[-1])
#self.write_debug_gds("debug_route.gds", False)
#breakpoint()
return True
else:
return False

View File

@ -154,7 +154,7 @@ class supply_tree_router(router):
print("DST {}: ".format(dest) + str(self.pin_groups[pin_name][dest].grids) + str(self.pin_groups[pin_name][dest].blockages))
self.write_debug_gds("post_{0}_{1}.gds".format(src, dest), False)
#self.write_debug_gds("final_tree_router_{}.gds".format(pin_name), False)
self.write_debug_gds("final_tree_router_{}.gds".format(pin_name), False)
#return
def route_signal(self, pin_name, src_idx, dest_idx):
@ -180,11 +180,11 @@ class supply_tree_router(router):
# Add the single component of the pin as the source
# which unmarks it as a blockage too
self.add_pin_component_source(pin_name, src_idx)
self.set_pin_component_source(pin_name, src_idx)
# Marks all pin components except index as target
# which unmarks it as a blockage too
self.add_pin_component_target(pin_name, dest_idx)
self.set_pin_component_target(pin_name, dest_idx)
# Actually run the A* router
if self.run_router(detour_scale=detour_scale):

View File

@ -213,7 +213,7 @@ class sram_base(design, verilog, lef):
self.add_lvs_correspondence_points()
self.offset_all_coordinates()
#self.offset_all_coordinates()
highest_coord = self.find_highest_coords()
self.width = highest_coord[0]

View File

@ -14,6 +14,6 @@ tech_name = OPTS.tech_name
nominal_corner_only = True
check_lvsdrc = True
route_supplies = False
#route_supplies = False
output_name = "sram"