Merge branch 'supply_router' into dev

This commit is contained in:
mrg 2021-01-15 14:28:08 -08:00
commit 3048c61c20
30 changed files with 321 additions and 288 deletions

View File

@ -1220,49 +1220,89 @@ class layout():
pin.height()) pin.height())
elif add_vias: 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. Add a signle input or output pin up to metal 3.
""" """
pin = instance.get_pin(pin_name) pin = instance.get_pin(pin_name)
if new_name == "":
new_name = pin_name
if not start_layer: if not start_layer:
start_layer = pin.layer start_layer = pin.layer
# 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(name=new_name, loc=pin.center(), start_layer=start_layer) self.add_power_pin(new_name, pin.center(), start_layer=start_layer)
def add_power_pin(self, name, loc, size=[1, 1], directions=None, start_layer="m1"): 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 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 the given center location. The starting layer is specified to determine
which vias are needed. which vias are needed.
""" """
if start_layer == self.pwr_grid_layer: if not loc:
self.add_layout_pin_rect_center(text=name, loc = pin.center()
layer=self.pwr_grid_layer,
offset=loc)
else:
via = self.add_via_stack_center(from_layer=start_layer,
to_layer=self.pwr_grid_layer,
size=size,
offset=loc,
directions=directions)
# Hack for min area # Hack for min area
if OPTS.tech_name == "sky130": if OPTS.tech_name == "sky130":
width = round_to_grid(sqrt(drc["minarea_m3"])) min_area = drc["minarea_{}".format(self.pwr_grid_layer)]
height = round_to_grid(drc["minarea_m3"] / width) width = round_to_grid(sqrt(min_area))
height = round_to_grid(min_area / width)
else: else:
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,
offset=loc,
directions=directions)
if not width:
width = via.width width = via.width
if not height:
height = via.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, layer=self.pwr_grid_layer,
offset=loc, offset=loc,
width=width, width=width,

View File

@ -615,9 +615,7 @@ class bank(design.design):
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
pin_list = inst.get_pins(pin_name) pin_list = inst.get_pins(pin_name)
for pin in pin_list: for pin in pin_list:
self.add_power_pin(pin_name, self.copy_power_pin(pin, pin.center())
pin.center(),
start_layer=pin.layer)
def route_bank_select(self, port): def route_bank_select(self, port):
""" Route the bank select logic. """ """ Route the bank select logic. """

View File

@ -100,7 +100,5 @@ class col_cap_array(bitcell_base_array):
inst = self.cell_inst[row, col] inst = self.cell_inst[row, col]
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
for pin in inst.get_pins(pin_name): for pin in inst.get_pins(pin_name):
self.add_power_pin(name=pin_name, self.copy_power_pin(pin)
loc=pin.center(),
start_layer=pin.layer)

View File

@ -177,14 +177,10 @@ class delay_chain(design.design):
load_list = self.load_inst_map[inst] load_list = self.load_inst_map[inst]
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
pin = load_list[0].get_pin(pin_name) pin = load_list[0].get_pin(pin_name)
self.add_power_pin(pin_name, self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0))
pin.rc() - vector(self.m1_pitch, 0),
start_layer=pin.layer)
pin = load_list[-2].get_pin(pin_name) pin = load_list[-2].get_pin(pin_name)
self.add_power_pin(pin_name, self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0))
pin.rc() - vector(self.m1_pitch, 0),
start_layer=pin.layer)
def add_layout_pins(self): def add_layout_pins(self):

View File

@ -112,11 +112,11 @@ class dff_array(design.design):
for col in range(self.columns): for col in range(self.columns):
# Continous vdd rail along with label. # Continous vdd rail along with label.
vdd_pin=self.dff_insts[row, col].get_pin("vdd") 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. # Continous gnd rail along with label.
gnd_pin=self.dff_insts[row, col].get_pin("gnd") 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 row in range(self.rows):
for col in range(self.columns): for col in range(self.columns):

View File

@ -159,11 +159,11 @@ class dff_buf_array(design.design):
for col in range(self.columns): for col in range(self.columns):
# Continous vdd rail along with label. # Continous vdd rail along with label.
vdd_pin=self.dff_insts[row, col].get_pin("vdd") 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. # Continous gnd rail along with label.
gnd_pin=self.dff_insts[row, col].get_pin("gnd") 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): def add_layout_pins(self):

View File

@ -7,11 +7,10 @@
# #
import debug import debug
import design import design
from tech import drc
from math import log
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
import dff_inv from sram_factory import factory
class dff_inv_array(design.design): class dff_inv_array(design.design):
""" """
@ -130,12 +129,11 @@ class dff_inv_array(design.design):
for col in range(self.columns): for col in range(self.columns):
# Adds power pin on left of row # Adds power pin on left of row
vdd_pin=self.dff_insts[row,col].get_pin("vdd") 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 # Adds gnd pin on left of row
gnd_pin=self.dff_insts[row,col].get_pin("gnd") 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 row in range(self.rows):
for col in range(self.columns): for col in range(self.columns):

View File

@ -611,12 +611,7 @@ class hierarchical_decoder(design.design):
for i in self.and_inst[:-1]: for i in self.and_inst[:-1]:
pins = i.get_pins(n) pins = i.get_pins(n)
for pin in pins: for pin in pins:
self.add_power_pin(name=n, self.copy_power_pin(pin, loc=pin.uc())
loc=pin.uc(),
start_layer=pin.layer)
self.add_power_pin(name=n,
loc=pin.uc(),
start_layer=pin.layer)
for i in self.pre2x4_inst + self.pre3x8_inst: for i in self.pre2x4_inst + self.pre3x8_inst:
self.copy_layout_pin(i, n) self.copy_layout_pin(i, n)
@ -628,9 +623,7 @@ class hierarchical_decoder(design.design):
# The nand and inv are the same height rows... # The nand and inv are the same height rows...
supply_pin = self.and_inst[row].get_pin(pin_name) supply_pin = self.and_inst[row].get_pin(pin_name)
pin_pos = vector(xoffset, supply_pin.cy()) pin_pos = vector(xoffset, supply_pin.cy())
self.add_power_pin(name=pin_name, self.copy_power_pin(supply_pin, loc=pin_pos)
loc=pin_pos,
start_layer=supply_pin.layer)
# Copy the pins from the predecoders # Copy the pins from the predecoders
for pre in self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst: for pre in self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst:

View File

@ -330,12 +330,7 @@ class hierarchical_predecode(design.design):
for i in self.inv_inst[:-1:2] + self.and_inst[:-1:2]: for i in self.inv_inst[:-1:2] + self.and_inst[:-1:2]:
pins = i.get_pins(n) pins = i.get_pins(n)
for pin in pins: for pin in pins:
self.add_power_pin(name=n, self.copy_power_pin(pin, loc=pin.uc())
loc=pin.uc(),
start_layer=pin.layer)
self.add_power_pin(name=n,
loc=pin.uc(),
start_layer=pin.layer)
# In other techs, we are using standard cell decoder cells with horizontal power # In other techs, we are using standard cell decoder cells with horizontal power
else: else:
@ -353,9 +348,7 @@ class hierarchical_predecode(design.design):
for xoffset in [self.inv_inst[0].lx() - self.bus_space, for xoffset in [self.inv_inst[0].lx() - self.bus_space,
self.and_inst[0].lx() - self.bus_space]: self.and_inst[0].lx() - self.bus_space]:
pin_pos = vector(xoffset, and_pin.cy()) pin_pos = vector(xoffset, and_pin.cy())
self.add_power_pin(name=n, self.copy_power_pin(and_pin, loc=pin_pos)
loc=pin_pos,
start_layer=and_pin.layer)

View File

@ -186,9 +186,7 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
for inst in supply_insts: for inst in supply_insts:
pin_list = inst.get_pins(pin_name) pin_list = inst.get_pins(pin_name)
for pin in pin_list: for pin in pin_list:
self.add_power_pin(name=pin_name, self.copy_power_pin(pin)
loc=pin.center(),
start_layer=pin.layer)
def route(self): def route(self):

View File

@ -82,9 +82,9 @@ class port_address(design.design):
for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"): for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"):
if layer_props.port_address.supply_offset: if layer_props.port_address.supply_offset:
self.add_power_pin("vdd", rbl_vdd_pin.center()) self.copy_power_pin(rbl_vdd_pin)
else: 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 # Also connect the B input of the RBL and_dec to vdd
if OPTS.local_array_size == 0: if OPTS.local_array_size == 0:

View File

@ -473,9 +473,7 @@ class replica_bitcell_array(bitcell_base_array):
for inst in supply_insts: for inst in supply_insts:
pin_list = inst.get_pins(pin_name) pin_list = inst.get_pins(pin_name)
for pin in pin_list: for pin in pin_list:
self.add_power_pin(name=pin_name, self.copy_power_pin(pin)
loc=pin.center(),
start_layer=pin.layer)
for inst in self.replica_col_insts: for inst in self.replica_col_insts:
if inst: if inst:

View File

@ -190,7 +190,8 @@ class replica_column(bitcell_base_array):
for (index, inst) in enumerate(self.cell_inst): for (index, inst) in enumerate(self.cell_inst):
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
if inst in [self.cell_inst[0], self.cell_inst[self.total_size - 1]]: 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: else:
self.copy_layout_pin(inst, pin_name) self.copy_layout_pin(inst, pin_name)

View File

@ -113,7 +113,5 @@ class row_cap_array(bitcell_base_array):
inst = self.cell_inst[row, col] inst = self.cell_inst[row, col]
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
for pin in inst.get_pins(pin_name): for pin in inst.get_pins(pin_name):
self.add_power_pin(name=pin_name, self.copy_power_pin(pin)
loc=pin.center(),
start_layer=pin.layer)

View File

@ -146,16 +146,10 @@ class sense_amp_array(design.design):
inst = self.local_insts[i] inst = self.local_insts[i]
for gnd_pin in inst.get_pins("gnd"): for gnd_pin in inst.get_pins("gnd"):
self.add_power_pin(name="gnd", self.copy_power_pin(gnd_pin, directions=("V", "V"))
loc=gnd_pin.center(),
start_layer=gnd_pin.layer,
directions=("V", "V"))
for vdd_pin in inst.get_pins("vdd"): for vdd_pin in inst.get_pins("vdd"):
self.add_power_pin(name="vdd", self.copy_power_pin(vdd_pin, directions=("V", "V"))
loc=vdd_pin.center(),
start_layer=vdd_pin.layer,
directions=("V", "V"))
bl_pin = inst.get_pin(inst.mod.get_bl_names()) bl_pin = inst.get_pin(inst.mod.get_bl_names())
br_pin = inst.get_pin(inst.mod.get_br_names()) br_pin = inst.get_pin(inst.mod.get_br_names())

View File

@ -96,7 +96,7 @@ class wordline_buffer_array(design.design):
# Add pins in two locations # Add pins in two locations
for xoffset in xoffset_list: for xoffset in xoffset_list:
pin_pos = vector(xoffset, supply_pin.cy()) 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): def create_drivers(self):
self.wld_inst = [] self.wld_inst = []

View File

@ -97,7 +97,7 @@ class wordline_driver_array(design.design):
# Add pins in two locations # Add pins in two locations
for xoffset in xoffset_list: for xoffset in xoffset_list:
pin_pos = vector(xoffset, supply_pin.cy()) 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): def create_drivers(self):
self.wld_inst = [] self.wld_inst = []

View File

@ -208,10 +208,8 @@ class write_driver_array(design.design):
for n in ["vdd", "gnd"]: for n in ["vdd", "gnd"]:
pin_list = self.driver_insts[i].get_pins(n) pin_list = self.driver_insts[i].get_pins(n)
for pin in pin_list: for pin in pin_list:
self.add_power_pin(name=n, self.copy_power_pin(pin, directions=("V", "V"))
loc=pin.center(),
directions=("V", "V"),
start_layer=pin.layer)
if self.write_size: if self.write_size:
for bit in range(self.num_wmasks): for bit in range(self.num_wmasks):
inst = self.driver_insts[bit * self.write_size] inst = self.driver_insts[bit * self.write_size]

View File

@ -145,6 +145,6 @@ class write_mask_and_array(design.design):
left_loc = vector(0, supply_pin_yoffset) left_loc = vector(0, supply_pin_yoffset)
right_loc = vector(self.width, supply_pin_yoffset) right_loc = vector(self.width, supply_pin_yoffset)
self.add_path(supply_pin.layer, [left_loc, right_loc]) self.add_path(supply_pin.layer, [left_loc, right_loc])
self.add_power_pin(supply, left_loc, start_layer=supply_pin.layer) self.copy_power_pin(supply_pin, loc=left_loc)
self.add_power_pin(supply, right_loc, start_layer=supply_pin.layer) self.copy_power_pin(supply_pin, loc=right_loc)

View File

@ -131,7 +131,10 @@ class pinv_dec(pinv.pinv):
self.nmos_inst.place(self.nmos_pos, self.nmos_inst.place(self.nmos_pos,
rotate=270) rotate=270)
# place PMOS so it is half a poly spacing down from the top # 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_pos = vector(xoffset, y_offset)
self.pmos_inst.place(self.pmos_pos, self.pmos_inst.place(self.pmos_pos,
rotate=270) rotate=270)

View File

@ -36,7 +36,7 @@ class grid:
# The bounds are in grids for this # The bounds are in grids for this
# This is really lower left bottom layer and upper right top layer in 3D. # 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.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 # let's leave the map sparse, cells are created on demand to reduce memory
self.map={} self.map={}

View File

@ -8,6 +8,7 @@
from direction import direction from direction import direction
from pin_layout import pin_layout from pin_layout import pin_layout
from vector import vector from vector import vector
from vector3d import vector3d
import debug import debug
@ -41,10 +42,7 @@ class pin_group:
# or could not be part of the pin # or could not be part of the pin
self.secondary_grids = set() self.secondary_grids = set()
# The corresponding set of partially blocked grids for each pin group. # The set of blocked grids due to this pin
# 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.
self.blockages = set() self.blockages = set()
# This is a set of pin_layout shapes to cover the grids # This is a set of pin_layout shapes to cover the grids
@ -421,7 +419,7 @@ class pin_group:
while True: while True:
next_cell = row[-1] + offset1 next_cell = row[-1] + offset1
# Can't move if not in the pin shape # 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) row.append(next_cell)
else: else:
break break
@ -430,7 +428,7 @@ class pin_group:
next_row = [x + offset2 for x in row] next_row = [x + offset2 for x in row]
for cell in next_row: for cell in next_row:
# Can't move if any cell is not in the pin shape # 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 break
else: else:
row = next_row row = next_row
@ -606,9 +604,10 @@ class pin_group:
The secondary set of grids are "optional" pin shapes that The secondary set of grids are "optional" pin shapes that
should be either blocked or part of the pin. should be either blocked or part of the pin.
""" """
# Set of tracks that overlap a pin
pin_set = set() pin_set = set()
# Set of track adjacent to or paritally overlap a pin (not full DRC connection)
partial_set = set() partial_set = set()
blockage_set = set()
for pin in self.pins: for pin in self.pins:
debug.info(4, " Converting {0}".format(pin)) debug.info(4, " Converting {0}".format(pin))
@ -621,25 +620,18 @@ class pin_group:
# Blockages will be a super-set of pins since # Blockages will be a super-set of pins since
# it uses the inflated pin shape. # it uses the inflated pin shape.
blockage_in_tracks = self.router.convert_blockage(pin) 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 # If we have a blockage, we must remove the grids
# Remember, this excludes the pin blockages already # Remember, this excludes the pin blockages already
shared_set = pin_set & self.router.blocked_grids blocked_grids = self.router.get_blocked_grids()
if len(shared_set) > 0: pin_set.difference_update(blocked_grids)
debug.info(4, "Removing pins {}".format(shared_set)) partial_set.difference_update(blocked_grids)
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)
# At least one of the groups must have some valid tracks # 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)) # debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins))
for pin in self.pins: for pin in self.pins:
@ -648,15 +640,25 @@ class pin_group:
(sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name, (sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
pin, pin,
expansion=1) expansion=1)
# This time, don't remove blockages in the hopes that it might be ok.
# Could cause DRC problems!
pin_set.update(sufficient) pin_set.update(sufficient)
partial_set.update(insufficient) partial_set.update(insufficient)
# If it's still empty, we must bail.
if len(pin_set) == 0 and len(partial_set) == 0: if len(pin_set) == 0 and len(partial_set) == 0:
debug.error("Unable to find unblocked pin {} {}".format(self.name, debug.error("Unable to find unblocked pin {} {}".format(self.name,
self.pins)) self.pins))
self.router.write_debug_gds("blocked_pin.gds") 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 self.grids = pin_set | partial_set
if len(self.grids) < 0: if len(self.grids) < 0:
debug.error("Did not find any unblocked grids: {}".format(str(self.pins))) debug.error("Did not find any unblocked grids: {}".format(str(self.pins)))

View File

@ -28,7 +28,7 @@ class router(router_tech):
route on a given layer. This is limited to two layer routes. route on a given layer. This is limited to two layer routes.
It populates blockages on a grid class. 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 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 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 # The blockage data structures
# A list of metal shapes (using the same pin_layout structure) # 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 = [] 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() self.blocked_grids = set()
# The routed data structures # 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) # A list of path blockages (they might be expanded for wide metal DRC)
self.path_blockages = [] self.path_blockages = []
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 # The boundary will determine the limits to the size
# of the routing grid # of the routing grid
self.boundary = self.layout.measureBoundary(self.top_name) self.boundary = self.layout.measureBoundary(self.top_name)
# These must be un-indexed to get rid of the matrix type # These must be un-indexed to get rid of the matrix type
self.ll = vector(self.boundary[0][0], self.boundary[0][1]) self.ll = vector(self.boundary[0][0], self.boundary[0][1])
self.ur = vector(self.boundary[1][0], self.boundary[1][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): def clear_pins(self):
""" """
@ -345,16 +371,17 @@ class router(router_tech):
# This is just a virtual function # This is just a virtual function
pass pass
def prepare_blockages(self, pin_name): def prepare_blockages(self):
""" """
Reset and add all of the blockages in the design. 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.") debug.info(3, "Preparing blockages.")
# Start fresh. Not the best for run-time, but simpler. # 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 # This adds the initial blockges of the design
# which includes all blockages due to non-pin shapes
# print("BLOCKING:", self.blocked_grids) # print("BLOCKING:", self.blocked_grids)
self.set_blockages(self.blocked_grids, True) 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 # If function doesn't exist, it isn't a supply router
pass pass
# Block all of the pin components # Now go and block all of the blockages due to pin shapes.
# (some will be unblocked if they're a source/target) # Some of these will get unblocked later if they are the source/target.
# Also block the previous routes
for name in self.pin_groups: for name in self.pin_groups:
blockage_grids = {y for x in self.pin_groups[name] for y in x.grids} # This should be a superset of the grids...
self.set_blockages(blockage_grids, True)
blockage_grids = {y for x in self.pin_groups[name] for y in x.blockages} blockage_grids = {y for x in self.pin_groups[name] for y in x.blockages}
self.set_blockages(blockage_grids, True) self.set_blockages(blockage_grids, True)
# FIXME: These duplicate a bit of work # If we have paths that were recently routed, add them as blockages as well.
# These are the paths that have already been routed. # 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) 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): def convert_shape_to_units(self, shape):
""" """
Scale a shape (two vector list) to user units Scale a shape (two vector list) to user units
@ -421,7 +440,14 @@ class router(router_tech):
# z direction # z direction
return 2 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. Clear all blockages on the grid.
""" """
@ -432,24 +458,24 @@ class router(router_tech):
""" Flag the blockages in the grid """ """ Flag the blockages in the grid """
self.rg.set_blocked(blockages, value) self.rg.set_blocked(blockages, value)
def get_blockage_tracks(self, ll, ur, z): def convert_to_tracks(self, ll, ur, z):
debug.info(3, "Converting blockage ll={0} ur={1} z={2}".format(str(ll),str(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 x in range(int(ll[0]), int(ur[0])+1):
for y in range(int(ll[1]), int(ur[1])+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): def convert_blockage(self, blockage):
""" """
Convert a pin layout blockage shape to routing grid tracks. Convert a pin layout blockage shape to routing grid tracks.
""" """
# Inflate the blockage by half a spacing rule # 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) 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 return blockage_tracks
def convert_blockages(self): def convert_blockages(self):
@ -460,6 +486,14 @@ class router(router_tech):
blockage_list = self.convert_blockage(blockage) blockage_list = self.convert_blockage(blockage)
self.blocked_grids.update(blockage_list) 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): def retrieve_blockages(self, lpp):
""" """
Recursive find boundaries as blockages to the routing grid. 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)), new_pin = pin_layout("blockage{}".format(len(self.blockages)),
rect, rect,
lpp) lpp)
# If there is a rectangle that is the same in the pins, # If there is a rectangle that is the same in the pins,
# it isn't a blockage! # it isn't a blockage!
if new_pin not in self.all_pins: if new_pin not in self.all_pins:
@ -493,9 +526,9 @@ class router(router_tech):
""" """
return [self.convert_point_to_units(i) for i in wave] 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, ur) = shape
ll = snap_to_grid(ll) ll = snap_to_grid(ll)
@ -531,8 +564,8 @@ class router(router_tech):
insufficient_list = set() insufficient_list = set()
zindex = self.get_zindex(pin.lpp) zindex = self.get_zindex(pin.lpp)
for x in range(int(ll[0]) + expansion, int(ur[0]) + 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): for y in range(int(ll[1] - expansion), int(ur[1]) + 1 + expansion):
(full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin, (full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin,
vector3d(x, vector3d(x,
y, y,
@ -813,6 +846,7 @@ class router(router_tech):
for pin_name in self.pin_groups: for pin_name in self.pin_groups:
debug.info(2, "Enclosing pins for {}".format(pin_name)) debug.info(2, "Enclosing pins for {}".format(pin_name))
for pg in self.pin_groups[pin_name]: for pg in self.pin_groups[pin_name]:
self.clear_blockages(pin_name)
pg.enclose_pin() pg.enclose_pin()
pg.add_enclosure(self.cell) pg.add_enclosure(self.cell)
@ -824,6 +858,9 @@ class router(router_tech):
for i in range(self.num_pin_components(pin_name)): for i in range(self.num_pin_components(pin_name)):
self.add_pin_component_source(pin_name, i) 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): def add_target(self, pin_name):
""" """
This will mark the grids for all pin components as a target. 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)): for i in range(self.num_pin_components(pin_name)):
self.add_pin_component_target(pin_name, i) 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"): def add_perimeter_target(self, side="all"):
""" """
This will mark all the cells on the perimeter of the original layout as a target. 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.paths.append(grid_utils.flatten_set(path))
self.add_route(path) self.add_route(path)
self.path_blockages.append(self.paths[-1]) self.path_blockages.append(self.paths[-1])
return True return True
else: else:
@ -1107,7 +1146,7 @@ class router(router_tech):
""" """
Erase all of the comments on the current level. Erase all of the comments on the current level.
""" """
debug.info(0, "Erasing router info") debug.info(2, "Erasing router info")
lpp = techlayer["text"] lpp = techlayer["text"]
self.cell.objs = [x for x in self.cell.objs if x.lpp != lpp] 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 the boundary layer for debugging purposes. This can only be
called once or the labels will overlap. called once or the labels will overlap.
""" """
debug.info(0, "Adding router info") debug.info(2, "Adding router info")
show_blockages = False show_blockages = False
show_blockage_grids = False show_blockage_grids = False

View File

@ -17,20 +17,12 @@ class signal_escape_router(router):
A router that routes signals to perimeter and makes pins. 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 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). either the gds file name or the design itself (by saving to a gds file).
""" """
router.__init__(self, layers, design, gds_filename, 1) router.__init__(self, layers, design, gds_filename, bbox)
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)
def perimeter_dist(self, pin_name): 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, 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. 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() start_time = datetime.now()
self.find_pins_and_blockages(pin_names) self.find_pins_and_blockages(pin_names)
@ -62,6 +54,8 @@ class signal_escape_router(router):
start_time = datetime.now() start_time = datetime.now()
for pin_name in ordered_pin_names: for pin_name in ordered_pin_names:
self.route_signal(pin_name) 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) 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 # This is inefficient since it is non-incremental, but it was
# easier to debug. # 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 # Add the single component of the pin as the source
# which unmarks it as a blockage too # 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 # Marks the grid cells all along the perimeter as a target
self.add_perimeter_target(side) self.add_perimeter_target(side)
# if pin_name == "dout0[3]":
# self.write_debug_gds("pre_route.gds", False)
# breakpoint()
# Actually run the A* router # Actually run the A* router
if self.run_router(detour_scale=detour_scale): if self.run_router(detour_scale=detour_scale):
new_pin = self.get_perimeter_pin() new_pin = self.get_perimeter_pin()
self.cell.replace_layout_pin(pin_name, new_pin) self.cell.replace_layout_pin(pin_name, new_pin)
return return
# if pin_name == "dout0[3]":
# self.write_debug_gds("pre_route.gds", False)
# breakpoint()
self.write_debug_gds("debug_route.gds", True) self.write_debug_gds("debug_route.gds", True)

