mirror of https://github.com/VLSIDA/OpenRAM.git
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:
parent
48d3b25b74
commit
f7a2766c29
|
|
@ -636,6 +636,181 @@ class layout(lef.lef):
|
|||
offset=bus_pos,
|
||||
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"):
|
||||
""" Add a layer that surrounds the given instances. Useful
|
||||
for creating wells, for example. Doesn't check for minimum widths or
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class sram_1bank(sram_base):
|
|||
control_pos.y + self.control_logic.height + self.m1_pitch)
|
||||
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
|
||||
# Keep it aligned with the data flops
|
||||
|
|
@ -174,23 +174,14 @@ class sram_1bank(sram_base):
|
|||
|
||||
def route_data_dff(self):
|
||||
""" Connect the output of the data flops to the write driver """
|
||||
# Create a horizontal bus
|
||||
bus_names = ["data[{}]".format(x) for x in range(self.word_size)]
|
||||
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)
|
||||
|
||||
# This is where the channel will start (y-dimension at least)
|
||||
offset = self.data_dff_inst.ul() + vector(0, self.m1_pitch)
|
||||
|
||||
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)]
|
||||
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)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue