mirror of https://github.com/VLSIDA/OpenRAM.git
add route_outside, remove unused methods
This commit is contained in:
parent
86588619fd
commit
4fe635a05f
|
|
@ -1913,8 +1913,8 @@ class layout():
|
|||
# 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)
|
||||
|
||||
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
|
||||
def add_power_pin_m2(self, name, loc, directions=None, start_layer="m1"):
|
||||
# same function like normal one, but add power pin at m2
|
||||
# Hack for min area
|
||||
if OPTS.tech_name == "sky130":
|
||||
min_area = drc["minarea_{}".format(self.pwr_grid_layers[1])]
|
||||
|
|
@ -1925,7 +1925,7 @@ class layout():
|
|||
height = None
|
||||
|
||||
pin = None
|
||||
if start_layer in self.pwr_grid_layers:
|
||||
if start_layer == "m2":
|
||||
pin = self.add_layout_pin_rect_center(text=name,
|
||||
layer=start_layer,
|
||||
offset=loc,
|
||||
|
|
@ -1933,7 +1933,7 @@ class layout():
|
|||
height=height)
|
||||
else:
|
||||
via = self.add_via_stack_center(from_layer=start_layer,
|
||||
to_layer=start_layer,# so only enclosure shape will be added
|
||||
to_layer="m2",
|
||||
offset=loc,
|
||||
directions=directions)
|
||||
|
||||
|
|
@ -1942,7 +1942,7 @@ class layout():
|
|||
if not height:
|
||||
height = via.height
|
||||
pin = self.add_layout_pin_rect_center(text=name,
|
||||
layer=start_layer,
|
||||
layer="m2",
|
||||
offset=loc,
|
||||
width=width,
|
||||
height=height)
|
||||
|
|
@ -2063,7 +2063,7 @@ class layout():
|
|||
layer=layer,
|
||||
offset=peri_pin_loc)
|
||||
|
||||
def add_dnwell(self, bbox=None, inflate=1, add_vias=True):
|
||||
def add_dnwell(self, bbox=None, inflate=1, route_option="classic"):
|
||||
""" Create a dnwell, along with nwell moat at border. """
|
||||
|
||||
if "dnwell" not in tech_layer:
|
||||
|
|
@ -2108,9 +2108,9 @@ class layout():
|
|||
tap_spacing = 2
|
||||
nwell_offset = vector(self.nwell_width, self.nwell_width)
|
||||
|
||||
# Every nth tap is connected to gnd
|
||||
# Every nth tap is connected to vdd
|
||||
period = 5
|
||||
|
||||
moat_pins = []
|
||||
# BOTTOM
|
||||
count = 0
|
||||
loc = ll + nwell_offset.scale(tap_spacing, 0)
|
||||
|
|
@ -2125,14 +2125,10 @@ class layout():
|
|||
to_layer="m1",
|
||||
offset=loc)
|
||||
else:
|
||||
if add_vias:
|
||||
self.add_power_pin(name="vdd",
|
||||
loc=loc,
|
||||
start_layer="li")
|
||||
else:
|
||||
self.add_power_pin_no_via(name="vdd",
|
||||
loc=loc,
|
||||
start_layer="li")
|
||||
pin = self.add_power_pin(name="vdd",
|
||||
loc=loc,
|
||||
start_layer="li")
|
||||
moat_pins.append(pin)
|
||||
count += 1
|
||||
loc += nwell_offset.scale(tap_spacing, 0)
|
||||
|
||||
|
|
@ -2150,14 +2146,10 @@ class layout():
|
|||
to_layer="m1",
|
||||
offset=loc)
|
||||
else:
|
||||
if add_vias:
|
||||
self.add_power_pin(name="vdd",
|
||||
loc=loc,
|
||||
start_layer="li")
|
||||
else:
|
||||
self.add_power_pin_no_via(name="vdd",
|
||||
loc=loc,
|
||||
start_layer="li")
|
||||
pin = self.add_power_pin(name="vdd",
|
||||
loc=loc,
|
||||
start_layer="li")
|
||||
moat_pins.append(pin)
|
||||
count += 1
|
||||
loc += nwell_offset.scale(tap_spacing, 0)
|
||||
|
||||
|
|
@ -2175,14 +2167,15 @@ class layout():
|
|||
to_layer="m2",
|
||||
offset=loc)
|
||||
else:
|
||||
if add_vias:
|
||||
self.add_power_pin(name="vdd",
|
||||
loc=loc,
|
||||
start_layer="li")
|
||||
else:
|
||||
self.add_power_pin_no_via(name="vdd",
|
||||
loc=loc,
|
||||
start_layer="li")
|
||||
if route_option == "classic":
|
||||
pin = self.add_power_pin(name="vdd",
|
||||
loc=loc,
|
||||
start_layer="li")
|
||||
elif route_option == "fast":
|
||||
pin = self.add_power_pin_m2(name="vdd",
|
||||
loc=loc,
|
||||
start_layer="li")
|
||||
moat_pins.append(pin)
|
||||
count += 1
|
||||
loc += nwell_offset.scale(0, tap_spacing)
|
||||
|
||||
|
|
@ -2200,19 +2193,21 @@ class layout():
|
|||
to_layer="m2",
|
||||
offset=loc)
|
||||
else:
|
||||
if add_vias:
|
||||
self.add_power_pin(name="vdd",
|
||||
loc=loc,
|
||||
start_layer="li")
|
||||
else:
|
||||
self.add_power_pin_no_via(name="vdd",
|
||||
loc=loc,
|
||||
start_layer="li")
|
||||
if route_option == "classic":
|
||||
pin = self.add_power_pin(name="vdd",
|
||||
loc=loc,
|
||||
start_layer="li")
|
||||
elif route_option == "fast":
|
||||
pin = self.add_power_pin_m2(name="vdd",
|
||||
loc=loc,
|
||||
start_layer="li")
|
||||
moat_pins.append(pin)
|
||||
count += 1
|
||||
loc += nwell_offset.scale(0, tap_spacing)
|
||||
|
||||
# Add the gnd ring
|
||||
# Add the vdd ring
|
||||
self.add_ring([ll, ur])
|
||||
return moat_pins
|
||||
|
||||
def add_ring(self, bbox=None, width_mult=8, offset=0):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -53,8 +53,10 @@ class sram_1bank(design, verilog, lef):
|
|||
# delay control logic does not have RBLs
|
||||
self.has_rbl = OPTS.control_logic != "control_logic_delay"
|
||||
|
||||
# IO pins, except power, list of pin names
|
||||
# IO pins, except power, list of pin names
|
||||
self.pins_to_route = []
|
||||
# vdd pins on moat, list of pins
|
||||
self.moat_pins = []
|
||||
|
||||
def add_pins(self):
|
||||
""" Add pins for entire SRAM. """
|
||||
|
|
@ -248,6 +250,7 @@ class sram_1bank(design, verilog, lef):
|
|||
debug.error("Must override pure virtual function.", -1)
|
||||
|
||||
def route_supplies_constructive(self, bbox=None):
|
||||
""" Corresponding supply router for io_pin_placer """
|
||||
# prepare the "router"
|
||||
from openram.router.supply_placer import supply_placer as router
|
||||
rtr = router(layers=self.supply_stack,
|
||||
|
|
@ -255,22 +258,32 @@ class sram_1bank(design, verilog, lef):
|
|||
bbox=bbox,
|
||||
pin_type=OPTS.supply_pin_type,
|
||||
ext_vdd_name=self.vdd_name,
|
||||
ext_gnd_name=self.gnd_name)
|
||||
ext_gnd_name=self.gnd_name,
|
||||
moat_pins=self.moat_pins)
|
||||
|
||||
# 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)
|
||||
rtr.add_side_pin("vdd")
|
||||
rtr.add_side_pin("gnd")# noraml 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)
|
||||
rtr.add_ring_pin("vdd")
|
||||
rtr.add_ring_pin("gnd")# normal gnd name
|
||||
else:
|
||||
debug.warning("Side supply pins aren't created.")
|
||||
|
||||
# maze router the bank power pins
|
||||
# Prepare the inside power pins (all power pins of submodules), at m3
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
for inst in self.bank_insts:
|
||||
for inst in self.insts:
|
||||
self.copy_power_pins(inst, pin_name)
|
||||
rtr.route_bank()
|
||||
# Route all the power pins
|
||||
#rtr.route_inside() # only connecting the power pins of inside submodules with each other, moat pins will connect to the ring
|
||||
rtr.route_outside(io_pin_names=self.pins_to_route)
|
||||
# route moat vdds
|
||||
#rtr.route_moat(self.pins_to_route)
|
||||
|
||||
# route to the outside
|
||||
#rtr.prepare_escape_pins()
|
||||
|
||||
|
||||
def route_supplies(self, bbox=None):
|
||||
""" Route the supply grid and connect the pins to them. """
|
||||
|
|
@ -1114,7 +1127,7 @@ class sram_1bank(design, verilog, lef):
|
|||
self.add_layout_pins()
|
||||
|
||||
# Some technologies have an isolation
|
||||
self.add_dnwell(inflate=2.5, add_vias=False)
|
||||
self.moat_pins = self.add_dnwell(inflate=2.5, route_option=route_option)
|
||||
|
||||
init_bbox = self.get_bbox()
|
||||
# Route the supplies together and/or to the ring/stripes.
|
||||
|
|
|
|||
|
|
@ -112,10 +112,10 @@ class router(router_tech):
|
|||
|
||||
|
||||
def find_pins_inside(self, pin_name):
|
||||
# find pins except moat, power ring, the moat pins will be store as list and return
|
||||
# find pins except moat, power ring, the moat pins will be store as set 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:
|
||||
|
|
@ -130,7 +130,6 @@ class router(router_tech):
|
|||
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)
|
||||
|
|
@ -138,7 +137,6 @@ class router(router_tech):
|
|||
# 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):
|
||||
|
|
|
|||
|
|
@ -89,6 +89,8 @@ class router_tech:
|
|||
|
||||
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
|
||||
self.layer_widths = [self.track_wire, 1, self.track_wire]
|
||||
# via2 to via3 distance requirements
|
||||
self.via2_via3_pitch = 0.5 * drc("minwidth_{}".format("via2")) + 0.5 * drc("minwidth_{}".format("via3")) + drc["via3_to_via2"]
|
||||
|
||||
def same_lpp(self, lpp1, lpp2):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ 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"):
|
||||
def __init__(self, layers, design, bbox=None, pin_type=None, ext_vdd_name="vccd1", ext_gnd_name="vssd1", moat_pins=None):
|
||||
|
||||
# `router` is the base router class
|
||||
router.__init__(self, layers, design, bbox)
|
||||
|
|
@ -28,14 +28,23 @@ class supply_placer(router):
|
|||
# instances
|
||||
self.insts = self.design.insts
|
||||
# moat pins
|
||||
self.moat_pins = []
|
||||
self.moat_pins = moat_pins
|
||||
# store a graphshape of intermediate points(if shift)/source points(if no shift) when connecting moat_pins to outside
|
||||
# trick: since in the creation of dnwell, these pins are "ordered" added, so they'are also ordered here
|
||||
# order inside list: left -> right or bottom -> up
|
||||
self.moat_pins_left = []
|
||||
self.moat_pins_right = []
|
||||
self.moat_pins_top = []
|
||||
self.moat_pins_bottom = []
|
||||
# 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"):
|
||||
|
||||
def route_outside(self, vdd_name="vdd", gnd_name="gnd", io_pin_names=None):
|
||||
# only connect supply with inside submodules, not connecting to the power ring
|
||||
debug.info(1, "Running router for {} and {}...".format(vdd_name, gnd_name))
|
||||
|
||||
# Save pin names
|
||||
|
|
@ -46,7 +55,75 @@ class supply_placer(router):
|
|||
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(vdd_name)
|
||||
self.find_pins_inside(gnd_name)
|
||||
self.route_moat(io_pin_names)
|
||||
# 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))
|
||||
|
||||
# Prepare the selected moat pins
|
||||
selected_moat_pins = self.prepare_selected_moat_pins()
|
||||
# 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]:
|
||||
if pin_name == gnd_name: # otherwise will not recognaize the moat blocakge
|
||||
self.prepare_gds_reader()
|
||||
# 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()
|
||||
|
||||
pins = self.pins[pin_name]
|
||||
# Route closest pins according to the minimum spanning tree
|
||||
for source, target in self.get_mst_with_ring(list(pins), selected_moat_pins, pin_name):
|
||||
# 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))
|
||||
# finsih
|
||||
self.replace_layout_pins()
|
||||
|
||||
|
||||
def route_inside(self, vdd_name="vdd", gnd_name="gnd"):
|
||||
# only connect supply with inside submodules, not connecting to the power ring
|
||||
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.find_pins_inside(vdd_name)
|
||||
self.find_pins_inside(gnd_name)
|
||||
|
||||
# Find blockages and vias
|
||||
|
|
@ -86,14 +163,152 @@ class supply_placer(router):
|
|||
# Report routed count
|
||||
routed_count += 1
|
||||
debug.info(2, "Routed {} of {} supply pins".format(routed_count, routed_max))
|
||||
# finsih
|
||||
self.replace_layout_pins()
|
||||
|
||||
|
||||
#def route_moat(self):
|
||||
def route_moat(self, io_pin_names):
|
||||
# route the vdd pins at the moat
|
||||
# io_pin_names is a list
|
||||
# the moat vdd shape will also be created and stored in the list
|
||||
for moat_pin in self.moat_pins:
|
||||
self.check_overlap(moat_pin, io_pin_names)
|
||||
|
||||
|
||||
def replace_layout_pins(self):
|
||||
# clear all the inside "vdd " "gnd" at sram module level
|
||||
# Copy the pin shape(s) to rectangles
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
# Copy the pin shape(s) to rectangles
|
||||
for pin in self.design.get_pins(pin_name):
|
||||
self.design.add_rect(pin.layer,
|
||||
pin.ll(),
|
||||
pin.width(),
|
||||
pin.height())
|
||||
|
||||
# Remove the pin shape(s)
|
||||
self.design.remove_layout_pin(pin_name)
|
||||
|
||||
#def route_other(self):
|
||||
# Get new pins, change the name of ring to extern supply name
|
||||
# vccd1 ring
|
||||
pins = self.get_new_pins("vdd")
|
||||
for pin in pins:
|
||||
self.design.add_layout_pin(self.ext_vdd_name,
|
||||
pin.layer,
|
||||
pin.ll(),
|
||||
pin.width(),
|
||||
pin.height())
|
||||
# vssd1 ring
|
||||
pins = self.get_new_pins("gnd")
|
||||
for pin in pins:
|
||||
self.design.add_layout_pin(self.ext_gnd_name,
|
||||
pin.layer,
|
||||
pin.ll(),
|
||||
pin.width(),
|
||||
pin.height())
|
||||
|
||||
|
||||
def prepare_selected_moat_pins(self):
|
||||
""" Selcet the possibe moat pins, feed into the MST, where will decide which of these pin should be connected to which pin """
|
||||
if len(self.design.all_ports) > 1:
|
||||
# in order to save runtime
|
||||
# top -> moat pins all
|
||||
# bottom -> moat pins all
|
||||
# left -> moat pins near control logic
|
||||
# right -> moat pins near control logic
|
||||
# expected connection for control logic
|
||||
|
||||
# for port 0 -> left
|
||||
start_y = self.design.control_logic_insts[0].by()# bottom edge y value
|
||||
end_y = self.design.control_logic_insts[0].uy()# up edge y value
|
||||
# filter the pin in the range
|
||||
filtered_moat_pins_left = [pin for pin in self.moat_pins_left if start_y <= pin.center().y <= end_y]
|
||||
|
||||
# for port 1 -> right
|
||||
start_y = self.design.control_logic_insts[1].by()# bottom edge y value
|
||||
end_y = self.design.control_logic_insts[1].uy()# up edge y value
|
||||
# filter the pin in the range
|
||||
filtered_moat_pins_right = [pin for pin in self.moat_pins_right if start_y <= pin.center().y <= end_y]
|
||||
# return the selected moat pins
|
||||
selected_moat_pins = []
|
||||
selected_moat_pins.extend(filtered_moat_pins_left)
|
||||
selected_moat_pins.extend(self.moat_pins_bottom)
|
||||
selected_moat_pins.extend(filtered_moat_pins_right)
|
||||
selected_moat_pins.extend(self.moat_pins_top)
|
||||
return selected_moat_pins
|
||||
|
||||
else: # only 1 port
|
||||
# in order to save runtime
|
||||
# top -> moat pins all
|
||||
# bottom -> moat pins all
|
||||
# left -> moat pins near control logic
|
||||
# right -> moat pins all
|
||||
start_y = self.design.control_logic_insts[0].by()# bottom edge y value
|
||||
end_y = self.design.control_logic_insts[0].uy()# up edge y value
|
||||
# filter the pin in the range
|
||||
filtered_moat_pins_left = [pin for pin in self.moat_pins_left if start_y <= pin.center().y <= end_y]
|
||||
# return the selected moat pins
|
||||
selected_moat_pins = []
|
||||
selected_moat_pins.extend(filtered_moat_pins_left)
|
||||
selected_moat_pins.extend(self.moat_pins_bottom)
|
||||
selected_moat_pins.extend(self.moat_pins_right)
|
||||
selected_moat_pins.extend(self.moat_pins_top)
|
||||
return selected_moat_pins
|
||||
|
||||
|
||||
def prepare_escape_pins(self):
|
||||
# clear all the inside "vdd " "gnd" at sram module level
|
||||
# Copy the pin shape(s) to rectangles
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
# Copy the pin shape(s) to rectangles
|
||||
for pin in self.design.get_pins(pin_name):
|
||||
self.design.add_rect(pin.layer,
|
||||
pin.ll(),
|
||||
pin.width(),
|
||||
pin.height())
|
||||
|
||||
# Remove the pin shape(s)
|
||||
self.design.remove_layout_pin(pin_name)
|
||||
|
||||
# prepare pins for every instances
|
||||
for pin_name in ["vdd"]:
|
||||
count =0
|
||||
for pin in self.design.control_logic_insts[0].get_pins(pin_name):
|
||||
debug.warning("vdd pin shape -> ll:{0} ur:{1}".format(pin.ll(), pin.ur()))
|
||||
"""
|
||||
count = count + 1
|
||||
new_pin = graph_shape("gnd", pin.rect, pin.layer)
|
||||
source = new_pin
|
||||
source_center_x = pin.center().x
|
||||
target_ur_y = self.new_pins[self.ext_gnd_name][1].center().y + 0.5 * self.new_pins[self.ext_gnd_name][1].height()
|
||||
ll = vector(source_center_x - 2.6 - 0.5 * self.track_wire, pin.center().y - 0.5 * self.track_wire)#target_ur_y - self.track_wire)
|
||||
ur = vector(source_center_x - 2.6 + 0.5 * self.track_wire, pin.center().y + 0.5 * self.track_wire)#target_ur_y)
|
||||
target = graph_shape("fake", [ll,ur], pin.layer)
|
||||
# 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)
|
||||
"""
|
||||
debug.warning("vdd of wmask number -> {0}".format(count))
|
||||
debug.warning("instance postion -> {0} {1}".format(self.design.control_logic_insts[0].lx(), self.design.control_logic_insts[0].by()))
|
||||
|
||||
# print pins_all
|
||||
for pin in self.all_pins:
|
||||
debug.warning("all_pins -> {0}".format(pin))
|
||||
|
||||
|
||||
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
|
||||
# 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 connect them
|
||||
add_distance = 0
|
||||
direction = 1
|
||||
self.prepare_io_pins(io_pin_names)
|
||||
|
|
@ -101,36 +316,294 @@ class supply_placer(router):
|
|||
edge = self.get_closest_edge(moat_pin)
|
||||
source_center = moat_pin.center()
|
||||
if edge == "bottom":
|
||||
add_distance = self.via2_via3_pitch # if shift, need to fulfill via2-via3 spacing, top/bottom only
|
||||
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
|
||||
tmp_center = vector(source_center.x, source_center.y)
|
||||
while pin_too_close:
|
||||
tmp_center = source_center
|
||||
tmp_center = vector(source_center.x, source_center.y)
|
||||
add_distance = add_distance + 0.1
|
||||
if direction == 1: # right shift
|
||||
tmp_center = tmp_center + add_distance
|
||||
tmp_center = vector((tmp_center.x + add_distance), tmp_center.y)
|
||||
else: # left shift
|
||||
tmp_center = tmp_center - add_distance
|
||||
tmp_center = vector((tmp_center.x - add_distance), tmp_center.y)
|
||||
pin_too_close = any(abs(io_pin.center().x - tmp_center.x) < self.track_width for io_pin in self.io_pins_bottom)
|
||||
direction = - direction
|
||||
# the nearst vdd ring
|
||||
vdd_ring = self.new_pins["vdd"][1] # order in list -> "top", "bottom", "right", "left"]
|
||||
# bottom ring's y position at it's top
|
||||
target_egde_y = vdd_ring.center().y + 0.5 * vdd_ring.height()
|
||||
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="")
|
||||
# no jog, direct return the source/target center position
|
||||
# the target center position, should consider enought space for via
|
||||
target_point = vector(tmp_center.x, (target_egde_y - 0.5 * self.track_wire))
|
||||
source_point = vector(tmp_center.x, tmp_center.y)
|
||||
point_list = [source_point, target_point]
|
||||
self.add_wire(point_list, vertical=True)
|
||||
# store the shape of moat pins, need for route later
|
||||
ll = vector(source_point.x - 0.5 * self.track_wire, source_point.y - 0.5 * self.track_wire)
|
||||
ur = vector(source_point.x + 0.5 * self.track_wire, source_point.y + 0.5 * self.track_wire)
|
||||
rect = [ll, ur]
|
||||
moat_pin_route = graph_shape("vdd", rect, "m4")
|
||||
self.moat_pins_bottom.append(moat_pin_route)
|
||||
else: # need jog
|
||||
# shift the center
|
||||
# add rectangle at same layer (original)
|
||||
self.design.add
|
||||
intermediate_point = vector(tmp_center.x, tmp_center.y)
|
||||
source_point = vector(source_center.x, source_center.y)
|
||||
target_point = vector(tmp_center.x, (target_egde_y - 0.5 * self.track_wire))
|
||||
point_list = [source_point, intermediate_point, target_point]
|
||||
self.add_wire(point_list, vertical=True)
|
||||
# store the shape of moat pins, need for route later
|
||||
ll = vector(intermediate_point.x - 0.5 * self.track_wire, intermediate_point.y - 0.5 * self.track_wire)
|
||||
ur = vector(intermediate_point.x + 0.5 * self.track_wire, intermediate_point.y + 0.5 * self.track_wire)
|
||||
rect = [ll, ur]
|
||||
moat_pin_route = graph_shape("vdd", rect, "m4")
|
||||
self.moat_pins_bottom.append(moat_pin_route)
|
||||
elif edge == "top":
|
||||
pass
|
||||
add_distance = self.via2_via3_pitch # if shift, need to fulfill via2-via3 spacing, top/bottom only
|
||||
pin_too_close = any(abs(io_pin.center().x - source_center.x) < self.track_width for io_pin in self.io_pins_top)
|
||||
tmp_center = vector(source_center.x, source_center.y)
|
||||
while pin_too_close:
|
||||
tmp_center = vector(source_center.x, source_center.y)
|
||||
add_distance = add_distance + 0.1
|
||||
if direction == 1: # right shift
|
||||
tmp_center = vector((tmp_center.x + add_distance), tmp_center.y)
|
||||
else: # left shift
|
||||
tmp_center = vector((tmp_center.x - add_distance), tmp_center.y)
|
||||
pin_too_close = any(abs(io_pin.center().x - tmp_center.x) < self.track_width for io_pin in self.io_pins_top)
|
||||
direction = - direction
|
||||
# the nearst vdd ring
|
||||
vdd_ring = self.new_pins["vdd"][0] # order in list -> "top", "bottom", "right", "left"]
|
||||
# top ring's y position at it's bottom
|
||||
target_egde_y = vdd_ring.center().y - 0.5 * vdd_ring.height()
|
||||
if tmp_center == source_center: # no overlap
|
||||
# no jog, direct return the source/target center position
|
||||
# the target center position, should consider enought space for via
|
||||
target_point = vector(tmp_center.x, (target_egde_y + 0.5 * self.track_wire))
|
||||
source_point = vector(tmp_center.x, tmp_center.y)
|
||||
point_list = [source_point, target_point]
|
||||
self.add_wire(point_list, vertical=True)
|
||||
# store the shape of moat pins, need for route later
|
||||
ll = vector(source_point.x - 0.5 * self.track_wire, source_point.y - 0.5 * self.track_wire)
|
||||
ur = vector(source_point.x + 0.5 * self.track_wire, source_point.y + 0.5 * self.track_wire)
|
||||
rect = [ll, ur]
|
||||
moat_pin_route = graph_shape("vdd", rect, "m4")
|
||||
self.moat_pins_top.append(moat_pin_route)
|
||||
else: # need jog
|
||||
# shift the center
|
||||
# add rectangle at same layer (original)
|
||||
intermediate_point = vector(tmp_center.x, tmp_center.y)
|
||||
source_point = vector(source_center.x, source_center.y)
|
||||
target_point = vector(tmp_center.x, (target_egde_y + 0.5 * self.track_wire))
|
||||
point_list = [source_point, intermediate_point, target_point]
|
||||
self.add_wire(point_list, vertical=True)
|
||||
# store the shape of moat pins, need for route later
|
||||
ll = vector(intermediate_point.x - 0.5 * self.track_wire, intermediate_point.y - 0.5 * self.track_wire)
|
||||
ur = vector(intermediate_point.x + 0.5 * self.track_wire, intermediate_point.y + 0.5 * self.track_wire)
|
||||
rect = [ll, ur]
|
||||
moat_pin_route = graph_shape("vdd", rect, "m4")
|
||||
self.moat_pins_top.append(moat_pin_route)
|
||||
elif edge == "left":
|
||||
pass
|
||||
pin_too_close = any(abs(io_pin.center().y - source_center.y) < self.track_width for io_pin in self.io_pins_left)
|
||||
tmp_center = vector(source_center.x, source_center.y)
|
||||
while pin_too_close:
|
||||
tmp_center = vector(source_center.x, source_center.y)
|
||||
add_distance = add_distance + 0.1
|
||||
if direction == 1: # up shift
|
||||
tmp_center = vector(tmp_center.x, (tmp_center.y + add_distance))
|
||||
else: # down shift
|
||||
tmp_center = vector(tmp_center.x, (tmp_center.y - add_distance))
|
||||
pin_too_close = any(abs(io_pin.center().y - tmp_center.y) < self.track_width for io_pin in self.io_pins_left)
|
||||
direction = - direction
|
||||
# the nearst vdd ring
|
||||
vdd_ring = self.new_pins["vdd"][3] # order in list -> "top", "bottom", "right", "left"]
|
||||
# left ring's x position at it's right
|
||||
target_egde_x = vdd_ring.center().x + 0.5 * vdd_ring.width()
|
||||
if tmp_center == source_center: # no overlap
|
||||
# no jog, direct return the source/target center position
|
||||
# the target center position, should consider enought space for via
|
||||
target_point = vector((target_egde_x - 0.5 * self.track_wire), tmp_center.y)
|
||||
source_point = vector(tmp_center.x, tmp_center.y)
|
||||
point_list = [source_point, target_point]
|
||||
self.add_wire(point_list, vertical=False)
|
||||
# store the shape of moat pins, need for route later
|
||||
ll = vector(source_point.x - 0.5 * self.track_wire, source_point.y - 0.5 * self.track_wire)
|
||||
ur = vector(source_point.x + 0.5 * self.track_wire, source_point.y + 0.5 * self.track_wire)
|
||||
rect = [ll, ur]
|
||||
moat_pin_route = graph_shape("vdd", rect, "m3")
|
||||
self.moat_pins_left.append(moat_pin_route)
|
||||
else: # need jog
|
||||
# shift the center
|
||||
# add rectangle at same layer (original)
|
||||
intermediate_point = vector(tmp_center.x, tmp_center.y)
|
||||
source_point = vector(source_center.x, source_center.y)
|
||||
target_point = vector((target_egde_x - 0.5 * self.track_wire), tmp_center.y)
|
||||
point_list = [source_point, intermediate_point, target_point]
|
||||
self.add_wire(point_list, vertical=False)
|
||||
# store the shape of moat pins, need for route later
|
||||
ll = vector(intermediate_point.x - 0.5 * self.track_wire, intermediate_point.y - 0.5 * self.track_wire)
|
||||
ur = vector(intermediate_point.x + 0.5 * self.track_wire, intermediate_point.y + 0.5 * self.track_wire)
|
||||
rect = [ll, ur]
|
||||
moat_pin_route = graph_shape("vdd", rect, "m3")
|
||||
self.moat_pins_left.append(moat_pin_route)
|
||||
else: #right
|
||||
pass
|
||||
pin_too_close = any(abs(io_pin.center().y - source_center.y) < self.track_width for io_pin in self.io_pins_right)
|
||||
tmp_center = vector(source_center.x, source_center.y)
|
||||
while pin_too_close:
|
||||
tmp_center = vector(source_center.x, source_center.y)
|
||||
add_distance = add_distance + 0.1
|
||||
if direction == 1: # up shift
|
||||
tmp_center = vector(tmp_center.x, (tmp_center.y + add_distance))
|
||||
else: # down shift
|
||||
tmp_center = vector(tmp_center.x, (tmp_center.y - add_distance))
|
||||
pin_too_close = any(abs(io_pin.center().y - tmp_center.y) < self.track_width for io_pin in self.io_pins_right)
|
||||
direction = - direction
|
||||
# the nearst vdd ring
|
||||
vdd_ring = self.new_pins["vdd"][2] # order in list -> "top", "bottom", "right", "left"]
|
||||
# right ring's y position at it's left
|
||||
target_egde_x = vdd_ring.center().x - 0.5 * vdd_ring.width()
|
||||
if tmp_center == source_center: # no overlap
|
||||
# no jog, direct return the source/target center position
|
||||
# the target center position, should consider enought space for via
|
||||
target_point = vector((target_egde_x + 0.5 * self.track_wire), tmp_center.y)
|
||||
source_point = vector(tmp_center.x, tmp_center.y)
|
||||
point_list = [source_point, target_point]
|
||||
self.add_wire(point_list, vertical=False)
|
||||
# store the shape of moat pins, need for route later
|
||||
ll = vector(source_point.x - 0.5 * self.track_wire, source_point.y - 0.5 * self.track_wire)
|
||||
ur = vector(source_point.x + 0.5 * self.track_wire, source_point.y + 0.5 * self.track_wire)
|
||||
rect = [ll, ur]
|
||||
moat_pin_route = graph_shape("vdd", rect, "m3")
|
||||
self.moat_pins_right.append(moat_pin_route)
|
||||
else: # need jog
|
||||
# shift the center
|
||||
# add rectangle at same layer (original)
|
||||
intermediate_point = vector(tmp_center.x, tmp_center.y)
|
||||
source_point = vector(source_center.x, source_center.y)
|
||||
target_point = vector((target_egde_x + 0.5 * self.track_wire) ,tmp_center.y)
|
||||
point_list = [source_point, intermediate_point, target_point]
|
||||
self.add_wire(point_list, vertical=False)
|
||||
# store the shape of moat pins, need for route later
|
||||
ll = vector(intermediate_point.x - 0.5 * self.track_wire, intermediate_point.y - 0.5 * self.track_wire)
|
||||
ur = vector(intermediate_point.x + 0.5 * self.track_wire, intermediate_point.y + 0.5 * self.track_wire)
|
||||
rect = [ll, ur]
|
||||
moat_pin_route = graph_shape("vdd", rect, "m3")
|
||||
self.moat_pins_right.append(moat_pin_route)
|
||||
|
||||
|
||||
def add_wire(self, point_list, vertical=False):
|
||||
if vertical == True: # m4 line, need start via3(m3 -> m4), end via3(m3 -> m4)
|
||||
if len(point_list) == 2: # direct connect
|
||||
# start via
|
||||
self.add_via(point=point_list[0],
|
||||
from_layer="m3",
|
||||
to_layer="m4")
|
||||
self.add_via(point=point_list[0],
|
||||
from_layer="m4",
|
||||
to_layer="m4") # shape
|
||||
# connection
|
||||
self.add_line(point_1=point_list[0],
|
||||
point_2=point_list[1],
|
||||
layer="m4")
|
||||
# end via
|
||||
self.add_via(point=point_list[1],
|
||||
from_layer="m3",
|
||||
to_layer="m4")
|
||||
self.add_via(point=point_list[1],
|
||||
from_layer="m4",
|
||||
to_layer="m4") # shape
|
||||
elif len(point_list) == 3: # need intermediate point
|
||||
# jog
|
||||
self.add_line(point_1=point_list[0],
|
||||
point_2=point_list[1],
|
||||
layer="m3")
|
||||
# start_via
|
||||
self.add_via(point=point_list[1],
|
||||
from_layer="m3",
|
||||
to_layer="m4")
|
||||
self.add_via(point=point_list[1],
|
||||
from_layer="m3",
|
||||
to_layer="m3") # shape
|
||||
# connection
|
||||
self.add_line(point_1=point_list[1],
|
||||
point_2=point_list[2],
|
||||
layer="m4")
|
||||
# end via
|
||||
self.add_via(point=point_list[2],
|
||||
from_layer="m3",
|
||||
to_layer="m4")
|
||||
self.add_via(point=point_list[2],
|
||||
from_layer="m4",
|
||||
to_layer="m4") # shape
|
||||
else: # m3 line, need start via2(m2 -> m3), end via3(m3 -> m4)
|
||||
if len(point_list) == 2: # direct connect
|
||||
# start via
|
||||
self.add_via(point=point_list[0],
|
||||
from_layer="m2",
|
||||
to_layer="m3")
|
||||
self.add_via(point=point_list[0],
|
||||
from_layer="m3",
|
||||
to_layer="m3") # shape
|
||||
# connection
|
||||
self.add_line(point_1=point_list[0],
|
||||
point_2=point_list[1],
|
||||
layer="m3")
|
||||
# end via
|
||||
self.add_via(point=point_list[1],
|
||||
from_layer="m3",
|
||||
to_layer="m4")
|
||||
self.add_via(point=point_list[1],
|
||||
from_layer="m3",
|
||||
to_layer="m3") # shape
|
||||
elif len(point_list) == 3: # need intermediate point
|
||||
# jog
|
||||
self.add_line(point_1=point_list[0],
|
||||
point_2=point_list[1],
|
||||
layer="m2")
|
||||
# start_via
|
||||
self.add_via(point=point_list[1],
|
||||
from_layer="m2",
|
||||
to_layer="m3")
|
||||
self.add_via(point=point_list[1],
|
||||
from_layer="m3",
|
||||
to_layer="m3") # shape
|
||||
# connection
|
||||
self.add_line(point_1=point_list[1],
|
||||
point_2=point_list[2],
|
||||
layer="m3")
|
||||
# end via
|
||||
self.add_via(point=point_list[2],
|
||||
from_layer="m3",
|
||||
to_layer="m4")
|
||||
self.add_via(point=point_list[2],
|
||||
from_layer="m3",
|
||||
to_layer="m3") # shape
|
||||
|
||||
|
||||
def add_line(self, point_1, point_2, layer="m3"): # "m2", "m3", "m4"
|
||||
self.design.add_path(layer, [point_1, point_2], self.track_wire)
|
||||
|
||||
|
||||
def add_via(self, point, from_layer="m3", to_layer="m4"):
|
||||
# via could be via2(m2 -> m3), via3(m3 -> m4)
|
||||
# or a shape at same layer
|
||||
if from_layer == to_layer:
|
||||
self.design.add_rect_center(layer=from_layer,
|
||||
offset=point,
|
||||
width=self.track_wire,
|
||||
height=self.track_wire)
|
||||
else:
|
||||
self.design.add_via_stack_center(from_layer=from_layer,
|
||||
to_layer=to_layer,
|
||||
offset=point)
|
||||
|
||||
|
||||
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]
|
||||
io_pin = next(iter(self.pins[pin_name]))
|
||||
self.find_closest_edge(io_pin)
|
||||
|
||||
|
||||
|
|
@ -139,6 +612,7 @@ class supply_placer(router):
|
|||
|
||||
ll, ur = self.bbox
|
||||
point = pin.center()
|
||||
debug.warning("moat pin center -> {0}".format(point))
|
||||
# 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)
|
||||
|
|
@ -159,6 +633,7 @@ class supply_placer(router):
|
|||
""" Use to find the edge, where the io pin locats """
|
||||
|
||||
ll, ur = self.bbox
|
||||
#debug.warning("pin -> {0}".format(pin))
|
||||
point = pin.center()
|
||||
# Snap the pin to the perimeter and break the iteration
|
||||
ll_diff_x = abs(point.x - ll.x)
|
||||
|
|
@ -182,7 +657,7 @@ class supply_placer(router):
|
|||
|
||||
ll, ur = self.bbox
|
||||
vertical = side in ["left", "right"]
|
||||
inner = pin_name == self.ext_vdd_name
|
||||
inner = pin_name == "vdd"
|
||||
|
||||
# Calculate wires' wideness
|
||||
wideness = self.track_wire * num_vias + self.track_space * (num_vias - 1)
|
||||
|
|
@ -225,29 +700,7 @@ class supply_placer(router):
|
|||
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
|
||||
return pin
|
||||
|
||||
|
||||
def add_ring_pin(self, pin_name, num_vias=3, num_fake_pins=4):
|
||||
|
|
@ -256,7 +709,7 @@ class supply_placer(router):
|
|||
# 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)
|
||||
new_shape = 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"])
|
||||
|
|
@ -264,8 +717,6 @@ class supply_placer(router):
|
|||
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
|
||||
|
|
@ -338,6 +789,56 @@ class supply_placer(router):
|
|||
return mst_pairs
|
||||
|
||||
|
||||
def get_mst_with_ring(self, pins, ring_pins, pin_name="vdd"):
|
||||
"""
|
||||
Extend the MST logic to connect internal pins to the nearest external ring pins.
|
||||
"""
|
||||
# Prepare the pins that are allowed to connect to the moat pins.
|
||||
# Specical handle gnd ring
|
||||
candidate_pins = []
|
||||
max_distance = 13
|
||||
if pin_name == "gnd":
|
||||
ring_pins = []
|
||||
ring_pins = self.new_pins[pin_name]
|
||||
for pin in pins:
|
||||
for ring_pin in ring_pins:
|
||||
dist = pin.distance(ring_pin)
|
||||
if max_distance is None or dist <= max_distance:
|
||||
candidate_pins.append(pin)
|
||||
break
|
||||
|
||||
# Compute the MST for internal pins
|
||||
mst_pairs = self.get_mst_pairs(pins)
|
||||
|
||||
# Connect each internal pin to the nearest external ring pin
|
||||
used_ring_pins = set()
|
||||
internal_to_ring_pairs = []
|
||||
for pin in candidate_pins:
|
||||
min_distance = float("inf")
|
||||
nearest_ring_pin = None
|
||||
|
||||
for ring_pin in ring_pins:
|
||||
if pin_name == "vdd" and ring_pin in used_ring_pins:
|
||||
continue
|
||||
|
||||
dist = pin.distance(ring_pin)
|
||||
if dist < min_distance:
|
||||
min_distance = dist
|
||||
nearest_ring_pin = ring_pin
|
||||
|
||||
# Add the connection to the nearest ring pin
|
||||
if nearest_ring_pin:
|
||||
internal_to_ring_pairs.append((pin, nearest_ring_pin))
|
||||
# Mark the ring pin as used if the pin is VDD
|
||||
if pin_name == "vdd":
|
||||
used_ring_pins.add(nearest_ring_pin)
|
||||
|
||||
# Combine internal MST pairs and external connections
|
||||
full_connections = mst_pairs + internal_to_ring_pairs
|
||||
|
||||
return full_connections
|
||||
|
||||
|
||||
def get_new_pins(self, name):
|
||||
""" Return the new supply pins added by this router. """
|
||||
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ class sram():
|
|||
spname = OPTS.output_path + self.s.name + ".sp"
|
||||
debug.print_raw("SP: Writing to {0}".format(spname))
|
||||
self.sp_write(spname)
|
||||
#''' #comment the following state when generating big sram, and then disable drc/lvs, because maigc_ext stuck
|
||||
''' #comment the following state when generating big sram, and then disable drc/lvs, because maigc_ext stuck
|
||||
# Save a functional simulation file with default period
|
||||
functional(self.s,
|
||||
spname,
|
||||
|
|
@ -191,7 +191,7 @@ class sram():
|
|||
d.targ_write_ports = [self.s.write_ports[0]]
|
||||
d.write_delay_stimulus()
|
||||
print_time("DELAY", datetime.datetime.now(), start_time)
|
||||
#''' #comment the above when generating big sram, and then disable drc/lvs, bevause magic_ext stuck
|
||||
''' #comment the above when generating big sram, and then disable drc/lvs, bevause magic_ext stuck
|
||||
# Save trimmed spice file
|
||||
temp_trim_sp = "{0}trimmed.sp".format(OPTS.output_path)
|
||||
self.sp_write(temp_trim_sp, lvs=False, trim=True)
|
||||
|
|
|
|||
Loading…
Reference in New Issue