View File

@ -15,24 +15,12 @@ class signal_router(router):
route on a given layer. This is limited to two layer routes. 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 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). either the gds file name or the design itself (by saving to a gds file).
""" """
router.__init__(self, layers, design, gds_filename) router.__init__(self, layers, design, gds_filename, bbox)
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)
def route(self, src, dest, detour_scale=5): def route(self, src, dest, detour_scale=5):
""" """
@ -52,7 +40,7 @@ class signal_router(router):
# Creat a routing grid over the entire area # Creat a routing grid over the entire area
# FIXME: This could be created only over the routing region, # FIXME: This could be created only over the routing region,
# but this is simplest for now. # but this is simplest for now.
self.create_routing_grid() self.create_routing_grid(signal_grid)
# Get the pin shapes # Get the pin shapes
self.find_pins_and_blockages([src, dest]) self.find_pins_and_blockages([src, dest])

View File

@ -11,6 +11,7 @@ from vector3d import vector3d
from router import router from router import router
from direction import direction from direction import direction
from datetime import datetime from datetime import datetime
from supply_grid import supply_grid
import grid_utils import grid_utils
@ -20,7 +21,7 @@ class supply_grid_router(router):
routes a grid to connect the supply on the two layers. 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 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). 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 # Power rail width in minimum wire widths
self.route_track_width = 2 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 # The list of supply rails (grid sets) that may be routed
self.supply_rails = {} self.supply_rails = {}
@ -39,16 +40,6 @@ class supply_grid_router(router):
print_time("Init supply router", datetime.now(), start_time, 3) 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"): def route(self, vdd_name="vdd", gnd_name="gnd"):
""" """
Add power supply rails and connect all pins to these rails. 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 # Creat a routing grid over the entire area
# FIXME: This could be created only over the routing region, # FIXME: This could be created only over the routing region,
# but this is simplest for now. # but this is simplest for now.
self.create_routing_grid() self.create_routing_grid(supply_grid)
# Get the pin shapes # Get the pin shapes
start_time = datetime.now() 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 # Add the supply rails in a mesh network and connect H/V with vias
start_time = datetime.now() start_time = datetime.now()
# Block everything # Block everything
self.prepare_blockages(self.gnd_name) self.prepare_blockages()
self.clear_blockages(self.gnd_name)
# Determine the rail locations # Determine the rail locations
self.route_supply_rails(self.gnd_name, 0) self.route_supply_rails(self.gnd_name, 0)
# Block everything # Block everything
self.prepare_blockages(self.vdd_name) self.prepare_blockages()
self.clear_blockages(self.vdd_name)
# Determine the rail locations # Determine the rail locations
self.route_supply_rails(self.vdd_name, 1) self.route_supply_rails(self.vdd_name, 1)
print_time("Routing supply rails", datetime.now(), start_time, 3) print_time("Routing supply rails", datetime.now(), start_time, 3)

View File

@ -21,23 +21,17 @@ class supply_tree_router(router):
routes a grid to connect the supply on the two layers. 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 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). either the gds file name or the design itself (by saving to a gds file).
""" """
# Power rail width in minimum wire widths # 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) router.__init__(self, layers, design, gds_filename, bbox, 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)
def route(self, vdd_name="vdd", gnd_name="gnd"): 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 # Creat a routing grid over the entire area
# FIXME: This could be created only over the routing region, # FIXME: This could be created only over the routing region,
# but this is simplest for now. # but this is simplest for now.
self.create_routing_grid() self.create_routing_grid(signal_grid)
# Get the pin shapes # Get the pin shapes
start_time = datetime.now() start_time = datetime.now()
self.find_pins_and_blockages([self.vdd_name, self.gnd_name]) self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
print_time("Finding pins and blockages",datetime.now(), start_time, 3) 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 the supply pins to the supply rails
# Route vdd first since we want it to be shorter # Route vdd first since we want it to be shorter
start_time = datetime.now() start_time = datetime.now()
@ -122,12 +110,20 @@ class supply_tree_router(router):
# Route MST components # Route MST components
for (src, dest) in connections: for (src, dest) in connections:
self.route_signal(pin_name, src, dest) 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) #self.write_debug_gds("final.gds", True)
#return #return
def route_signal(self, pin_name, src_idx, dest_idx): def route_signal(self, pin_name, src_idx, dest_idx):
# 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)]: 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)) debug.info(2, "Routing {0} to {1} with scale {2}".format(src_idx, dest_idx, detour_scale))
@ -136,7 +132,12 @@ class supply_tree_router(router):
# This is inefficient since it is non-incremental, but it was # This is inefficient since it is non-incremental, but it was
# easier to debug. # easier to debug.
self.prepare_blockages(pin_name) 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 # Add the single component of the pin as the source
# which unmarks it as a blockage too # which unmarks it as a blockage too

