mirror of https://github.com/VLSIDA/OpenRAM.git
first commt
This commit is contained in:
parent
f56460bb94
commit
86588619fd
|
|
@ -1913,6 +1913,42 @@ class layout():
|
||||||
# Just use the power pin function for now to save code
|
# 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)
|
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
|
||||||
|
# Hack for min area
|
||||||
|
if OPTS.tech_name == "sky130":
|
||||||
|
min_area = drc["minarea_{}".format(self.pwr_grid_layers[1])]
|
||||||
|
width = round_to_grid(sqrt(min_area))
|
||||||
|
height = round_to_grid(min_area / width)
|
||||||
|
else:
|
||||||
|
width = None
|
||||||
|
height = None
|
||||||
|
|
||||||
|
pin = None
|
||||||
|
if start_layer in self.pwr_grid_layers:
|
||||||
|
pin = self.add_layout_pin_rect_center(text=name,
|
||||||
|
layer=start_layer,
|
||||||
|
offset=loc,
|
||||||
|
width=width,
|
||||||
|
height=height)
|
||||||
|
else:
|
||||||
|
via = self.add_via_stack_center(from_layer=start_layer,
|
||||||
|
to_layer=start_layer,# so only enclosure shape will be added
|
||||||
|
offset=loc,
|
||||||
|
directions=directions)
|
||||||
|
|
||||||
|
if not width:
|
||||||
|
width = via.width
|
||||||
|
if not height:
|
||||||
|
height = via.height
|
||||||
|
pin = self.add_layout_pin_rect_center(text=name,
|
||||||
|
layer=start_layer,
|
||||||
|
offset=loc,
|
||||||
|
width=width,
|
||||||
|
height=height)
|
||||||
|
|
||||||
|
return pin
|
||||||
|
|
||||||
def add_power_pin(self, name, loc, directions=None, start_layer="m1"):
|
def add_power_pin(self, name, loc, directions=None, start_layer="m1"):
|
||||||
# Hack for min area
|
# Hack for min area
|
||||||
if OPTS.tech_name == "sky130":
|
if OPTS.tech_name == "sky130":
|
||||||
|
|
@ -2027,7 +2063,7 @@ class layout():
|
||||||
layer=layer,
|
layer=layer,
|
||||||
offset=peri_pin_loc)
|
offset=peri_pin_loc)
|
||||||
|
|
||||||
def add_dnwell(self, bbox=None, inflate=1):
|
def add_dnwell(self, bbox=None, inflate=1, add_vias=True):
|
||||||
""" Create a dnwell, along with nwell moat at border. """
|
""" Create a dnwell, along with nwell moat at border. """
|
||||||
|
|
||||||
if "dnwell" not in tech_layer:
|
if "dnwell" not in tech_layer:
|
||||||
|
|
@ -2049,11 +2085,20 @@ class layout():
|
||||||
ul = vector(ll.x, ur.y)
|
ul = vector(ll.x, ur.y)
|
||||||
lr = vector(ur.x, ll.y)
|
lr = vector(ur.x, ll.y)
|
||||||
|
|
||||||
# Add the dnwell
|
# Hack for sky130 klayout drc rule nwell.6
|
||||||
self.add_rect("dnwell",
|
if OPTS.tech_name == "sky130":
|
||||||
offset=ll,
|
# Apply the drc rule
|
||||||
height=ur.y - ll.y,
|
# Add the dnwell
|
||||||
width=ur.x - ll.x)
|
self.add_rect("dnwell",
|
||||||
|
offset=ll - vector(0.5 * self.nwell_width, 0.5 * self.nwell_width) - vector(drc["minclosure_nwell_by_dnwell"], drc["minclosure_nwell_by_dnwell"]),
|
||||||
|
height=ur.y - ll.y + self.nwell_width + 2 * drc["minclosure_nwell_by_dnwell"],
|
||||||
|
width=ur.x - ll.x + self.nwell_width + 2 * drc["minclosure_nwell_by_dnwell"])
|
||||||
|
else: # other tech
|
||||||
|
# Add the dnwell
|
||||||
|
self.add_rect("dnwell",
|
||||||
|
offset=ll,
|
||||||
|
height=ur.y - ll.y,
|
||||||
|
width=ur.x - ll.x)
|
||||||
|
|
||||||
# Add the moat
|
# Add the moat
|
||||||
self.add_path("nwell", [ll, lr, ur, ul, ll - vector(0, 0.5 * self.nwell_width)])
|
self.add_path("nwell", [ll, lr, ur, ul, ll - vector(0, 0.5 * self.nwell_width)])
|
||||||
|
|
@ -2080,9 +2125,14 @@ class layout():
|
||||||
to_layer="m1",
|
to_layer="m1",
|
||||||
offset=loc)
|
offset=loc)
|
||||||
else:
|
else:
|
||||||
self.add_power_pin(name="vdd",
|
if add_vias:
|
||||||
loc=loc,
|
self.add_power_pin(name="vdd",
|
||||||
start_layer="li")
|
loc=loc,
|
||||||
|
start_layer="li")
|
||||||
|
else:
|
||||||
|
self.add_power_pin_no_via(name="vdd",
|
||||||
|
loc=loc,
|
||||||
|
start_layer="li")
|
||||||
count += 1
|
count += 1
|
||||||
loc += nwell_offset.scale(tap_spacing, 0)
|
loc += nwell_offset.scale(tap_spacing, 0)
|
||||||
|
|
||||||
|
|
@ -2100,9 +2150,14 @@ class layout():
|
||||||
to_layer="m1",
|
to_layer="m1",
|
||||||
offset=loc)
|
offset=loc)
|
||||||
else:
|
else:
|
||||||
self.add_power_pin(name="vdd",
|
if add_vias:
|
||||||
loc=loc,
|
self.add_power_pin(name="vdd",
|
||||||
start_layer="li")
|
loc=loc,
|
||||||
|
start_layer="li")
|
||||||
|
else:
|
||||||
|
self.add_power_pin_no_via(name="vdd",
|
||||||
|
loc=loc,
|
||||||
|
start_layer="li")
|
||||||
count += 1
|
count += 1
|
||||||
loc += nwell_offset.scale(tap_spacing, 0)
|
loc += nwell_offset.scale(tap_spacing, 0)
|
||||||
|
|
||||||
|
|
@ -2120,9 +2175,14 @@ class layout():
|
||||||
to_layer="m2",
|
to_layer="m2",
|
||||||
offset=loc)
|
offset=loc)
|
||||||
else:
|
else:
|
||||||
self.add_power_pin(name="vdd",
|
if add_vias:
|
||||||
loc=loc,
|
self.add_power_pin(name="vdd",
|
||||||
start_layer="li")
|
loc=loc,
|
||||||
|
start_layer="li")
|
||||||
|
else:
|
||||||
|
self.add_power_pin_no_via(name="vdd",
|
||||||
|
loc=loc,
|
||||||
|
start_layer="li")
|
||||||
count += 1
|
count += 1
|
||||||
loc += nwell_offset.scale(0, tap_spacing)
|
loc += nwell_offset.scale(0, tap_spacing)
|
||||||
|
|
||||||
|
|
@ -2140,9 +2200,14 @@ class layout():
|
||||||
to_layer="m2",
|
to_layer="m2",
|
||||||
offset=loc)
|
offset=loc)
|
||||||
else:
|
else:
|
||||||
self.add_power_pin(name="vdd",
|
if add_vias:
|
||||||
loc=loc,
|
self.add_power_pin(name="vdd",
|
||||||
start_layer="li")
|
loc=loc,
|
||||||
|
start_layer="li")
|
||||||
|
else:
|
||||||
|
self.add_power_pin_no_via(name="vdd",
|
||||||
|
loc=loc,
|
||||||
|
start_layer="li")
|
||||||
count += 1
|
count += 1
|
||||||
loc += nwell_offset.scale(0, tap_spacing)
|
loc += nwell_offset.scale(0, tap_spacing)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,9 @@ class sram_1bank(design, verilog, lef):
|
||||||
# delay control logic does not have RBLs
|
# delay control logic does not have RBLs
|
||||||
self.has_rbl = OPTS.control_logic != "control_logic_delay"
|
self.has_rbl = OPTS.control_logic != "control_logic_delay"
|
||||||
|
|
||||||
|
# IO pins, except power, list of pin names
|
||||||
|
self.pins_to_route = []
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
""" Add pins for entire SRAM. """
|
""" Add pins for entire SRAM. """
|
||||||
|
|
||||||
|
|
@ -244,6 +247,31 @@ class sram_1bank(design, verilog, lef):
|
||||||
def create_modules(self):
|
def create_modules(self):
|
||||||
debug.error("Must override pure virtual function.", -1)
|
debug.error("Must override pure virtual function.", -1)
|
||||||
|
|
||||||
|
def route_supplies_constructive(self, bbox=None):
|
||||||
|
# prepare the "router"
|
||||||
|
from openram.router.supply_placer import supply_placer as router
|
||||||
|
rtr = router(layers=self.supply_stack,
|
||||||
|
design=self,
|
||||||
|
bbox=bbox,
|
||||||
|
pin_type=OPTS.supply_pin_type,
|
||||||
|
ext_vdd_name=self.vdd_name,
|
||||||
|
ext_gnd_name=self.gnd_name)
|
||||||
|
# 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)
|
||||||
|
elif OPTS.supply_pin_type == "ring":
|
||||||
|
rtr.add_ring_pin(self.vdd_name)# ring vdd name
|
||||||
|
rtr.add_ring_pin(self.gnd_name)
|
||||||
|
else:
|
||||||
|
debug.warning("Side supply pins aren't created.")
|
||||||
|
|
||||||
|
# maze router the bank power pins
|
||||||
|
for pin_name in ["vdd", "gnd"]:
|
||||||
|
for inst in self.bank_insts:
|
||||||
|
self.copy_power_pins(inst, pin_name)
|
||||||
|
rtr.route_bank()
|
||||||
|
|
||||||
def route_supplies(self, bbox=None):
|
def route_supplies(self, bbox=None):
|
||||||
""" Route the supply grid and connect the pins to them. """
|
""" Route the supply grid and connect the pins to them. """
|
||||||
|
|
||||||
|
|
@ -324,44 +352,41 @@ class sram_1bank(design, verilog, lef):
|
||||||
"""
|
"""
|
||||||
Add the top-level pins for a single bank SRAM with control.
|
Add the top-level pins for a single bank SRAM with control.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# List of pin to new pin name
|
|
||||||
pins_to_route = []
|
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
# Connect the control pins as inputs
|
# Connect the control pins as inputs
|
||||||
for signal in self.control_logic_inputs[port]:
|
for signal in self.control_logic_inputs[port]:
|
||||||
if signal.startswith("rbl"):
|
if signal.startswith("rbl"):
|
||||||
continue
|
continue
|
||||||
if signal=="clk":
|
if signal=="clk":
|
||||||
pins_to_route.append("{0}{1}".format(signal, port))
|
self.pins_to_route.append("{0}{1}".format(signal, port))
|
||||||
else:
|
else:
|
||||||
pins_to_route.append("{0}{1}".format(signal, port))
|
self.pins_to_route.append("{0}{1}".format(signal, port))
|
||||||
|
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
for bit in range(self.word_size + self.num_spare_cols):
|
for bit in range(self.word_size + self.num_spare_cols):
|
||||||
pins_to_route.append("din{0}[{1}]".format(port, bit))
|
self.pins_to_route.append("din{0}[{1}]".format(port, bit))
|
||||||
|
|
||||||
if port in self.readwrite_ports or port in self.read_ports:
|
if port in self.readwrite_ports or port in self.read_ports:
|
||||||
for bit in range(self.word_size + self.num_spare_cols):
|
for bit in range(self.word_size + self.num_spare_cols):
|
||||||
pins_to_route.append("dout{0}[{1}]".format(port, bit))
|
self.pins_to_route.append("dout{0}[{1}]".format(port, bit))
|
||||||
|
|
||||||
for bit in range(self.col_addr_size):
|
for bit in range(self.col_addr_size):
|
||||||
pins_to_route.append("addr{0}[{1}]".format(port, bit))
|
self.pins_to_route.append("addr{0}[{1}]".format(port, bit))
|
||||||
|
|
||||||
for bit in range(self.row_addr_size):
|
for bit in range(self.row_addr_size):
|
||||||
pins_to_route.append("addr{0}[{1}]".format(port, bit + self.col_addr_size))
|
self.pins_to_route.append("addr{0}[{1}]".format(port, bit + self.col_addr_size))
|
||||||
|
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
if self.write_size != self.word_size:
|
if self.write_size != self.word_size:
|
||||||
for bit in range(self.num_wmasks):
|
for bit in range(self.num_wmasks):
|
||||||
pins_to_route.append("wmask{0}[{1}]".format(port, bit))
|
self.pins_to_route.append("wmask{0}[{1}]".format(port, bit))
|
||||||
|
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
if self.num_spare_cols == 1:
|
if self.num_spare_cols == 1:
|
||||||
pins_to_route.append("spare_wen{0}".format(port))
|
self.pins_to_route.append("spare_wen{0}".format(port))
|
||||||
else:
|
else:
|
||||||
for bit in range(self.num_spare_cols):
|
for bit in range(self.num_spare_cols):
|
||||||
pins_to_route.append("spare_wen{0}[{1}]".format(port, bit))
|
self.pins_to_route.append("spare_wen{0}[{1}]".format(port, bit))
|
||||||
|
|
||||||
if route_option == "classic":
|
if route_option == "classic":
|
||||||
from openram.router import signal_escape_router as router
|
from openram.router import signal_escape_router as router
|
||||||
|
|
@ -373,7 +398,7 @@ class sram_1bank(design, verilog, lef):
|
||||||
bbox=bbox,
|
bbox=bbox,
|
||||||
design=self,
|
design=self,
|
||||||
mod=mod)
|
mod=mod)
|
||||||
rtr.route(pins_to_route)
|
rtr.route(self.pins_to_route)
|
||||||
elif route_option == "fast":
|
elif route_option == "fast":
|
||||||
# use io_pin_placer
|
# use io_pin_placer
|
||||||
# put the IO pins at the edge
|
# put the IO pins at the edge
|
||||||
|
|
@ -381,10 +406,10 @@ class sram_1bank(design, verilog, lef):
|
||||||
pl = placer(layers=self.m3_stack,
|
pl = placer(layers=self.m3_stack,
|
||||||
bbox=bbox,
|
bbox=bbox,
|
||||||
design=self)
|
design=self)
|
||||||
for name in pins_to_route:
|
for name in self.pins_to_route:
|
||||||
debug.warning("pins_to_route pins -> {0}".format(name))
|
debug.warning("pins_to_route pins -> {0}".format(name))
|
||||||
pl.add_io_pins_connected(pins_to_route)
|
pl.add_io_pins_connected(self.pins_to_route)
|
||||||
#pl.add_io_pins(pins_to_route)
|
#pl.add_io_pins(self.pins_to_route)
|
||||||
|
|
||||||
def compute_bus_sizes(self):
|
def compute_bus_sizes(self):
|
||||||
""" Compute the independent bus widths shared between two and four bank SRAMs """
|
""" Compute the independent bus widths shared between two and four bank SRAMs """
|
||||||
|
|
@ -1089,7 +1114,7 @@ class sram_1bank(design, verilog, lef):
|
||||||
self.add_layout_pins()
|
self.add_layout_pins()
|
||||||
|
|
||||||
# Some technologies have an isolation
|
# Some technologies have an isolation
|
||||||
self.add_dnwell(inflate=2.5)
|
self.add_dnwell(inflate=2.5, add_vias=False)
|
||||||
|
|
||||||
init_bbox = self.get_bbox()
|
init_bbox = self.get_bbox()
|
||||||
# Route the supplies together and/or to the ring/stripes.
|
# Route the supplies together and/or to the ring/stripes.
|
||||||
|
|
@ -1100,7 +1125,8 @@ class sram_1bank(design, verilog, lef):
|
||||||
self.route_escape_pins(bbox=init_bbox, mod=mod, route_option=route_option)
|
self.route_escape_pins(bbox=init_bbox, mod=mod, route_option=route_option)
|
||||||
|
|
||||||
if OPTS.route_supplies:
|
if OPTS.route_supplies:
|
||||||
self.route_supplies(init_bbox)
|
#self.route_supplies(init_bbox)
|
||||||
|
self.route_supplies_constructive(init_bbox)
|
||||||
|
|
||||||
def route_dffs(self, add_routes=True):
|
def route_dffs(self, add_routes=True):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -412,7 +412,7 @@ class io_pin_placer(router):
|
||||||
return [source_pin.uc(), target_pin.bc()]
|
return [source_pin.uc(), target_pin.bc()]
|
||||||
else:
|
else:
|
||||||
# need intermediate point
|
# need intermediate point
|
||||||
via_basic_y = ll.y + 21 # 21 is magic number, make sure out of dff area
|
via_basic_y = ll.y + 22 # 22 is magic number, make sure out of dff area
|
||||||
if is_up:
|
if is_up:
|
||||||
via_basic_y = via_basic_y + 0.5
|
via_basic_y = via_basic_y + 0.5
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,54 @@ class router(router_tech):
|
||||||
self.all_pins.update(pin_set)
|
self.all_pins.update(pin_set)
|
||||||
|
|
||||||
|
|
||||||
|
def find_pins_inside(self, pin_name):
|
||||||
|
# find pins except moat, power ring, the moat pins will be store as list 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:
|
||||||
|
layer, boundary = shape
|
||||||
|
# gdsMill boundaries are in (left, bottom, right, top) order
|
||||||
|
ll = vector(boundary[0], boundary[1])
|
||||||
|
ur = vector(boundary[2], boundary[3])
|
||||||
|
rect = [ll, ur]
|
||||||
|
new_pin = graph_shape(pin_name, rect, layer)
|
||||||
|
# Skip this pin if it's contained by another pin of the same type
|
||||||
|
if new_pin.core_contained_by_any(pin_set):
|
||||||
|
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)
|
||||||
|
pin_set.add(new_pin)
|
||||||
|
# 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):
|
||||||
|
""" Check if a given pin is on the moat. """
|
||||||
|
ll, ur = self.bbox
|
||||||
|
left_x = ll.x
|
||||||
|
right_x = ur.x
|
||||||
|
bottom_y = ll.y
|
||||||
|
top_y = ur.y
|
||||||
|
|
||||||
|
threshold = 10 # inside this distance, could be considered as on the moat
|
||||||
|
|
||||||
|
is_on_left = abs(pin_shape.center().x - left_x) < threshold
|
||||||
|
is_on_right = abs(pin_shape.center().x - right_x) < threshold
|
||||||
|
is_on_bottom = abs(pin_shape.center().y - bottom_y) < threshold
|
||||||
|
is_on_top = abs(pin_shape.center().y - top_y) < threshold
|
||||||
|
|
||||||
|
return is_on_left or is_on_right or is_on_bottom or is_on_top
|
||||||
|
|
||||||
|
|
||||||
def find_blockages(self, name="blockage", shape_list=None):
|
def find_blockages(self, name="blockage", shape_list=None):
|
||||||
""" Find all blockages in the routing layers. """
|
""" Find all blockages in the routing layers. """
|
||||||
debug.info(4, "Finding blockages...")
|
debug.info(4, "Finding blockages...")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,344 @@
|
||||||
|
# See LICENSE for licensing information.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
from openram import debug
|
||||||
|
from openram.base.vector import vector
|
||||||
|
from openram import OPTS
|
||||||
|
from .graph import graph
|
||||||
|
from .graph_shape import graph_shape
|
||||||
|
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"):
|
||||||
|
|
||||||
|
# `router` is the base router class
|
||||||
|
router.__init__(self, layers, design, bbox)
|
||||||
|
|
||||||
|
# Side supply pin type
|
||||||
|
# (can be "top", "bottom", "right", "left", and "ring")
|
||||||
|
self.pin_type = pin_type
|
||||||
|
# New pins are the side supply pins
|
||||||
|
self.new_pins = {}
|
||||||
|
# external power name of the whole macro
|
||||||
|
self.ext_vdd_name = ext_vdd_name
|
||||||
|
self.ext_gnd_name = ext_gnd_name
|
||||||
|
# instances
|
||||||
|
self.insts = self.design.insts
|
||||||
|
# moat pins
|
||||||
|
self.moat_pins = []
|
||||||
|
# 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"):
|
||||||
|
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.moat_pins = self.find_pins_inside(vdd_name)
|
||||||
|
self.find_pins_inside(gnd_name)
|
||||||
|
|
||||||
|
# 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))
|
||||||
|
|
||||||
|
# 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]:
|
||||||
|
pins = self.pins[pin_name]
|
||||||
|
# Route closest pins according to the minimum spanning tree
|
||||||
|
for source, target in self.get_mst_pairs(list(pins)):
|
||||||
|
# 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))
|
||||||
|
|
||||||
|
|
||||||
|
#def route_moat(self):
|
||||||
|
|
||||||
|
#def route_other(self):
|
||||||
|
|
||||||
|
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
|
||||||
|
add_distance = 0
|
||||||
|
direction = 1
|
||||||
|
self.prepare_io_pins(io_pin_names)
|
||||||
|
# judge the edge of moat vdd
|
||||||
|
edge = self.get_closest_edge(moat_pin)
|
||||||
|
source_center = moat_pin.center()
|
||||||
|
if edge == "bottom":
|
||||||
|
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
|
||||||
|
while pin_too_close:
|
||||||
|
tmp_center = source_center
|
||||||
|
add_distance = add_distance + 0.1
|
||||||
|
if direction == 1: # right shift
|
||||||
|
tmp_center = tmp_center + add_distance
|
||||||
|
else: # left shift
|
||||||
|
tmp_center = tmp_center - add_distance
|
||||||
|
pin_too_close = any(abs(io_pin.center().x - tmp_center.x) < self.track_width for io_pin in self.io_pins_bottom)
|
||||||
|
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="")
|
||||||
|
else: # need jog
|
||||||
|
# shift the center
|
||||||
|
# add rectangle at same layer (original)
|
||||||
|
self.design.add
|
||||||
|
elif edge == "top":
|
||||||
|
pass
|
||||||
|
elif edge == "left":
|
||||||
|
pass
|
||||||
|
else: #right
|
||||||
|
pass
|
||||||
|
|
||||||
|
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]
|
||||||
|
self.find_closest_edge(io_pin)
|
||||||
|
|
||||||
|
|
||||||
|
def get_closest_edge(self, pin):
|
||||||
|
""" Return a point's the closest edge and the edge's axis direction. Here we use to find the edge of moat vdd """
|
||||||
|
|
||||||
|
ll, ur = self.bbox
|
||||||
|
point = pin.center()
|
||||||
|
# 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)
|
||||||
|
ur_diff_x = abs(point.x - ur.x)
|
||||||
|
ur_diff_y = abs(point.y - ur.y)
|
||||||
|
min_diff = min(ll_diff_x, ll_diff_y, ur_diff_x, ur_diff_y)
|
||||||
|
|
||||||
|
if min_diff == ll_diff_x:
|
||||||
|
return "left"
|
||||||
|
if min_diff == ll_diff_y:
|
||||||
|
return "bottom"
|
||||||
|
if min_diff == ur_diff_x:
|
||||||
|
return "right"
|
||||||
|
return "top"
|
||||||
|
|
||||||
|
|
||||||
|
def find_closest_edge(self, pin):
|
||||||
|
""" Use to find the edge, where the io pin locats """
|
||||||
|
|
||||||
|
ll, ur = self.bbox
|
||||||
|
point = pin.center()
|
||||||
|
# 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)
|
||||||
|
ur_diff_x = abs(point.x - ur.x)
|
||||||
|
ur_diff_y = abs(point.y - ur.y)
|
||||||
|
min_diff = min(ll_diff_x, ll_diff_y, ur_diff_x, ur_diff_y)
|
||||||
|
|
||||||
|
if min_diff == ll_diff_x:
|
||||||
|
self.io_pins_left.append(pin)
|
||||||
|
elif min_diff == ll_diff_y:
|
||||||
|
self.io_pins_bottom.append(pin)
|
||||||
|
elif min_diff == ur_diff_x:
|
||||||
|
self.io_pins_right.append(pin)
|
||||||
|
else:
|
||||||
|
self.io_pins_top.append(pin)
|
||||||
|
|
||||||
|
|
||||||
|
def add_side_pin(self, pin_name, side, num_vias=3, num_fake_pins=4):
|
||||||
|
""" Add supply pin to one side of the layout. """
|
||||||
|
|
||||||
|
ll, ur = self.bbox
|
||||||
|
vertical = side in ["left", "right"]
|
||||||
|
inner = pin_name == self.ext_vdd_name
|
||||||
|
|
||||||
|
# Calculate wires' wideness
|
||||||
|
wideness = self.track_wire * num_vias + self.track_space * (num_vias - 1)
|
||||||
|
|
||||||
|
# Calculate the offset for the inner ring
|
||||||
|
if inner:
|
||||||
|
margin = wideness * 2
|
||||||
|
else:
|
||||||
|
margin = 0
|
||||||
|
|
||||||
|
# Calculate the lower left coordinate
|
||||||
|
if side == "top":
|
||||||
|
offset = vector(ll.x + margin, ur.y - wideness - margin)
|
||||||
|
elif side == "bottom":
|
||||||
|
offset = vector(ll.x + margin, ll.y + margin)
|
||||||
|
elif side == "left":
|
||||||
|
offset = vector(ll.x + margin, ll.y + margin)
|
||||||
|
elif side == "right":
|
||||||
|
offset = vector(ur.x - wideness - margin, ll.y + margin)
|
||||||
|
|
||||||
|
# Calculate width and height
|
||||||
|
shape = ur - ll
|
||||||
|
if vertical:
|
||||||
|
shape_width = wideness
|
||||||
|
shape_height = shape.y
|
||||||
|
else:
|
||||||
|
shape_width = shape.x
|
||||||
|
shape_height = wideness
|
||||||
|
if inner:
|
||||||
|
if vertical:
|
||||||
|
shape_height -= margin * 2
|
||||||
|
else:
|
||||||
|
shape_width -= margin * 2
|
||||||
|
|
||||||
|
# Add this new pin
|
||||||
|
layer = self.get_layer(int(vertical))
|
||||||
|
pin = self.design.add_layout_pin(text=pin_name,
|
||||||
|
layer=layer,
|
||||||
|
offset=offset,
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def add_ring_pin(self, pin_name, num_vias=3, num_fake_pins=4):
|
||||||
|
""" Add the supply ring to the layout. """
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
ll, ur = new_shape.rect
|
||||||
|
rect = [ll, ur]
|
||||||
|
layer = self.get_layer(side in ["left", "right"])
|
||||||
|
new_pin = graph_shape(name=pin_name,
|
||||||
|
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
|
||||||
|
half_wide = self.track_wire / 2
|
||||||
|
for i in range(4):
|
||||||
|
ll, ur = new_pins[i].rect
|
||||||
|
if i % 2:
|
||||||
|
top_left = vector(ur.x - (num_vias - 1) * shift - half_wide, ll.y + (num_vias - 1) * shift + half_wide)
|
||||||
|
else:
|
||||||
|
top_left = vector(ll.x + half_wide, ur.y - half_wide)
|
||||||
|
for j in range(num_vias):
|
||||||
|
for k in range(num_vias):
|
||||||
|
offset = vector(top_left.x + j * shift, top_left.y - k * shift)
|
||||||
|
self.design.add_via_center(layers=self.layers,
|
||||||
|
offset=offset)
|
||||||
|
|
||||||
|
# Save side pins for routing
|
||||||
|
self.new_pins[pin_name] = new_pins
|
||||||
|
for pin in new_pins:
|
||||||
|
self.blockages.append(self.inflate_shape(pin))
|
||||||
|
|
||||||
|
|
||||||
|
def get_mst_pairs(self, pins):
|
||||||
|
"""
|
||||||
|
Return the pin pairs from the minimum spanning tree in a graph that
|
||||||
|
connects all pins together.
|
||||||
|
"""
|
||||||
|
|
||||||
|
pin_count = len(pins)
|
||||||
|
|
||||||
|
# Create an adjacency matrix that connects all pins
|
||||||
|
edges = [[0] * pin_count for i in range(pin_count)]
|
||||||
|
for i in range(pin_count):
|
||||||
|
for j in range(pin_count):
|
||||||
|
# Skip if they're the same pin
|
||||||
|
if i == j:
|
||||||
|
continue
|
||||||
|
# Skip if both pins are fake
|
||||||
|
if pins[i] in self.fake_pins and pins[j] in self.fake_pins:
|
||||||
|
continue
|
||||||
|
edges[i][j] = pins[i].distance(pins[j])
|
||||||
|
|
||||||
|
pin_connected = [False] * pin_count
|
||||||
|
pin_connected[0] = True
|
||||||
|
|
||||||
|
# Add the minimum cost edge in each iteration (Prim's)
|
||||||
|
mst_pairs = []
|
||||||
|
for i in range(pin_count - 1):
|
||||||
|
min_cost = float("inf")
|
||||||
|
s = 0
|
||||||
|
t = 0
|
||||||
|
# Iterate over already connected pins
|
||||||
|
for m in range(pin_count):
|
||||||
|
# Skip if not connected
|
||||||
|
if not pin_connected[m]:
|
||||||
|
continue
|
||||||
|
# Iterate over this pin's neighbors
|
||||||
|
for n in range(pin_count):
|
||||||
|
# Skip if already connected or isn't a neighbor
|
||||||
|
if pin_connected[n] or edges[m][n] == 0:
|
||||||
|
continue
|
||||||
|
# Choose this edge if it's better the the current one
|
||||||
|
if edges[m][n] < min_cost:
|
||||||
|
min_cost = edges[m][n]
|
||||||
|
s = m
|
||||||
|
t = n
|
||||||
|
pin_connected[t] = True
|
||||||
|
mst_pairs.append((pins[s], pins[t]))
|
||||||
|
|
||||||
|
return mst_pairs
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_pins(self, name):
|
||||||
|
""" Return the new supply pins added by this router. """
|
||||||
|
|
||||||
|
return self.new_pins[name]
|
||||||
|
|
@ -97,7 +97,7 @@ class supply_router(router):
|
||||||
|
|
||||||
ll, ur = self.bbox
|
ll, ur = self.bbox
|
||||||
vertical = side in ["left", "right"]
|
vertical = side in ["left", "right"]
|
||||||
inner = pin_name == self.gnd_name
|
inner = pin_name == self.vdd_name
|
||||||
|
|
||||||
# Calculate wires' wideness
|
# Calculate wires' wideness
|
||||||
wideness = self.track_wire * num_vias + self.track_space * (num_vias - 1)
|
wideness = self.track_wire * num_vias + self.track_space * (num_vias - 1)
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ for path in output_files:
|
||||||
|
|
||||||
# Create an SRAM (we can also pass sram_config, see documentation/tutorials for details)
|
# Create an SRAM (we can also pass sram_config, see documentation/tutorials for details)
|
||||||
from openram import sram
|
from openram import sram
|
||||||
s = sram(route_option="classic")# "classic" or "fast"
|
s = sram(route_option="fast")# "classic" or "fast"
|
||||||
# Output the files for the resulting SRAM
|
# Output the files for the resulting SRAM
|
||||||
s.save()
|
s.save()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue