First draft of naive channel route in hierarchy_layout. It doesn't implement horizontal conflicts or try to minimize the number of channels.

This commit is contained in:
Matt Guthaus 2018-07-25 11:13:30 -07:00
parent 48d3b25b74
commit f7a2766c29
2 changed files with 180 additions and 14 deletions

View File

@ -635,7 +635,182 @@ class layout(lef.lef):
self.add_via_center(layers=layer_stack, self.add_via_center(layers=layer_stack,
offset=bus_pos, offset=bus_pos,
rotate=90) rotate=90)
def add_horizontal_trunk_route(self, pins, trunk_offset,
layer_stack=("metal1", "via1", "metal2"),
pitch=None):
"""
Create a trunk route for all pins with the the trunk located at the given y offset.
"""
if not pitch:
pitch = self.m1_pitch
max_x = max([pin.center().x for pin in pins])
min_x = min([pin.center().x for pin in pins])
half_minwidth = 0.5*drc["minwidth_{}".format(layer_stack[0])]
# if we are less than a pitch, just create a non-preferred layer jog
if max_x-min_x < pitch:
# Add the horizontal trunk on the vertical layer!
self.add_path(layer_stack[2],[vector(min_x-half_minwidth,trunk_offset.y), vector(max_x+half_minwidth,trunk_offset.y)])
# Route each pin to the trunk
for pin in pins:
# No bend needed here
mid = vector(pin.center().x, trunk_offset.y)
self.add_path(layer_stack[2], [pin.center(), mid])
else:
# Add the horizontal trunk
self.add_path(layer_stack[0],[vector(min_x,trunk_offset.y), vector(max_x,trunk_offset.y)])
trunk_mid = vector(0.5*(max_x+min_x),trunk_offset.y)
# Route each pin to the trunk
for pin in pins:
# Bend to the center of the trunk so it adds a via automatically
mid = vector(pin.center().x, trunk_offset.y)
self.add_wire(layer_stack, [pin.center(), mid, trunk_mid])
def add_vertical_trunk_route(self, pins, trunk_offset,
layer_stack=("metal1", "via1", "metal2"),
pitch=None):
"""
Create a trunk route for all pins with the the trunk located at the given x offset.
"""
if not pitch:
pitch = self.m2_pitch
max_y = max([pin.center().y for pin in pins])
min_y = min([pin.center().y for pin in pins])
# Add the vertical trunk
half_minwidth = 0.5*drc["minwidth_{}".format(layer_stack[2])]
# if we are less than a pitch, just create a non-preferred layer jog
if max_y-min_y < pitch:
# Add the horizontal trunk on the vertical layer!
self.add_path(layer_stack[0],[vector(trunk_offset.x,min_y-half_minwidth), vector(trunk_offset.x,max_y+half_minwidth)])
# Route each pin to the trunk
for pin in pins:
# No bend needed here
mid = vector(trunk_offset.x, pin.center().y)
self.add_path(layer_stack[0], [pin.center(), mid])
else:
# Add the vertical trunk
self.add_path(layer_stack[2],[vector(trunk_offset.x,min_y), vector(trunk_offset.x,max_y)])
trunk_mid = vector(trunk_offset.x,0.5*(max_y+min_y),)
# Route each pin to the trunk
for pin in pins:
# Bend to the center of the trunk so it adds a via automatically
mid = vector(trunk_offset.x, pin.center().y)
self.add_wire(layer_stack, [pin.center(), mid, trunk_mid])
def create_channel_route(self, route_map, bottom_inst, top_inst, offset,
layer_stack=("metal1", "via1", "metal2"), pitch=None,
vertical=False):
"""
This is a simple channel route for one-to-one connections that
will jog the top route whenever there is a conflict. It does NOT
try to minimize the number of tracks -- instead, it picks an order to avoid the vertical
conflicts between pins.
"""
if not pitch and vertical:
pitch = self.m2_pitch
elif not pitch and not vertical:
pitch = self.m1_pitch
# FIXME: Must extend this to a horizontal conflict graph too if we want to minimize the
# number of tracks!
# Initialize the vertical conflict graph (vcg) and make a list of all pins
vcg = {}
all_pins = {}
for (top_name, bot_name) in route_map:
vcg[top_name] = []
vcg[bot_name] = []
top_pin = top_inst.get_pin(top_name)
bot_pin = bottom_inst.get_pin(bot_name)
all_pins[top_name]=top_pin
all_pins[bot_name]=bot_pin
# Find the vertical pin conflicts
for (top_name, bot_name) in route_map:
top_pin = all_pins[top_name]
bot_pin = all_pins[bot_name]
if abs(top_pin.center().x-bot_pin.center().x) < pitch:
# The edges only go from top to bottom
# since we will order tracks bottom up
vcg[top_name].append(bot_name)
# This is the starting offset of the first trunk
if vertical:
half_minwidth = 0.5*drc["minwidth_{}".format(layer_stack[2])]
offset = offset + vector(half_minwidth,0)
else:
half_minwidth = 0.5*drc["minwidth_{}".format(layer_stack[0])]
offset = offset + vector(0,half_minwidth)
# list of routes to do
while vcg:
# get a route from conflict graph with empty fanout set
route_pin=None
for route_pin,conflicts in vcg.items():
if len(conflicts)==0:
# Remove the pin from the keys
vcg.pop(route_pin,None)
# Remove the pin from all conflicts
# This is O(n^2), so maybe optimize it.
for pin,conflicts in vcg.items():
if pin in conflicts:
conflicts.remove(route_pin)
vcg[pin]=conflicts
break
#print("Routing:",route_pin)
# Get the connected pins from the routing map
for pin_connections in route_map:
if route_pin in pin_connections:
break
#print("Routing:",pin_connections)
# Remove the other pins from the conflict graph too
for pin in pin_connections:
vcg.pop(pin,None)
# Create a list of the pins rather than a list of the names
pin_list = [all_pins[pin_name] for pin_name in pin_connections]
# Add the trunk route and move up to next track
if vertical:
self.add_vertical_trunk_route(pin_list, offset, layer_stack, pitch)
offset += vector(pitch,0)
else:
self.add_horizontal_trunk_route(pin_list, offset, layer_stack, pitch)
offset += vector(0,pitch)
def create_vertical_channel_route(self, route_map, left_inst, right_inst, offset,
layer_stack=("metal1", "via1", "metal2"),
pitch=None):
"""
Wrapper to create a vertical channel route
"""
self.create_channel_route(route_map, left_inst, right_inst, offset,
layer_stack, pitch, vertical=True)
def create_horizontal_channel_route(self, route_map, top_inst, bottom_inst, offset,
layer_stack=("metal1", "via1", "metal2"),
pitch=None):
"""
Wrapper to create a horizontal channel route
"""
self.create_channel_route(route_map, top_inst, bottom_inst, offset,
layer_stack, pitch, vertical=False)
def add_enclosure(self, insts, layer="nwell"): def add_enclosure(self, insts, layer="nwell"):
""" Add a layer that surrounds the given instances. Useful """ Add a layer that surrounds the given instances. Useful
for creating wells, for example. Doesn't check for minimum widths or for creating wells, for example. Doesn't check for minimum widths or

View File

@ -38,7 +38,7 @@ class sram_1bank(sram_base):
control_pos.y + self.control_logic.height + self.m1_pitch) control_pos.y + self.control_logic.height + self.m1_pitch)
self.add_row_addr_dff(row_addr_pos) self.add_row_addr_dff(row_addr_pos)
data_gap = -self.m2_pitch*(self.word_size+1) data_gap = -self.m1_pitch*(self.word_size+1)
# Add the column address below the bank under the control # Add the column address below the bank under the control
# Keep it aligned with the data flops # Keep it aligned with the data flops
@ -174,23 +174,14 @@ class sram_1bank(sram_base):
def route_data_dff(self): def route_data_dff(self):
""" Connect the output of the data flops to the write driver """ """ Connect the output of the data flops to the write driver """
# Create a horizontal bus # This is where the channel will start (y-dimension at least)
bus_names = ["data[{}]".format(x) for x in range(self.word_size)] offset = self.data_dff_inst.ul() + vector(0, self.m1_pitch)
data_bus_offsets = self.create_horizontal_bus(layer="metal1",
pitch=self.m1_pitch,
offset=self.data_dff_inst.ul() + vector(0, self.m1_pitch),
names=bus_names,
length=self.data_dff_inst.width)
dff_names = ["dout[{}]".format(x) for x in range(self.word_size)] dff_names = ["dout[{}]".format(x) for x in range(self.word_size)]
data_dff_map = zip(dff_names, bus_names)
self.connect_horizontal_bus(data_dff_map, self.data_dff_inst, data_bus_offsets)
bank_names = ["bank_din[{}]".format(x) for x in range(self.word_size)] bank_names = ["bank_din[{}]".format(x) for x in range(self.word_size)]
data_bank_map = zip(bank_names, bus_names)
self.connect_horizontal_bus(data_bank_map, self.bank_inst, data_bus_offsets)
route_map = list(zip(bank_names, dff_names))
self.create_horizontal_channel_route(route_map, self.data_dff_inst, self.bank_inst, offset)