View File

@ -9,7 +9,6 @@ from vector import vector
from sram_base import sram_base from sram_base import sram_base
from contact import m2_via from contact import m2_via
from channel_route import channel_route from channel_route import channel_route
from signal_escape_router import signal_escape_router as router
from globals import OPTS from globals import OPTS
@ -246,49 +245,6 @@ class sram_1bank(sram_base):
self.data_pos[port] = vector(x_offset, y_offset) self.data_pos[port] = vector(x_offset, y_offset)
self.spare_wen_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): def add_layout_pins(self, add_vias=True):
""" """
Add the top-level pins for a single bank SRAM with control. Add the top-level pins for a single bank SRAM with control.
@ -436,9 +392,9 @@ class sram_1bank(sram_base):
if add_routes: if add_routes:
# This causes problem in magic since it sometimes cannot extract connectivity of isntances # This causes problem in magic since it sometimes cannot extract connectivity of isntances
# with no active devices. # with no active devices.
# self.add_inst(cr.name, cr) self.add_inst(cr.name, cr)
# self.connect_inst([]) self.connect_inst([])
self.add_flat_inst(cr.name, cr) #self.add_flat_inst(cr.name, cr)
else: else:
self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap
else: else:
@ -451,9 +407,9 @@ class sram_1bank(sram_base):
if add_routes: if add_routes:
# This causes problem in magic since it sometimes cannot extract connectivity of isntances # This causes problem in magic since it sometimes cannot extract connectivity of isntances
# with no active devices. # with no active devices.
# self.add_inst(cr.name, cr) self.add_inst(cr.name, cr)
# self.connect_inst([]) self.connect_inst([])
self.add_flat_inst(cr.name, cr) #self.add_flat_inst(cr.name, cr)
else: else:
self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap

View File

@ -264,6 +264,50 @@ class sram_base(design, verilog, lef):
pin.width(), pin.width(),
pin.height()) 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): 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 """

View File

@ -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 # 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, # to flattening channel routes and vias (hierarchy with no devices in it). Otherwise,
# they appear to be disconnected. # they appear to be disconnected.
f.write("#gds flatten true\n") f.write("gds flatten true\n")
f.write("#gds ordering true\n") f.write("gds ordering true\n")
f.write("gds readonly true\n") f.write("gds readonly true\n")
f.write("gds read {}\n".format(gds_name)) f.write("gds read {}\n".format(gds_name))
f.write('puts "Finished reading gds {}"\n'.format(gds_name)) f.write('puts "Finished reading gds {}"\n'.format(gds_name))