mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'supply_router' into dev
This commit is contained in:
commit
3048c61c20
|
|
@ -1220,49 +1220,89 @@ class layout():
|
|||
pin.height())
|
||||
|
||||
elif add_vias:
|
||||
self.add_power_pin(name, pin.center(), start_layer=pin.layer)
|
||||
self.copy_power_pin(pin)
|
||||
|
||||
def add_io_pin(self, instance, pin_name, new_name="", start_layer=None):
|
||||
def add_io_pin(self, instance, pin_name, new_name, start_layer=None):
|
||||
"""
|
||||
Add a signle input or output pin up to metal 3.
|
||||
"""
|
||||
pin = instance.get_pin(pin_name)
|
||||
|
||||
if new_name == "":
|
||||
new_name = pin_name
|
||||
|
||||
if not start_layer:
|
||||
start_layer = pin.layer
|
||||
|
||||
# Just use the power pin function for now to save code
|
||||
self.add_power_pin(name=new_name, loc=pin.center(), start_layer=start_layer)
|
||||
|
||||
def add_power_pin(self, name, loc, size=[1, 1], directions=None, start_layer="m1"):
|
||||
# Just use the power pin function for now to save code
|
||||
self.add_power_pin(new_name, pin.center(), start_layer=start_layer)
|
||||
|
||||
def add_power_pin(self, name, loc, directions=None, start_layer="m1"):
|
||||
|
||||
# Hack for min area
|
||||
if OPTS.tech_name == "sky130":
|
||||
min_area = drc["minarea_{}".format(self.pwr_grid_layer)]
|
||||
width = round_to_grid(sqrt(min_area))
|
||||
height = round_to_grid(min_area / width)
|
||||
else:
|
||||
width = None
|
||||
height = None
|
||||
|
||||
if start_layer == self.pwr_grid_layer:
|
||||
self.add_layout_pin_rect_center(text=name,
|
||||
layer=self.pwr_grid_layer,
|
||||
offset=loc,
|
||||
width=width,
|
||||
height=height)
|
||||
else:
|
||||
via = self.add_via_stack_center(from_layer=start_layer,
|
||||
to_layer=self.pwr_grid_layer,
|
||||
offset=loc,
|
||||
directions=directions)
|
||||
|
||||
if not width:
|
||||
width = via.width
|
||||
if not height:
|
||||
height = via.height
|
||||
self.add_layout_pin_rect_center(text=name,
|
||||
layer=self.pwr_grid_layer,
|
||||
offset=loc,
|
||||
width=width,
|
||||
height=height)
|
||||
|
||||
def copy_power_pin(self, pin, loc=None, directions=None):
|
||||
"""
|
||||
Add a single power pin from the lowest power_grid layer down to M1 (or li) at
|
||||
the given center location. The starting layer is specified to determine
|
||||
which vias are needed.
|
||||
"""
|
||||
|
||||
if start_layer == self.pwr_grid_layer:
|
||||
self.add_layout_pin_rect_center(text=name,
|
||||
layer=self.pwr_grid_layer,
|
||||
offset=loc)
|
||||
if not loc:
|
||||
loc = pin.center()
|
||||
|
||||
# Hack for min area
|
||||
if OPTS.tech_name == "sky130":
|
||||
min_area = drc["minarea_{}".format(self.pwr_grid_layer)]
|
||||
width = round_to_grid(sqrt(min_area))
|
||||
height = round_to_grid(min_area / width)
|
||||
else:
|
||||
via = self.add_via_stack_center(from_layer=start_layer,
|
||||
width = None
|
||||
height = None
|
||||
|
||||
if pin.layer == self.pwr_grid_layer:
|
||||
self.add_layout_pin_rect_center(text=pin.name,
|
||||
layer=self.pwr_grid_layer,
|
||||
offset=loc,
|
||||
width=width,
|
||||
height=height)
|
||||
else:
|
||||
via = self.add_via_stack_center(from_layer=pin.layer,
|
||||
to_layer=self.pwr_grid_layer,
|
||||
size=size,
|
||||
offset=loc,
|
||||
directions=directions)
|
||||
|
||||
# Hack for min area
|
||||
if OPTS.tech_name == "sky130":
|
||||
width = round_to_grid(sqrt(drc["minarea_m3"]))
|
||||
height = round_to_grid(drc["minarea_m3"] / width)
|
||||
else:
|
||||
if not width:
|
||||
width = via.width
|
||||
if not height:
|
||||
height = via.height
|
||||
self.add_layout_pin_rect_center(text=name,
|
||||
self.add_layout_pin_rect_center(text=pin.name,
|
||||
layer=self.pwr_grid_layer,
|
||||
offset=loc,
|
||||
width=width,
|
||||
|
|
|
|||
|
|
@ -615,9 +615,7 @@ class bank(design.design):
|
|||
for pin_name in ["vdd", "gnd"]:
|
||||
pin_list = inst.get_pins(pin_name)
|
||||
for pin in pin_list:
|
||||
self.add_power_pin(pin_name,
|
||||
pin.center(),
|
||||
start_layer=pin.layer)
|
||||
self.copy_power_pin(pin, pin.center())
|
||||
|
||||
def route_bank_select(self, port):
|
||||
""" Route the bank select logic. """
|
||||
|
|
|
|||
|
|
@ -100,7 +100,5 @@ class col_cap_array(bitcell_base_array):
|
|||
inst = self.cell_inst[row, col]
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
for pin in inst.get_pins(pin_name):
|
||||
self.add_power_pin(name=pin_name,
|
||||
loc=pin.center(),
|
||||
start_layer=pin.layer)
|
||||
self.copy_power_pin(pin)
|
||||
|
||||
|
|
|
|||
|
|
@ -177,14 +177,10 @@ class delay_chain(design.design):
|
|||
load_list = self.load_inst_map[inst]
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
pin = load_list[0].get_pin(pin_name)
|
||||
self.add_power_pin(pin_name,
|
||||
pin.rc() - vector(self.m1_pitch, 0),
|
||||
start_layer=pin.layer)
|
||||
self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0))
|
||||
|
||||
pin = load_list[-2].get_pin(pin_name)
|
||||
self.add_power_pin(pin_name,
|
||||
pin.rc() - vector(self.m1_pitch, 0),
|
||||
start_layer=pin.layer)
|
||||
self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0))
|
||||
|
||||
def add_layout_pins(self):
|
||||
|
||||
|
|
|
|||
|
|
@ -112,11 +112,11 @@ class dff_array(design.design):
|
|||
for col in range(self.columns):
|
||||
# Continous vdd rail along with label.
|
||||
vdd_pin=self.dff_insts[row, col].get_pin("vdd")
|
||||
self.add_power_pin("vdd", vdd_pin.center(), start_layer=vdd_pin.layer)
|
||||
self.copy_power_pin(vdd_pin)
|
||||
|
||||
# Continous gnd rail along with label.
|
||||
gnd_pin=self.dff_insts[row, col].get_pin("gnd")
|
||||
self.add_power_pin("gnd", gnd_pin.center(), start_layer=gnd_pin.layer)
|
||||
self.copy_power_pin(gnd_pin)
|
||||
|
||||
for row in range(self.rows):
|
||||
for col in range(self.columns):
|
||||
|
|
|
|||
|
|
@ -159,11 +159,11 @@ class dff_buf_array(design.design):
|
|||
for col in range(self.columns):
|
||||
# Continous vdd rail along with label.
|
||||
vdd_pin=self.dff_insts[row, col].get_pin("vdd")
|
||||
self.add_power_pin("vdd", vdd_pin.lc(), start_layer=vdd_pin.layer)
|
||||
self.copy_power_pin(vdd_pin, loc=vdd_pin.lc())
|
||||
|
||||
# Continous gnd rail along with label.
|
||||
gnd_pin=self.dff_insts[row, col].get_pin("gnd")
|
||||
self.add_power_pin("gnd", gnd_pin.lc(), start_layer=gnd_pin.layer)
|
||||
self.copy_power_pin(gnd_pin, loc=gnd_pin.lc())
|
||||
|
||||
def add_layout_pins(self):
|
||||
|
||||
|
|
|
|||
|
|
@ -7,11 +7,10 @@
|
|||
#
|
||||
import debug
|
||||
import design
|
||||
from tech import drc
|
||||
from math import log
|
||||
from vector import vector
|
||||
from globals import OPTS
|
||||
import dff_inv
|
||||
from sram_factory import factory
|
||||
|
||||
|
||||
class dff_inv_array(design.design):
|
||||
"""
|
||||
|
|
@ -130,12 +129,11 @@ class dff_inv_array(design.design):
|
|||
for col in range(self.columns):
|
||||
# Adds power pin on left of row
|
||||
vdd_pin=self.dff_insts[row,col].get_pin("vdd")
|
||||
self.add_power_pin("vdd", vdd_pin.lc())
|
||||
self.add_power_pin(vdd_pin, loc=vdd_pin.lc())
|
||||
|
||||
# Adds gnd pin on left of row
|
||||
gnd_pin=self.dff_insts[row,col].get_pin("gnd")
|
||||
self.add_power_pin("gnd", gnd_pin.lc())
|
||||
|
||||
self.add_power_pin(gnd_pin, loc=gnd_pin.lc())
|
||||
|
||||
for row in range(self.rows):
|
||||
for col in range(self.columns):
|
||||
|
|
|
|||
|
|
@ -611,12 +611,7 @@ class hierarchical_decoder(design.design):
|
|||
for i in self.and_inst[:-1]:
|
||||
pins = i.get_pins(n)
|
||||
for pin in pins:
|
||||
self.add_power_pin(name=n,
|
||||
loc=pin.uc(),
|
||||
start_layer=pin.layer)
|
||||
self.add_power_pin(name=n,
|
||||
loc=pin.uc(),
|
||||
start_layer=pin.layer)
|
||||
self.copy_power_pin(pin, loc=pin.uc())
|
||||
|
||||
for i in self.pre2x4_inst + self.pre3x8_inst:
|
||||
self.copy_layout_pin(i, n)
|
||||
|
|
@ -628,9 +623,7 @@ class hierarchical_decoder(design.design):
|
|||
# The nand and inv are the same height rows...
|
||||
supply_pin = self.and_inst[row].get_pin(pin_name)
|
||||
pin_pos = vector(xoffset, supply_pin.cy())
|
||||
self.add_power_pin(name=pin_name,
|
||||
loc=pin_pos,
|
||||
start_layer=supply_pin.layer)
|
||||
self.copy_power_pin(supply_pin, loc=pin_pos)
|
||||
|
||||
# Copy the pins from the predecoders
|
||||
for pre in self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst:
|
||||
|
|
|
|||
|
|
@ -330,12 +330,7 @@ class hierarchical_predecode(design.design):
|
|||
for i in self.inv_inst[:-1:2] + self.and_inst[:-1:2]:
|
||||
pins = i.get_pins(n)
|
||||
for pin in pins:
|
||||
self.add_power_pin(name=n,
|
||||
loc=pin.uc(),
|
||||
start_layer=pin.layer)
|
||||
self.add_power_pin(name=n,
|
||||
loc=pin.uc(),
|
||||
start_layer=pin.layer)
|
||||
self.copy_power_pin(pin, loc=pin.uc())
|
||||
|
||||
# In other techs, we are using standard cell decoder cells with horizontal power
|
||||
else:
|
||||
|
|
@ -353,9 +348,7 @@ class hierarchical_predecode(design.design):
|
|||
for xoffset in [self.inv_inst[0].lx() - self.bus_space,
|
||||
self.and_inst[0].lx() - self.bus_space]:
|
||||
pin_pos = vector(xoffset, and_pin.cy())
|
||||
self.add_power_pin(name=n,
|
||||
loc=pin_pos,
|
||||
start_layer=and_pin.layer)
|
||||
self.copy_power_pin(and_pin, loc=pin_pos)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -186,9 +186,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
|
|||
for inst in supply_insts:
|
||||
pin_list = inst.get_pins(pin_name)
|
||||
for pin in pin_list:
|
||||
self.add_power_pin(name=pin_name,
|
||||
loc=pin.center(),
|
||||
start_layer=pin.layer)
|
||||
self.copy_power_pin(pin)
|
||||
|
||||
def route(self):
|
||||
|
||||
|
|
|
|||
|
|
@ -82,9 +82,9 @@ class port_address(design.design):
|
|||
|
||||
for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"):
|
||||
if layer_props.port_address.supply_offset:
|
||||
self.add_power_pin("vdd", rbl_vdd_pin.center())
|
||||
self.copy_power_pin(rbl_vdd_pin)
|
||||
else:
|
||||
self.add_power_pin("vdd", rbl_vdd_pin.lc())
|
||||
self.copy_power_pin(rbl_vdd_pin, loc=rbl_vdd_pin.lc())
|
||||
|
||||
# Also connect the B input of the RBL and_dec to vdd
|
||||
if OPTS.local_array_size == 0:
|
||||
|
|
|
|||
|
|
@ -473,9 +473,7 @@ class replica_bitcell_array(bitcell_base_array):
|
|||
for inst in supply_insts:
|
||||
pin_list = inst.get_pins(pin_name)
|
||||
for pin in pin_list:
|
||||
self.add_power_pin(name=pin_name,
|
||||
loc=pin.center(),
|
||||
start_layer=pin.layer)
|
||||
self.copy_power_pin(pin)
|
||||
|
||||
for inst in self.replica_col_insts:
|
||||
if inst:
|
||||
|
|
|
|||
|
|
@ -190,7 +190,8 @@ class replica_column(bitcell_base_array):
|
|||
for (index, inst) in enumerate(self.cell_inst):
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
if inst in [self.cell_inst[0], self.cell_inst[self.total_size - 1]]:
|
||||
self.copy_power_pins(inst, pin_name)
|
||||
for pin in inst.get_pins(pin_name):
|
||||
self.copy_power_pin(pin)
|
||||
else:
|
||||
self.copy_layout_pin(inst, pin_name)
|
||||
|
||||
|
|
|
|||
|
|
@ -113,7 +113,5 @@ class row_cap_array(bitcell_base_array):
|
|||
inst = self.cell_inst[row, col]
|
||||
for pin_name in ["vdd", "gnd"]:
|
||||
for pin in inst.get_pins(pin_name):
|
||||
self.add_power_pin(name=pin_name,
|
||||
loc=pin.center(),
|
||||
start_layer=pin.layer)
|
||||
self.copy_power_pin(pin)
|
||||
|
||||
|
|
|
|||
|
|
@ -146,16 +146,10 @@ class sense_amp_array(design.design):
|
|||
inst = self.local_insts[i]
|
||||
|
||||
for gnd_pin in inst.get_pins("gnd"):
|
||||
self.add_power_pin(name="gnd",
|
||||
loc=gnd_pin.center(),
|
||||
start_layer=gnd_pin.layer,
|
||||
directions=("V", "V"))
|
||||
self.copy_power_pin(gnd_pin, directions=("V", "V"))
|
||||
|
||||
for vdd_pin in inst.get_pins("vdd"):
|
||||
self.add_power_pin(name="vdd",
|
||||
loc=vdd_pin.center(),
|
||||
start_layer=vdd_pin.layer,
|
||||
directions=("V", "V"))
|
||||
self.copy_power_pin(vdd_pin, directions=("V", "V"))
|
||||
|
||||
bl_pin = inst.get_pin(inst.mod.get_bl_names())
|
||||
br_pin = inst.get_pin(inst.mod.get_br_names())
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ class wordline_buffer_array(design.design):
|
|||
# Add pins in two locations
|
||||
for xoffset in xoffset_list:
|
||||
pin_pos = vector(xoffset, supply_pin.cy())
|
||||
self.add_power_pin(name, pin_pos)
|
||||
self.copy_power_pin(supply_pin, loc=pin_pos)
|
||||
|
||||
def create_drivers(self):
|
||||
self.wld_inst = []
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ class wordline_driver_array(design.design):
|
|||
# Add pins in two locations
|
||||
for xoffset in xoffset_list:
|
||||
pin_pos = vector(xoffset, supply_pin.cy())
|
||||
self.add_power_pin(name, pin_pos)
|
||||
self.copy_power_pin(supply_pin, loc=pin_pos)
|
||||
|
||||
def create_drivers(self):
|
||||
self.wld_inst = []
|
||||
|
|
|
|||
|
|
@ -208,10 +208,8 @@ class write_driver_array(design.design):
|
|||
for n in ["vdd", "gnd"]:
|
||||
pin_list = self.driver_insts[i].get_pins(n)
|
||||
for pin in pin_list:
|
||||
self.add_power_pin(name=n,
|
||||
loc=pin.center(),
|
||||
directions=("V", "V"),
|
||||
start_layer=pin.layer)
|
||||
self.copy_power_pin(pin, directions=("V", "V"))
|
||||
|
||||
if self.write_size:
|
||||
for bit in range(self.num_wmasks):
|
||||
inst = self.driver_insts[bit * self.write_size]
|
||||
|
|
|
|||
|
|
@ -145,6 +145,6 @@ class write_mask_and_array(design.design):
|
|||
left_loc = vector(0, supply_pin_yoffset)
|
||||
right_loc = vector(self.width, supply_pin_yoffset)
|
||||
self.add_path(supply_pin.layer, [left_loc, right_loc])
|
||||
self.add_power_pin(supply, left_loc, start_layer=supply_pin.layer)
|
||||
self.add_power_pin(supply, right_loc, start_layer=supply_pin.layer)
|
||||
self.copy_power_pin(supply_pin, loc=left_loc)
|
||||
self.copy_power_pin(supply_pin, loc=right_loc)
|
||||
|
||||
|
|
|
|||
|
|
@ -131,7 +131,10 @@ class pinv_dec(pinv.pinv):
|
|||
self.nmos_inst.place(self.nmos_pos,
|
||||
rotate=270)
|
||||
# place PMOS so it is half a poly spacing down from the top
|
||||
xoffset = self.nmos_inst.rx() + 2 * self.poly_extend_active + 2 * self.well_extend_active + drc("pwell_to_nwell")
|
||||
well_offsets = 2 * self.poly_extend_active + 2 * self.well_extend_active + drc("pwell_to_nwell")
|
||||
# This is to provide spacing for the vdd rails
|
||||
metal_offsets = 2 * self.m3_pitch
|
||||
xoffset = self.nmos_inst.rx() + max(well_offsets, metal_offsets)
|
||||
self.pmos_pos = vector(xoffset, y_offset)
|
||||
self.pmos_inst.place(self.pmos_pos,
|
||||
rotate=270)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class grid:
|
|||
# The bounds are in grids for this
|
||||
# This is really lower left bottom layer and upper right top layer in 3D.
|
||||
self.ll = vector3d(ll.x, ll.y, 0).scale(self.track_factor).round()
|
||||
self.ur = vector3d(ur.x, ur.y, 1).scale(self.track_factor).round()
|
||||
self.ur = vector3d(ur.x, ur.y, 0).scale(self.track_factor).round()
|
||||
|
||||
# let's leave the map sparse, cells are created on demand to reduce memory
|
||||
self.map={}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
from direction import direction
|
||||
from pin_layout import pin_layout
|
||||
from vector import vector
|
||||
from vector3d import vector3d
|
||||
import debug
|
||||
|
||||
|
||||
|
|
@ -41,10 +42,7 @@ class pin_group:
|
|||
# or could not be part of the pin
|
||||
self.secondary_grids = set()
|
||||
|
||||
# The corresponding set of partially blocked grids for each pin group.
|
||||
# These are blockages for other nets but unblocked
|
||||
# for routing this group. These are also blockages if we
|
||||
# used a simple enclosure to route to a rail.
|
||||
# The set of blocked grids due to this pin
|
||||
self.blockages = set()
|
||||
|
||||
# This is a set of pin_layout shapes to cover the grids
|
||||
|
|
@ -421,16 +419,16 @@ class pin_group:
|
|||
while True:
|
||||
next_cell = row[-1] + offset1
|
||||
# Can't move if not in the pin shape
|
||||
if next_cell in self.grids and next_cell not in self.router.blocked_grids:
|
||||
if next_cell in self.grids and next_cell not in self.router.get_blocked_grids():
|
||||
row.append(next_cell)
|
||||
else:
|
||||
break
|
||||
# Move in dir2 while we can
|
||||
while True:
|
||||
next_row = [x+offset2 for x in row]
|
||||
next_row = [x + offset2 for x in row]
|
||||
for cell in next_row:
|
||||
# Can't move if any cell is not in the pin shape
|
||||
if cell not in self.grids or cell in self.router.blocked_grids:
|
||||
if cell not in self.grids or cell in self.router.get_blocked_grids():
|
||||
break
|
||||
else:
|
||||
row = next_row
|
||||
|
|
@ -606,9 +604,10 @@ class pin_group:
|
|||
The secondary set of grids are "optional" pin shapes that
|
||||
should be either blocked or part of the pin.
|
||||
"""
|
||||
# Set of tracks that overlap a pin
|
||||
pin_set = set()
|
||||
# Set of track adjacent to or paritally overlap a pin (not full DRC connection)
|
||||
partial_set = set()
|
||||
blockage_set = set()
|
||||
|
||||
for pin in self.pins:
|
||||
debug.info(4, " Converting {0}".format(pin))
|
||||
|
|
@ -621,25 +620,18 @@ class pin_group:
|
|||
# Blockages will be a super-set of pins since
|
||||
# it uses the inflated pin shape.
|
||||
blockage_in_tracks = self.router.convert_blockage(pin)
|
||||
blockage_set.update(blockage_in_tracks)
|
||||
|
||||
# Must include the pins here too because these are computed in a different
|
||||
# way than blockages.
|
||||
self.blockages.update(sufficient | insufficient | blockage_in_tracks)
|
||||
|
||||
# If we have a blockage, we must remove the grids
|
||||
# Remember, this excludes the pin blockages already
|
||||
shared_set = pin_set & self.router.blocked_grids
|
||||
if len(shared_set) > 0:
|
||||
debug.info(4, "Removing pins {}".format(shared_set))
|
||||
pin_set.difference_update(shared_set)
|
||||
shared_set = partial_set & self.router.blocked_grids
|
||||
if len(shared_set) > 0:
|
||||
debug.info(4, "Removing pins {}".format(shared_set))
|
||||
partial_set.difference_update(shared_set)
|
||||
shared_set = blockage_set & self.router.blocked_grids
|
||||
if len(shared_set) > 0:
|
||||
debug.info(4, "Removing blocks {}".format(shared_set))
|
||||
blockage_set.difference_update(shared_set)
|
||||
|
||||
blocked_grids = self.router.get_blocked_grids()
|
||||
pin_set.difference_update(blocked_grids)
|
||||
partial_set.difference_update(blocked_grids)
|
||||
|
||||
# At least one of the groups must have some valid tracks
|
||||
if (len(pin_set) == 0 and len(partial_set) == 0 and len(blockage_set) == 0):
|
||||
if (len(pin_set) == 0 and len(partial_set) == 0):
|
||||
# debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins))
|
||||
|
||||
for pin in self.pins:
|
||||
|
|
@ -648,15 +640,25 @@ class pin_group:
|
|||
(sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
|
||||
pin,
|
||||
expansion=1)
|
||||
|
||||
# This time, don't remove blockages in the hopes that it might be ok.
|
||||
# Could cause DRC problems!
|
||||
pin_set.update(sufficient)
|
||||
partial_set.update(insufficient)
|
||||
|
||||
# If it's still empty, we must bail.
|
||||
if len(pin_set) == 0 and len(partial_set) == 0:
|
||||
debug.error("Unable to find unblocked pin {} {}".format(self.name,
|
||||
self.pins))
|
||||
self.router.write_debug_gds("blocked_pin.gds")
|
||||
|
||||
# Consider all the grids that would be blocked
|
||||
# Consider the fully connected set first and if not the partial set
|
||||
# if len(pin_set) > 0:
|
||||
# self.grids = pin_set
|
||||
# else:
|
||||
# self.grids = partial_set
|
||||
# Just using the full set simplifies the enclosures, otherwise
|
||||
# we get some pin enclose DRC errors due to off grid pins
|
||||
self.grids = pin_set | partial_set
|
||||
if len(self.grids) < 0:
|
||||
debug.error("Did not find any unblocked grids: {}".format(str(self.pins)))
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class router(router_tech):
|
|||
route on a given layer. This is limited to two layer routes.
|
||||
It populates blockages on a grid class.
|
||||
"""
|
||||
def __init__(self, layers, design, gds_filename=None, route_track_width=1):
|
||||
def __init__(self, layers, design, gds_filename=None, bbox=None, route_track_width=1):
|
||||
"""
|
||||
This will instantiate a copy of the gds file or the module at (0,0) and
|
||||
route on top of this. The blockages from the gds/module will be
|
||||
|
|
@ -69,9 +69,12 @@ class router(router_tech):
|
|||
|
||||
# The blockage data structures
|
||||
# A list of metal shapes (using the same pin_layout structure)
|
||||
# that are not pins but blockages.
|
||||
# that could be blockages.
|
||||
# This will include the pins above as well.
|
||||
self.blockages = []
|
||||
# The corresponding set of blocked grids for above pin shapes
|
||||
# The corresponding set of blocked grids for above blockage pin_layout shapes
|
||||
# It is a cached set of grids that *could* be blocked, but may be unblocked
|
||||
# depending on which pin we are routing.
|
||||
self.blocked_grids = set()
|
||||
|
||||
# The routed data structures
|
||||
|
|
@ -80,12 +83,35 @@ class router(router_tech):
|
|||
# A list of path blockages (they might be expanded for wide metal DRC)
|
||||
self.path_blockages = []
|
||||
|
||||
# The boundary will determine the limits to the size
|
||||
# of the routing grid
|
||||
self.boundary = self.layout.measureBoundary(self.top_name)
|
||||
# These must be un-indexed to get rid of the matrix type
|
||||
self.ll = vector(self.boundary[0][0], self.boundary[0][1])
|
||||
self.ur = vector(self.boundary[1][0], self.boundary[1][1])
|
||||
self.init_bbox(bbox)
|
||||
|
||||
def init_bbox(self, bbox=None):
|
||||
"""
|
||||
Initialize the ll,ur values with the paramter or using the layout boundary.
|
||||
"""
|
||||
if not bbox:
|
||||
# The boundary will determine the limits to the size
|
||||
# of the routing grid
|
||||
self.boundary = self.layout.measureBoundary(self.top_name)
|
||||
# These must be un-indexed to get rid of the matrix type
|
||||
self.ll = vector(self.boundary[0][0], self.boundary[0][1])
|
||||
self.ur = vector(self.boundary[1][0], self.boundary[1][1])
|
||||
else:
|
||||
self.ll, self.ur = bbox
|
||||
|
||||
self.bbox = (self.ll, self.ur)
|
||||
size = self.ur - self.ll
|
||||
debug.info(1, "Size: {0} x {1}".format(size.x, size.y))
|
||||
|
||||
def get_bbox(self):
|
||||
return self.bbox
|
||||
|
||||
def create_routing_grid(self, router_type, bbox=None):
|
||||
"""
|
||||
Create a sprase routing grid with A* expansion functions.
|
||||
"""
|
||||
self.init_bbox(bbox)
|
||||
self.rg = router_type(self.ll, self.ur, self.track_width)
|
||||
|
||||
def clear_pins(self):
|
||||
"""
|
||||
|
|
@ -345,16 +371,17 @@ class router(router_tech):
|
|||
# This is just a virtual function
|
||||
pass
|
||||
|
||||
def prepare_blockages(self, pin_name):
|
||||
def prepare_blockages(self):
|
||||
"""
|
||||
Reset and add all of the blockages in the design.
|
||||
Names is a list of pins to add as a blockage.
|
||||
"""
|
||||
debug.info(3, "Preparing blockages.")
|
||||
|
||||
# Start fresh. Not the best for run-time, but simpler.
|
||||
self.clear_blockages()
|
||||
self.clear_all_blockages()
|
||||
|
||||
# This adds the initial blockges of the design
|
||||
# which includes all blockages due to non-pin shapes
|
||||
# print("BLOCKING:", self.blocked_grids)
|
||||
self.set_blockages(self.blocked_grids, True)
|
||||
|
||||
|
|
@ -366,26 +393,18 @@ class router(router_tech):
|
|||
# If function doesn't exist, it isn't a supply router
|
||||
pass
|
||||
|
||||
# Block all of the pin components
|
||||
# (some will be unblocked if they're a source/target)
|
||||
# Also block the previous routes
|
||||
# Now go and block all of the blockages due to pin shapes.
|
||||
# Some of these will get unblocked later if they are the source/target.
|
||||
for name in self.pin_groups:
|
||||
blockage_grids = {y for x in self.pin_groups[name] for y in x.grids}
|
||||
self.set_blockages(blockage_grids, True)
|
||||
# This should be a superset of the grids...
|
||||
blockage_grids = {y for x in self.pin_groups[name] for y in x.blockages}
|
||||
self.set_blockages(blockage_grids, True)
|
||||
|
||||
# FIXME: These duplicate a bit of work
|
||||
# These are the paths that have already been routed.
|
||||
# If we have paths that were recently routed, add them as blockages as well.
|
||||
# We might later do rip-up and reroute so they might not be metal shapes in the design yet.
|
||||
# Also, this prevents having to reload an entire GDS and find the blockage shapes.
|
||||
self.set_blockages(self.path_blockages)
|
||||
|
||||
# Don't mark the other components as targets since we want to route
|
||||
# directly to a rail, but unblock all the source components so we can
|
||||
# route over them
|
||||
# 1/6/21: This would cause things that looked like loops in the supply tree router
|
||||
# blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
|
||||
# self.set_blockages(blockage_grids, False)
|
||||
|
||||
def convert_shape_to_units(self, shape):
|
||||
"""
|
||||
Scale a shape (two vector list) to user units
|
||||
|
|
@ -421,7 +440,14 @@ class router(router_tech):
|
|||
# z direction
|
||||
return 2
|
||||
|
||||
def clear_blockages(self):
|
||||
def clear_blockages(self, pin_name):
|
||||
"""
|
||||
This function clears a given pin and all of its components from being blockages.
|
||||
"""
|
||||
blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.blockages}
|
||||
self.set_blockages(blockage_grids, False)
|
||||
|
||||
def clear_all_blockages(self):
|
||||
"""
|
||||
Clear all blockages on the grid.
|
||||
"""
|
||||
|
|
@ -432,24 +458,24 @@ class router(router_tech):
|
|||
""" Flag the blockages in the grid """
|
||||
self.rg.set_blocked(blockages, value)
|
||||
|
||||
def get_blockage_tracks(self, ll, ur, z):
|
||||
debug.info(3, "Converting blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
|
||||
def convert_to_tracks(self, ll, ur, z):
|
||||
debug.info(3, "Converting ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
|
||||
|
||||
block_list = []
|
||||
grid_list = []
|
||||
for x in range(int(ll[0]), int(ur[0])+1):
|
||||
for y in range(int(ll[1]), int(ur[1])+1):
|
||||
block_list.append(vector3d(x, y, z))
|
||||
grid_list.append(vector3d(x, y, z))
|
||||
|
||||
return set(block_list)
|
||||
return set(grid_list)
|
||||
|
||||
def convert_blockage(self, blockage):
|
||||
"""
|
||||
Convert a pin layout blockage shape to routing grid tracks.
|
||||
"""
|
||||
# Inflate the blockage by half a spacing rule
|
||||
[ll, ur] = self.convert_blockage_to_tracks(blockage.inflate())
|
||||
[ll, ur] = self.convert_shape_to_tracks(blockage.inflate())
|
||||
zlayer = self.get_zindex(blockage.lpp)
|
||||
blockage_tracks = self.get_blockage_tracks(ll, ur, zlayer)
|
||||
blockage_tracks = self.convert_to_tracks(ll, ur, zlayer)
|
||||
return blockage_tracks
|
||||
|
||||
def convert_blockages(self):
|
||||
|
|
@ -460,6 +486,14 @@ class router(router_tech):
|
|||
blockage_list = self.convert_blockage(blockage)
|
||||
self.blocked_grids.update(blockage_list)
|
||||
|
||||
def get_blocked_grids(self):
|
||||
"""
|
||||
Return the blocked grids with their flag set
|
||||
"""
|
||||
#return set([x for x in self.blocked_grids if self.rg.is_blocked(x)])
|
||||
# These are all the non-pin blockages
|
||||
return self.blocked_grids
|
||||
|
||||
def retrieve_blockages(self, lpp):
|
||||
"""
|
||||
Recursive find boundaries as blockages to the routing grid.
|
||||
|
|
@ -473,7 +507,6 @@ class router(router_tech):
|
|||
new_pin = pin_layout("blockage{}".format(len(self.blockages)),
|
||||
rect,
|
||||
lpp)
|
||||
|
||||
# If there is a rectangle that is the same in the pins,
|
||||
# it isn't a blockage!
|
||||
if new_pin not in self.all_pins:
|
||||
|
|
@ -492,10 +525,10 @@ class router(router_tech):
|
|||
Convert a wave to a set of center points
|
||||
"""
|
||||
return [self.convert_point_to_units(i) for i in wave]
|
||||
|
||||
def convert_blockage_to_tracks(self, shape):
|
||||
|
||||
def convert_shape_to_tracks(self, shape):
|
||||
"""
|
||||
Convert a rectangular blockage shape into track units.
|
||||
Convert a rectangular shape into track units.
|
||||
"""
|
||||
(ll, ur) = shape
|
||||
ll = snap_to_grid(ll)
|
||||
|
|
@ -531,8 +564,8 @@ class router(router_tech):
|
|||
insufficient_list = set()
|
||||
|
||||
zindex = self.get_zindex(pin.lpp)
|
||||
for x in range(int(ll[0]) + expansion, int(ur[0]) + 1 + expansion):
|
||||
for y in range(int(ll[1] + expansion), int(ur[1]) + 1 + expansion):
|
||||
for x in range(int(ll[0]) - expansion, int(ur[0]) + 1 + expansion):
|
||||
for y in range(int(ll[1] - expansion), int(ur[1]) + 1 + expansion):
|
||||
(full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin,
|
||||
vector3d(x,
|
||||
y,
|
||||
|
|
@ -813,6 +846,7 @@ class router(router_tech):
|
|||
for pin_name in self.pin_groups:
|
||||
debug.info(2, "Enclosing pins for {}".format(pin_name))
|
||||
for pg in self.pin_groups[pin_name]:
|
||||
self.clear_blockages(pin_name)
|
||||
pg.enclose_pin()
|
||||
pg.add_enclosure(self.cell)
|
||||
|
||||
|
|
@ -824,6 +858,9 @@ class router(router_tech):
|
|||
for i in range(self.num_pin_components(pin_name)):
|
||||
self.add_pin_component_source(pin_name, i)
|
||||
|
||||
# Clearing the blockage of this pin requires the inflated pins
|
||||
self.clear_blockages(pin_name)
|
||||
|
||||
def add_target(self, pin_name):
|
||||
"""
|
||||
This will mark the grids for all pin components as a target.
|
||||
|
|
@ -832,6 +869,9 @@ class router(router_tech):
|
|||
for i in range(self.num_pin_components(pin_name)):
|
||||
self.add_pin_component_target(pin_name, i)
|
||||
|
||||
# Clearing the blockage of this pin requires the inflated pins
|
||||
self.clear_blockages(pin_name)
|
||||
|
||||
def add_perimeter_target(self, side="all"):
|
||||
"""
|
||||
This will mark all the cells on the perimeter of the original layout as a target.
|
||||
|
|
@ -1018,7 +1058,6 @@ class router(router_tech):
|
|||
|
||||
self.paths.append(grid_utils.flatten_set(path))
|
||||
self.add_route(path)
|
||||
|
||||
self.path_blockages.append(self.paths[-1])
|
||||
return True
|
||||
else:
|
||||
|
|
@ -1107,7 +1146,7 @@ class router(router_tech):
|
|||
"""
|
||||
Erase all of the comments on the current level.
|
||||
"""
|
||||
debug.info(0, "Erasing router info")
|
||||
debug.info(2, "Erasing router info")
|
||||
lpp = techlayer["text"]
|
||||
self.cell.objs = [x for x in self.cell.objs if x.lpp != lpp]
|
||||
|
||||
|
|
@ -1117,7 +1156,7 @@ class router(router_tech):
|
|||
the boundary layer for debugging purposes. This can only be
|
||||
called once or the labels will overlap.
|
||||
"""
|
||||
debug.info(0, "Adding router info")
|
||||
debug.info(2, "Adding router info")
|
||||
|
||||
show_blockages = False
|
||||
show_blockage_grids = False
|
||||
|
|
|
|||
|
|
@ -17,20 +17,12 @@ class signal_escape_router(router):
|
|||
A router that routes signals to perimeter and makes pins.
|
||||
"""
|
||||
|
||||
def __init__(self, layers, design, gds_filename=None):
|
||||
def __init__(self, layers, design, bbox=None, gds_filename=None):
|
||||
"""
|
||||
This will route on layers in design. It will get the blockages from
|
||||
either the gds file name or the design itself (by saving to a gds file).
|
||||
"""
|
||||
router.__init__(self, layers, design, gds_filename, 1)
|
||||
|
||||
def create_routing_grid(self):
|
||||
"""
|
||||
Create a sprase routing grid with A* expansion functions.
|
||||
"""
|
||||
size = self.ur - self.ll
|
||||
debug.info(1,"Size: {0} x {1}".format(size.x, size.y))
|
||||
self.rg = signal_grid(self.ll, self.ur, self.track_width)
|
||||
router.__init__(self, layers, design, gds_filename, bbox)
|
||||
|
||||
def perimeter_dist(self, pin_name):
|
||||
"""
|
||||
|
|
@ -47,7 +39,7 @@ class signal_escape_router(router):
|
|||
Takes a list of tuples (name, side) and routes them. After routing,
|
||||
it removes the old pin and places a new one on the perimeter.
|
||||
"""
|
||||
self.create_routing_grid()
|
||||
self.create_routing_grid(signal_grid)
|
||||
|
||||
start_time = datetime.now()
|
||||
self.find_pins_and_blockages(pin_names)
|
||||
|
|
@ -62,6 +54,8 @@ class signal_escape_router(router):
|
|||
start_time = datetime.now()
|
||||
for pin_name in ordered_pin_names:
|
||||
self.route_signal(pin_name)
|
||||
#if pin_name == "dout1[1]":
|
||||
# self.write_debug_gds("postroute.gds", False)
|
||||
|
||||
print_time("Maze routing pins",datetime.now(), start_time, 3)
|
||||
|
||||
|
|
@ -79,7 +73,8 @@ class signal_escape_router(router):
|
|||
|
||||
# This is inefficient since it is non-incremental, but it was
|
||||
# easier to debug.
|
||||
self.prepare_blockages(pin_name)
|
||||
self.prepare_blockages()
|
||||
self.clear_blockages(pin_name)
|
||||
|
||||
# Add the single component of the pin as the source
|
||||
# which unmarks it as a blockage too
|
||||
|
|
@ -88,12 +83,20 @@ class signal_escape_router(router):
|
|||
# Marks the grid cells all along the perimeter as a target
|
||||
self.add_perimeter_target(side)
|
||||
|
||||
# if pin_name == "dout0[3]":
|
||||
# self.write_debug_gds("pre_route.gds", False)
|
||||
# breakpoint()
|
||||
|
||||
# Actually run the A* router
|
||||
if self.run_router(detour_scale=detour_scale):
|
||||
new_pin = self.get_perimeter_pin()
|
||||
self.cell.replace_layout_pin(pin_name, new_pin)
|
||||
return
|
||||
|
||||
# if pin_name == "dout0[3]":
|
||||
# self.write_debug_gds("pre_route.gds", False)
|
||||
# breakpoint()
|
||||
|
||||
self.write_debug_gds("debug_route.gds", True)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,24 +15,12 @@ class signal_router(router):
|
|||
route on a given layer. This is limited to two layer routes.
|
||||
"""
|
||||
|
||||
def __init__(self, layers, design, gds_filename=None):
|
||||
def __init__(self, layers, design, gds_filename=None, bbox=None):
|
||||
"""
|
||||
This will route on layers in design. It will get the blockages from
|
||||
either the gds file name or the design itself (by saving to a gds file).
|
||||
"""
|
||||
router.__init__(self, layers, design, gds_filename)
|
||||
|
||||
def create_routing_grid(self):
|
||||
"""
|
||||
Create a sprase routing grid with A* expansion functions.
|
||||
"""
|
||||
# We will add a halo around the boundary
|
||||
# of this many tracks
|
||||
size = self.ur - self.ll
|
||||
debug.info(1, "Size: {0} x {1}".format(size.x, size.y))
|
||||
|
||||
import signal_grid
|
||||
self.rg = signal_grid.signal_grid(self.ll, self.ur, self.route_track_width)
|
||||
router.__init__(self, layers, design, gds_filename, bbox)
|
||||
|
||||
def route(self, src, dest, detour_scale=5):
|
||||
"""
|
||||
|
|
@ -52,7 +40,7 @@ class signal_router(router):
|
|||
# Creat a routing grid over the entire area
|
||||
# FIXME: This could be created only over the routing region,
|
||||
# but this is simplest for now.
|
||||
self.create_routing_grid()
|
||||
self.create_routing_grid(signal_grid)
|
||||
|
||||
# Get the pin shapes
|
||||
self.find_pins_and_blockages([src, dest])
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ from vector3d import vector3d
|
|||
from router import router
|
||||
from direction import direction
|
||||
from datetime import datetime
|
||||
from supply_grid import supply_grid
|
||||
import grid_utils
|
||||
|
||||
|
||||
|
|
@ -20,7 +21,7 @@ class supply_grid_router(router):
|
|||
routes a grid to connect the supply on the two layers.
|
||||
"""
|
||||
|
||||
def __init__(self, layers, design, gds_filename=None):
|
||||
def __init__(self, layers, design, gds_filename=None, bbox=None):
|
||||
"""
|
||||
This will route on layers in design. It will get the blockages from
|
||||
either the gds file name or the design itself (by saving to a gds file).
|
||||
|
|
@ -30,7 +31,7 @@ class supply_grid_router(router):
|
|||
# Power rail width in minimum wire widths
|
||||
self.route_track_width = 2
|
||||
|
||||
router.__init__(self, layers, design, gds_filename, self.route_track_width)
|
||||
router.__init__(self, layers, design, gds_filename, bbox, self.route_track_width)
|
||||
|
||||
# The list of supply rails (grid sets) that may be routed
|
||||
self.supply_rails = {}
|
||||
|
|
@ -39,16 +40,6 @@ class supply_grid_router(router):
|
|||
|
||||
print_time("Init supply router", datetime.now(), start_time, 3)
|
||||
|
||||
def create_routing_grid(self):
|
||||
"""
|
||||
Create a sprase routing grid with A* expansion functions.
|
||||
"""
|
||||
size = self.ur - self.ll
|
||||
debug.info(1, "Size: {0} x {1}".format(size.x, size.y))
|
||||
|
||||
import supply_grid
|
||||
self.rg = supply_grid.supply_grid(self.ll, self.ur, self.route_track_width)
|
||||
|
||||
def route(self, vdd_name="vdd", gnd_name="gnd"):
|
||||
"""
|
||||
Add power supply rails and connect all pins to these rails.
|
||||
|
|
@ -64,7 +55,7 @@ class supply_grid_router(router):
|
|||
# Creat a routing grid over the entire area
|
||||
# FIXME: This could be created only over the routing region,
|
||||
# but this is simplest for now.
|
||||
self.create_routing_grid()
|
||||
self.create_routing_grid(supply_grid)
|
||||
|
||||
# Get the pin shapes
|
||||
start_time = datetime.now()
|
||||
|
|
@ -73,13 +64,16 @@ class supply_grid_router(router):
|
|||
# Add the supply rails in a mesh network and connect H/V with vias
|
||||
start_time = datetime.now()
|
||||
# Block everything
|
||||
self.prepare_blockages(self.gnd_name)
|
||||
self.prepare_blockages()
|
||||
self.clear_blockages(self.gnd_name)
|
||||
|
||||
|
||||
# Determine the rail locations
|
||||
self.route_supply_rails(self.gnd_name, 0)
|
||||
|
||||
# Block everything
|
||||
self.prepare_blockages(self.vdd_name)
|
||||
self.prepare_blockages()
|
||||
self.clear_blockages(self.vdd_name)
|
||||
# Determine the rail locations
|
||||
self.route_supply_rails(self.vdd_name, 1)
|
||||
print_time("Routing supply rails", datetime.now(), start_time, 3)
|
||||
|
|
|
|||
|
|
@ -21,23 +21,17 @@ class supply_tree_router(router):
|
|||
routes a grid to connect the supply on the two layers.
|
||||
"""
|
||||
|
||||
def __init__(self, layers, design, gds_filename=None):
|
||||
def __init__(self, layers, design, gds_filename=None, bbox=None):
|
||||
"""
|
||||
This will route on layers in design. It will get the blockages from
|
||||
either the gds file name or the design itself (by saving to a gds file).
|
||||
"""
|
||||
# Power rail width in minimum wire widths
|
||||
self.route_track_width = 2
|
||||
# This is set to match the signal router so that the grids are aligned
|
||||
# for prettier routes.
|
||||
self.route_track_width = 1
|
||||
|
||||
router.__init__(self, layers, design, gds_filename, self.route_track_width)
|
||||
|
||||
def create_routing_grid(self):
|
||||
"""
|
||||
Create a sprase routing grid with A* expansion functions.
|
||||
"""
|
||||
size = self.ur - self.ll
|
||||
debug.info(1,"Size: {0} x {1}".format(size.x,size.y))
|
||||
self.rg = signal_grid(self.ll, self.ur, self.route_track_width)
|
||||
router.__init__(self, layers, design, gds_filename, bbox, self.route_track_width)
|
||||
|
||||
def route(self, vdd_name="vdd", gnd_name="gnd"):
|
||||
"""
|
||||
|
|
@ -54,19 +48,13 @@ class supply_tree_router(router):
|
|||
# Creat a routing grid over the entire area
|
||||
# FIXME: This could be created only over the routing region,
|
||||
# but this is simplest for now.
|
||||
self.create_routing_grid()
|
||||
self.create_routing_grid(signal_grid)
|
||||
|
||||
# Get the pin shapes
|
||||
start_time = datetime.now()
|
||||
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
||||
print_time("Finding pins and blockages",datetime.now(), start_time, 3)
|
||||
|
||||
# Add the supply rails in a mesh network and connect H/V with vias
|
||||
start_time = datetime.now()
|
||||
# Block everything
|
||||
self.prepare_blockages(self.gnd_name)
|
||||
self.prepare_blockages(self.vdd_name)
|
||||
|
||||
# Route the supply pins to the supply rails
|
||||
# Route vdd first since we want it to be shorter
|
||||
start_time = datetime.now()
|
||||
|
|
@ -122,32 +110,45 @@ class supply_tree_router(router):
|
|||
# Route MST components
|
||||
for (src, dest) in connections:
|
||||
self.route_signal(pin_name, src, dest)
|
||||
# if pin_name == "gnd":
|
||||
# print("\nSRC {}: ".format(src) + str(self.pin_groups[pin_name][src].grids) + str(self.pin_groups[pin_name][src].blockages))
|
||||
# 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.gds", True)
|
||||
#return
|
||||
#return
|
||||
|
||||
def route_signal(self, pin_name, src_idx, dest_idx):
|
||||
|
||||
for detour_scale in [5 * pow(2, x) for x in range(5)]:
|
||||
debug.info(2, "Routing {0} to {1} with scale {2}".format(src_idx, dest_idx, detour_scale))
|
||||
|
||||
# First pass, try to route normally
|
||||
# Second pass, clear prior pin blockages so that you can route over other metal
|
||||
# of the same supply. Otherwise, this can create a lot of circular routes due to accidental overlaps.
|
||||
for unblock_routes in [False, True]:
|
||||
for detour_scale in [5 * pow(2, x) for x in range(5)]:
|
||||
debug.info(2, "Routing {0} to {1} with scale {2}".format(src_idx, dest_idx, detour_scale))
|
||||
|
||||
# Clear everything in the routing grid.
|
||||
self.rg.reinit()
|
||||
# Clear everything in the routing grid.
|
||||
self.rg.reinit()
|
||||
|
||||
# This is inefficient since it is non-incremental, but it was
|
||||
# easier to debug.
|
||||
self.prepare_blockages(pin_name)
|
||||
# This is inefficient since it is non-incremental, but it was
|
||||
# easier to debug.
|
||||
self.prepare_blockages()
|
||||
if unblock_routes:
|
||||
msg = "Unblocking supply self blockages to improve access (may cause DRC errors):\n{0}\n{1})"
|
||||
debug.warning(msg.format(pin_name,
|
||||
self.pin_groups[pin_name][src_idx].pins))
|
||||
self.set_blockages(self.path_blockages, False)
|
||||
|
||||
# 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)
|
||||
# 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)
|
||||
|
||||
# Marks all pin components except index as target
|
||||
self.add_pin_component_target(pin_name, dest_idx)
|
||||
# Marks all pin components except index as target
|
||||
self.add_pin_component_target(pin_name, dest_idx)
|
||||
|
||||
# Actually run the A* router
|
||||
if self.run_router(detour_scale=detour_scale):
|
||||
return
|
||||
# Actually run the A* router
|
||||
if self.run_router(detour_scale=detour_scale):
|
||||
return
|
||||
|
||||
self.write_debug_gds("debug_route.gds", True)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ from vector import vector
|
|||
from sram_base import sram_base
|
||||
from contact import m2_via
|
||||
from channel_route import channel_route
|
||||
from signal_escape_router import signal_escape_router as router
|
||||
from globals import OPTS
|
||||
|
||||
|
||||
|
|
@ -246,49 +245,6 @@ class sram_1bank(sram_base):
|
|||
self.data_pos[port] = vector(x_offset, y_offset)
|
||||
self.spare_wen_pos[port] = vector(x_offset, y_offset)
|
||||
|
||||
def route_escape_pins(self):
|
||||
"""
|
||||
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:
|
||||
# Connect the control pins as inputs
|
||||
for signal in self.control_logic_inputs[port]:
|
||||
if signal.startswith("rbl"):
|
||||
continue
|
||||
if signal=="clk":
|
||||
pins_to_route.append("{0}{1}".format(signal, port))
|
||||
else:
|
||||
pins_to_route.append("{0}{1}".format(signal, port))
|
||||
|
||||
if port in self.write_ports:
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
pins_to_route.append("din{0}[{1}]".format(port, bit))
|
||||
|
||||
if port in self.readwrite_ports or port in self.read_ports:
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
pins_to_route.append("dout{0}[{1}]".format(port, bit))
|
||||
|
||||
for bit in range(self.col_addr_size):
|
||||
pins_to_route.append("addr{0}[{1}]".format(port, bit))
|
||||
|
||||
for bit in range(self.row_addr_size):
|
||||
pins_to_route.append("addr{0}[{1}]".format(port, bit + self.col_addr_size))
|
||||
|
||||
if port in self.write_ports:
|
||||
if self.write_size:
|
||||
for bit in range(self.num_wmasks):
|
||||
pins_to_route.append("wmask{0}[{1}]".format(port, bit))
|
||||
|
||||
if port in self.write_ports:
|
||||
for bit in range(self.num_spare_cols):
|
||||
pins_to_route.append("spare_wen{0}[{1}]".format(port, bit))
|
||||
|
||||
rtr=router(self.m3_stack, self)
|
||||
rtr.escape_route(pins_to_route)
|
||||
|
||||
def add_layout_pins(self, add_vias=True):
|
||||
"""
|
||||
Add the top-level pins for a single bank SRAM with control.
|
||||
|
|
@ -436,9 +392,9 @@ class sram_1bank(sram_base):
|
|||
if add_routes:
|
||||
# This causes problem in magic since it sometimes cannot extract connectivity of isntances
|
||||
# with no active devices.
|
||||
# self.add_inst(cr.name, cr)
|
||||
# self.connect_inst([])
|
||||
self.add_flat_inst(cr.name, cr)
|
||||
self.add_inst(cr.name, cr)
|
||||
self.connect_inst([])
|
||||
#self.add_flat_inst(cr.name, cr)
|
||||
else:
|
||||
self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap
|
||||
else:
|
||||
|
|
@ -451,9 +407,9 @@ class sram_1bank(sram_base):
|
|||
if add_routes:
|
||||
# This causes problem in magic since it sometimes cannot extract connectivity of isntances
|
||||
# with no active devices.
|
||||
# self.add_inst(cr.name, cr)
|
||||
# self.connect_inst([])
|
||||
self.add_flat_inst(cr.name, cr)
|
||||
self.add_inst(cr.name, cr)
|
||||
self.connect_inst([])
|
||||
#self.add_flat_inst(cr.name, cr)
|
||||
else:
|
||||
self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap
|
||||
|
||||
|
|
|
|||
|
|
@ -264,6 +264,50 @@ class sram_base(design, verilog, lef):
|
|||
pin.width(),
|
||||
pin.height())
|
||||
|
||||
def route_escape_pins(self):
|
||||
"""
|
||||
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:
|
||||
# Connect the control pins as inputs
|
||||
for signal in self.control_logic_inputs[port]:
|
||||
if signal.startswith("rbl"):
|
||||
continue
|
||||
if signal=="clk":
|
||||
pins_to_route.append("{0}{1}".format(signal, port))
|
||||
else:
|
||||
pins_to_route.append("{0}{1}".format(signal, port))
|
||||
|
||||
if port in self.write_ports:
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
pins_to_route.append("din{0}[{1}]".format(port, bit))
|
||||
|
||||
if port in self.readwrite_ports or port in self.read_ports:
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
pins_to_route.append("dout{0}[{1}]".format(port, bit))
|
||||
|
||||
for bit in range(self.col_addr_size):
|
||||
pins_to_route.append("addr{0}[{1}]".format(port, bit))
|
||||
|
||||
for bit in range(self.row_addr_size):
|
||||
pins_to_route.append("addr{0}[{1}]".format(port, bit + self.col_addr_size))
|
||||
|
||||
if port in self.write_ports:
|
||||
if self.write_size:
|
||||
for bit in range(self.num_wmasks):
|
||||
pins_to_route.append("wmask{0}[{1}]".format(port, bit))
|
||||
|
||||
if port in self.write_ports:
|
||||
for bit in range(self.num_spare_cols):
|
||||
pins_to_route.append("spare_wen{0}[{1}]".format(port, bit))
|
||||
|
||||
from signal_escape_router import signal_escape_router as router
|
||||
rtr=router(self.m3_stack, self)
|
||||
rtr.escape_route(pins_to_route)
|
||||
|
||||
def compute_bus_sizes(self):
|
||||
""" Compute the independent bus widths shared between two and four bank SRAMs """
|
||||
|
||||
|
|
|
|||
|
|
@ -91,8 +91,8 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa
|
|||
# These two options are temporarily disabled until Tim fixes a bug in magic related
|
||||
# to flattening channel routes and vias (hierarchy with no devices in it). Otherwise,
|
||||
# they appear to be disconnected.
|
||||
f.write("#gds flatten true\n")
|
||||
f.write("#gds ordering true\n")
|
||||
f.write("gds flatten true\n")
|
||||
f.write("gds ordering true\n")
|
||||
f.write("gds readonly true\n")
|
||||
f.write("gds read {}\n".format(gds_name))
|
||||
f.write('puts "Finished reading gds {}"\n'.format(gds_name))
|
||||
|
|
|
|||
Loading…
Reference in New Issue