mirror of https://github.com/VLSIDA/OpenRAM.git
Updates to IO signal router.
Route signals to perimeter using maze router. Move IO pins without perimeter pins to M3 using add_io_pin (like add_power_pin).
This commit is contained in:
parent
348001b1c8
commit
ae1c889235
|
|
@ -1197,6 +1197,18 @@ class layout():
|
|||
elif add_vias:
|
||||
self.add_power_pin(name, pin.center(), start_layer=pin.layer)
|
||||
|
||||
def add_io_pin(self, instance, pin_name, new_name=""):
|
||||
"""
|
||||
Add a signle input or output pin up to metal 3.
|
||||
"""
|
||||
pin = instance.get_pin(pin_name)
|
||||
|
||||
if new_name == "":
|
||||
new_name = pin_name
|
||||
|
||||
# Just use the power pin function for now to save code
|
||||
self.add_power_pin(name=new_name, loc=pin.center(), start_layer=pin.layer)
|
||||
|
||||
def add_power_pin(self, name, loc, size=[1, 1], directions=None, start_layer="m1"):
|
||||
"""
|
||||
Add a single power pin from the lowest power_grid layer down to M1 (or li) at
|
||||
|
|
|
|||
|
|
@ -5,12 +5,11 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import numpy as np
|
||||
import string
|
||||
import debug
|
||||
from vector3d import vector3d
|
||||
from grid_cell import grid_cell
|
||||
|
||||
|
||||
class grid:
|
||||
"""
|
||||
A two layer routing map. Each cell can be blocked in the vertical
|
||||
|
|
@ -23,7 +22,6 @@ class grid:
|
|||
NONPREFERRED_COST = 4
|
||||
PREFERRED_COST = 1
|
||||
|
||||
|
||||
def __init__(self, ll, ur, track_width):
|
||||
""" Initialize the map and define the costs. """
|
||||
|
||||
|
|
@ -33,12 +31,12 @@ class grid:
|
|||
|
||||
self.track_width = track_width
|
||||
self.track_widths = [self.track_width, self.track_width, 1.0]
|
||||
self.track_factor = [1/self.track_width, 1/self.track_width, 1.0]
|
||||
self.track_factor = [1 / self.track_width, 1 / self.track_width, 1.0]
|
||||
|
||||
# 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.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()
|
||||
|
||||
# let's leave the map sparse, cells are created on demand to reduce memory
|
||||
self.map={}
|
||||
|
|
@ -46,18 +44,18 @@ class grid:
|
|||
def add_all_grids(self):
|
||||
for x in range(self.ll.x, self.ur.x, 1):
|
||||
for y in range(self.ll.y, self.ur.y, 1):
|
||||
self.add_map(vector3d(x,y,0))
|
||||
self.add_map(vector3d(x,y,1))
|
||||
self.add_map(vector3d(x, y, 0))
|
||||
self.add_map(vector3d(x, y, 1))
|
||||
|
||||
def set_blocked(self,n,value=True):
|
||||
def set_blocked(self, n, value=True):
|
||||
if not isinstance(n, vector3d):
|
||||
for item in n:
|
||||
self.set_blocked(item,value)
|
||||
self.set_blocked(item, value)
|
||||
else:
|
||||
self.add_map(n)
|
||||
self.map[n].blocked=value
|
||||
|
||||
def is_blocked(self,n):
|
||||
def is_blocked(self, n):
|
||||
if not isinstance(n, vector3d):
|
||||
for item in n:
|
||||
if self.is_blocked(item):
|
||||
|
|
@ -68,11 +66,10 @@ class grid:
|
|||
self.add_map(n)
|
||||
return self.map[n].blocked
|
||||
|
||||
|
||||
def set_path(self,n,value=True):
|
||||
if isinstance(n, (list,tuple,set,frozenset)):
|
||||
def set_path(self, n, value=True):
|
||||
if isinstance(n, (list, tuple, set, frozenset)):
|
||||
for item in n:
|
||||
self.set_path(item,value)
|
||||
self.set_path(item, value)
|
||||
else:
|
||||
self.add_map(n)
|
||||
self.map[n].path=value
|
||||
|
|
@ -81,47 +78,89 @@ class grid:
|
|||
for k in self.map:
|
||||
self.map[k].blocked=False
|
||||
|
||||
def set_source(self,n,value=True):
|
||||
def set_source(self, n, value=True):
|
||||
if not isinstance(n, vector3d):
|
||||
for item in n:
|
||||
self.set_source(item,value)
|
||||
self.set_source(item, value)
|
||||
else:
|
||||
self.add_map(n)
|
||||
self.map[n].source=value
|
||||
self.source.add(n)
|
||||
|
||||
def set_target(self,n,value=True):
|
||||
def set_target(self, n, value=True):
|
||||
if not isinstance(n, vector3d):
|
||||
for item in n:
|
||||
self.set_target(item,value)
|
||||
self.set_target(item, value)
|
||||
else:
|
||||
self.add_map(n)
|
||||
self.map[n].target=value
|
||||
self.target.add(n)
|
||||
|
||||
|
||||
def add_source(self,track_list,value=True):
|
||||
debug.info(3,"Adding source list={0}".format(str(track_list)))
|
||||
def add_source(self, track_list, value=True):
|
||||
debug.info(3, "Adding source list={0}".format(str(track_list)))
|
||||
for n in track_list:
|
||||
debug.info(4,"Adding source ={0}".format(str(n)))
|
||||
self.set_source(n,value)
|
||||
self.set_blocked(n,False)
|
||||
debug.info(4, "Adding source ={0}".format(str(n)))
|
||||
self.set_source(n, value)
|
||||
self.set_blocked(n, False)
|
||||
|
||||
|
||||
def add_target(self,track_list,value=True):
|
||||
debug.info(3,"Adding target list={0}".format(str(track_list)))
|
||||
def add_target(self, track_list, value=True):
|
||||
debug.info(3, "Adding target list={0}".format(str(track_list)))
|
||||
for n in track_list:
|
||||
debug.info(4,"Adding target ={0}".format(str(n)))
|
||||
self.set_target(n,value)
|
||||
self.set_blocked(n,False)
|
||||
debug.info(4, "Adding target ={0}".format(str(n)))
|
||||
self.set_target(n, value)
|
||||
self.set_blocked(n, False)
|
||||
|
||||
def is_target(self,point):
|
||||
def add_perimeter_target(self, side="all", value=True):
|
||||
debug.info(3, "Adding perimeter target")
|
||||
|
||||
# Add the left/right columns
|
||||
if side=="all" or side=="left":
|
||||
x = self.ll.x
|
||||
for y in range(self.ll.y, self.ur.y, 1):
|
||||
n = vector3d(x, y, 0)
|
||||
self.set_target(n, value)
|
||||
self.set_blocked(n, False)
|
||||
n = vector3d(x, y, 1)
|
||||
self.set_target(n, value)
|
||||
self.set_blocked(n, False)
|
||||
|
||||
if side=="all" or side=="right":
|
||||
x = self.ur.x
|
||||
for y in range(self.ll.y, self.ur.y, 1):
|
||||
n = vector3d(x, y, 0)
|
||||
self.set_target(n, value)
|
||||
self.set_blocked(n, False)
|
||||
n = vector3d(x, y, 1)
|
||||
self.set_target(n, value)
|
||||
self.set_blocked(n, False)
|
||||
|
||||
if side=="all" or side=="bottom":
|
||||
y = self.ll.y
|
||||
for x in range(self.ll.x, self.ur.x, 1):
|
||||
n = vector3d(x, y, 0)
|
||||
self.set_target(n, value)
|
||||
self.set_blocked(n, False)
|
||||
n = vector3d(x, y, 1)
|
||||
self.set_target(n, value)
|
||||
self.set_blocked(n, False)
|
||||
|
||||
if side=="all" or side=="top":
|
||||
y = self.ur.y
|
||||
for x in range(self.ll.x, self.ur.x, 1):
|
||||
n = vector3d(x, y, 0)
|
||||
self.set_target(n, value)
|
||||
self.set_blocked(n, False)
|
||||
n = vector3d(x, y, 1)
|
||||
self.set_target(n, value)
|
||||
self.set_blocked(n, False)
|
||||
|
||||
def is_target(self, point):
|
||||
"""
|
||||
Point is in the target set, so we are done.
|
||||
"""
|
||||
return point in self.target
|
||||
|
||||
def add_map(self,n):
|
||||
def add_map(self, n):
|
||||
"""
|
||||
Add a point to the map if it doesn't exist.
|
||||
"""
|
||||
|
|
@ -132,8 +171,7 @@ class grid:
|
|||
if n not in self.map:
|
||||
self.map[n]=grid_cell()
|
||||
|
||||
|
||||
def block_path(self,path):
|
||||
def block_path(self, path):
|
||||
"""
|
||||
Mark the path in the routing grid as blocked.
|
||||
Also unsets the path flag.
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ class router(router_tech):
|
|||
If so, reduce the pin group grid to not include the adjacent grid.
|
||||
Try to do this intelligently to keep th pins enclosed.
|
||||
"""
|
||||
debug.info(1,
|
||||
debug.info(2,
|
||||
"Comparing {0} and {1} adjacency".format(pin_name1,
|
||||
pin_name2))
|
||||
removed_grids = 0
|
||||
|
|
@ -302,7 +302,7 @@ class router(router_tech):
|
|||
adj_grids))
|
||||
self.remove_adjacent_grid(pg1, pg2, adj_grids)
|
||||
|
||||
debug.info(1, "Removed {} adjacent grids.".format(removed_grids))
|
||||
debug.info(2, "Removed {} adjacent grids.".format(removed_grids))
|
||||
|
||||
def remove_adjacent_grid(self, pg1, pg2, adj_grids):
|
||||
"""
|
||||
|
|
@ -348,6 +348,10 @@ class router(router_tech):
|
|||
smaller))
|
||||
smaller.grids.remove(adj)
|
||||
|
||||
def set_supply_rail_blocked(self, value):
|
||||
# This is just a virtual function
|
||||
pass
|
||||
|
||||
def prepare_blockages(self, pin_name):
|
||||
"""
|
||||
Reset and add all of the blockages in the design.
|
||||
|
|
@ -363,7 +367,11 @@ class router(router_tech):
|
|||
|
||||
# Block all of the supply rails
|
||||
# (some will be unblocked if they're a target)
|
||||
self.set_supply_rail_blocked(True)
|
||||
try:
|
||||
self.set_supply_rail_blocked(True)
|
||||
except AttributeError:
|
||||
# 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)
|
||||
|
|
@ -798,7 +806,7 @@ class router(router_tech):
|
|||
"""
|
||||
Convert the pin groups into pin tracks and blockage tracks.
|
||||
"""
|
||||
debug.info(1, "Converting pins for {}.".format(pin_name))
|
||||
debug.info(2, "Converting pins for {}.".format(pin_name))
|
||||
for pg in self.pin_groups[pin_name]:
|
||||
pg.convert_pin()
|
||||
|
||||
|
|
@ -809,7 +817,7 @@ class router(router_tech):
|
|||
that are blocked by other shapes.
|
||||
"""
|
||||
for pin_name in self.pin_groups:
|
||||
debug.info(1, "Enclosing pins for {}".format(pin_name))
|
||||
debug.info(2, "Enclosing pins for {}".format(pin_name))
|
||||
for pg in self.pin_groups[pin_name]:
|
||||
pg.enclose_pin()
|
||||
pg.add_enclosure(self.cell)
|
||||
|
|
@ -830,6 +838,12 @@ class router(router_tech):
|
|||
for i in range(self.num_pin_components(pin_name)):
|
||||
self.add_pin_component_target(pin_name, i)
|
||||
|
||||
def add_perimeter_target(self, side="all"):
|
||||
"""
|
||||
This will mark all the cells on the perimeter of the original layout as a target.
|
||||
"""
|
||||
self.rg.add_perimeter_target(side=side)
|
||||
|
||||
def num_pin_components(self, pin_name):
|
||||
"""
|
||||
This returns how many disconnected pin components there are.
|
||||
|
|
@ -902,7 +916,7 @@ class router(router_tech):
|
|||
# self.write_debug_gds()
|
||||
|
||||
# First, simplify the path for
|
||||
# debug.info(1, str(self.path))
|
||||
# debug.info(3, str(self.path))
|
||||
contracted_path = self.contract_path(path)
|
||||
debug.info(3, "Contracted path: " + str(contracted_path))
|
||||
|
||||
|
|
|
|||
|
|
@ -49,8 +49,6 @@ class signal_grid(grid):
|
|||
We will use an A* search, so this cost must be pessimistic.
|
||||
Cost so far will be the length of the path.
|
||||
"""
|
||||
#debug.info(3, "Initializing queue.")
|
||||
|
||||
# Counter is used to not require data comparison in Python 3.x
|
||||
# Items will be returned in order they are added during cost ties
|
||||
self.counter = 0
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ class supply_grid_router(router):
|
|||
start_time = datetime.now()
|
||||
# Block everything
|
||||
self.prepare_blockages(self.gnd_name)
|
||||
|
||||
# Determine the rail locations
|
||||
self.route_supply_rails(self.gnd_name, 0)
|
||||
|
||||
|
|
|
|||
|
|
@ -85,37 +85,6 @@ class supply_tree_router(router):
|
|||
|
||||
return True
|
||||
|
||||
def prepare_blockages(self, pin_name):
|
||||
"""
|
||||
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()
|
||||
# This adds the initial blockges of the design
|
||||
#print("BLOCKING:",self.blocked_grids)
|
||||
self.set_blockages(self.blocked_grids,True)
|
||||
|
||||
# Block all of the pin components (some will be unblocked if they're a source/target)
|
||||
# Also block the previous routes
|
||||
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)
|
||||
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.
|
||||
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
|
||||
blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
|
||||
self.set_blockages(blockage_grids,False)
|
||||
|
||||
def route_pins(self, pin_name):
|
||||
"""
|
||||
This will route each of the remaining pin components to the other pins.
|
||||
|
|
@ -187,3 +156,14 @@ class supply_tree_router(router):
|
|||
|
||||
|
||||
|
||||
def add_io_pin(self, instance, pin_name, new_name=""):
|
||||
"""
|
||||
Add a signle input or output pin up to metal 3.
|
||||
"""
|
||||
pin = instance.get_pins(pin_name)
|
||||
|
||||
if new_name == "":
|
||||
new_name = pin_name
|
||||
|
||||
# Just use the power pin function for now to save code
|
||||
self.add_power_pin(name=new_name, loc=pin.center(), start_layer=pin.layer)
|
||||
|
|
|
|||
|
|
@ -249,138 +249,73 @@ class sram_1bank(sram_base):
|
|||
"""
|
||||
Add the top-level pins for a single bank SRAM with control.
|
||||
"""
|
||||
highest_coord = self.find_highest_coords()
|
||||
lowest_coord = self.find_lowest_coords()
|
||||
bbox = [lowest_coord, highest_coord]
|
||||
|
||||
# List of pin to new pin name
|
||||
all_pins = []
|
||||
for port in self.all_ports:
|
||||
# Depending on the port, use the bottom/top or left/right sides
|
||||
# Port 0 is left/bottom
|
||||
# Port 1 is right/top
|
||||
bottom_or_top = "bottom" if port==0 else "top"
|
||||
left_or_right = "left" if port==0 else "right"
|
||||
|
||||
|
||||
# Connect the control pins as inputs
|
||||
for signal in self.control_logic_inputs[port]:
|
||||
if signal == "clk":
|
||||
continue
|
||||
if signal.startswith("rbl"):
|
||||
continue
|
||||
if OPTS.perimeter_pins:
|
||||
self.add_perimeter_pin(name=signal + "{}".format(port),
|
||||
pin=self.control_logic_insts[port].get_pin(signal),
|
||||
side=left_or_right,
|
||||
bbox=bbox)
|
||||
self.add_io_pin(self.control_logic_insts[port],
|
||||
signal,
|
||||
signal + "{}".format(port))
|
||||
if signal=="clk":
|
||||
all_pins.append(("{0}{1}".format(signal, port), bottom_or_top))
|
||||
else:
|
||||
self.copy_layout_pin(self.control_logic_insts[port],
|
||||
signal,
|
||||
signal + "{}".format(port))
|
||||
|
||||
if OPTS.perimeter_pins:
|
||||
self.add_perimeter_pin(name="clk{}".format(port),
|
||||
pin=self.control_logic_insts[port].get_pin("clk"),
|
||||
side=bottom_or_top,
|
||||
bbox=bbox)
|
||||
else:
|
||||
self.copy_layout_pin(self.control_logic_insts[port],
|
||||
"clk",
|
||||
"clk{}".format(port))
|
||||
|
||||
# Data input pins go to BOTTOM/TOP
|
||||
din_ports = []
|
||||
all_pins.append(("{0}{1}".format(signal, port), left_or_right))
|
||||
|
||||
if port in self.write_ports:
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
if OPTS.perimeter_pins:
|
||||
p = self.add_perimeter_pin(name="din{0}[{1}]".format(port, bit),
|
||||
pin=self.data_dff_insts[port].get_pin("din_{0}".format(bit)),
|
||||
side=bottom_or_top,
|
||||
bbox=bbox)
|
||||
din_ports.append(p)
|
||||
else:
|
||||
self.copy_layout_pin(self.data_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"din{0}[{1}]".format(port, bit))
|
||||
self.add_io_pin(self.data_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"din{0}[{1}]".format(port, bit))
|
||||
all_pins.append(("din{0}[{1}]".format(port, bit), bottom_or_top))
|
||||
|
||||
# Data output pins go to BOTTOM/TOP
|
||||
if port in self.readwrite_ports:
|
||||
if port in self.readwrite_ports or port in self.read_ports:
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
if OPTS.perimeter_pins:
|
||||
# This should be routed next to the din pin
|
||||
p = din_ports[bit]
|
||||
self.add_layout_pin_rect_center(text="dout{0}[{1}]".format(port, bit),
|
||||
layer=p.layer,
|
||||
offset=p.center() + vector(self.m3_pitch, 0),
|
||||
width=p.width(),
|
||||
height=p.height())
|
||||
else:
|
||||
self.copy_layout_pin(self.bank_inst,
|
||||
"dout{0}_{1}".format(port, bit),
|
||||
"dout{0}[{1}]".format(port, bit))
|
||||
elif port in self.read_ports:
|
||||
for bit in range(self.word_size + self.num_spare_cols):
|
||||
if OPTS.perimeter_pins:
|
||||
# This should have a clear route to the perimeter if there are no din routes
|
||||
self.add_perimeter_pin(name="dout{0}[{1}]".format(port, bit),
|
||||
pin=self.bank_inst.get_pin("dout{0}_{1}".format(port, bit)),
|
||||
side=bottom_or_top,
|
||||
bbox=bbox)
|
||||
else:
|
||||
self.copy_layout_pin(self.bank_inst,
|
||||
"dout{0}_{1}".format(port, bit),
|
||||
"dout{0}[{1}]".format(port, bit))
|
||||
self.add_io_pin(self.bank_inst,
|
||||
"dout{0}_{1}".format(port, bit),
|
||||
"dout{0}[{1}]".format(port, bit))
|
||||
all_pins.append(("dout{0}[{1}]".format(port, bit), bottom_or_top))
|
||||
|
||||
|
||||
|
||||
# Lower address bits go to BOTTOM/TOP
|
||||
for bit in range(self.col_addr_size):
|
||||
if OPTS.perimeter_pins:
|
||||
self.add_perimeter_pin(name="addr{0}[{1}]".format(port, bit),
|
||||
pin=self.col_addr_dff_insts[port].get_pin("din_{}".format(bit)),
|
||||
side=bottom_or_top,
|
||||
bbox=bbox)
|
||||
else:
|
||||
self.copy_layout_pin(self.col_addr_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"addr{0}[{1}]".format(port, bit))
|
||||
self.add_io_pin(self.col_addr_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"addr{0}[{1}]".format(port, bit))
|
||||
|
||||
all_pins.append(("addr{0}[{1}]".format(port, bit), bottom_or_top))
|
||||
|
||||
# Upper address bits go to LEFT/RIGHT
|
||||
for bit in range(self.row_addr_size):
|
||||
if OPTS.perimeter_pins:
|
||||
self.add_perimeter_pin(name="addr{0}[{1}]".format(port, bit + self.col_addr_size),
|
||||
pin=self.row_addr_dff_insts[port].get_pin("din_{}".format(bit)),
|
||||
side=left_or_right,
|
||||
bbox=bbox)
|
||||
else:
|
||||
self.copy_layout_pin(self.row_addr_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"addr{0}[{1}]".format(port, bit + self.col_addr_size))
|
||||
self.add_io_pin(self.row_addr_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"addr{0}[{1}]".format(port, bit + self.col_addr_size))
|
||||
all_pins.append(("addr{0}[{1}]".format(port, bit + self.col_addr_size), left_or_right))
|
||||
|
||||
# Write mask pins go to BOTTOM/TOP
|
||||
if port in self.write_ports:
|
||||
if self.write_size:
|
||||
for bit in range(self.num_wmasks):
|
||||
if OPTS.perimeter_pins:
|
||||
self.add_perimeter_pin(name="wmask{0}[{1}]".format(port, bit),
|
||||
pin=self.wmask_dff_insts[port].get_pin("din_{}".format(bit)),
|
||||
side=bottom_or_top,
|
||||
bbox=bbox)
|
||||
else:
|
||||
self.copy_layout_pin(self.wmask_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"wmask{0}[{1}]".format(port, bit))
|
||||
self.add_io_pin(self.wmask_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"wmask{0}[{1}]".format(port, bit))
|
||||
all_pins.append(("wmask{0}[{1}]".format(port, bit), bottom_or_top))
|
||||
|
||||
# Spare wen pins go to BOTTOM/TOP
|
||||
if port in self.write_ports:
|
||||
for bit in range(self.num_spare_cols):
|
||||
if OPTS.perimeter_pins:
|
||||
self.add_perimeter_pin(name="spare_wen{0}[{1}]".format(port, bit),
|
||||
pin=self.spare_wen_dff_insts[port].get_pin("din_{}".format(bit)),
|
||||
side=left_or_right,
|
||||
bbox=bbox)
|
||||
else:
|
||||
self.copy_layout_pin(self.spare_wen_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"spare_wen{0}[{1}]".format(port, bit))
|
||||
self.add_io_pin(self.spare_wen_dff_insts[port],
|
||||
"din_{}".format(bit),
|
||||
"spare_wen{0}[{1}]".format(port, bit))
|
||||
all_pins.append(("spare_wen{0}[{1}]".format(port, bit), bottom_or_top))
|
||||
|
||||
if OPTS.perimeter_pins:
|
||||
from signal_exit_router import signal_exit_router as router
|
||||
rtr=router(self.m3_stack, self)
|
||||
rtr.route(all_pins)
|
||||
|
||||
def route_layout(self):
|
||||
""" Route a single bank SRAM """
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ num_words = 16
|
|||
|
||||
tech_name = OPTS.tech_name
|
||||
|
||||
# perimeter_pins = True
|
||||
perimeter_pins = True
|
||||
|
||||
nominal_corner_only = True
|
||||
route_supplies = "grid"
|
||||
route_supplies = "tree"
|
||||
check_lvsdrc = True
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue