Supply tree uses signal grid. PEP8 cleanup.

This commit is contained in:
mrg 2020-12-21 13:51:50 -08:00
parent 98250cf115
commit 348001b1c8
15 changed files with 114 additions and 128 deletions

View File

@ -11,7 +11,7 @@ nominal_corner_only = True
route_supplies = True route_supplies = True
check_lvsdrc = True check_lvsdrc = True
perimeter_pins = True perimeter_pins = False
#netlist_only = True #netlist_only = True
#analytical_delay = False #analytical_delay = False
output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports, output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports,

View File

@ -11,8 +11,8 @@ num_w_ports = 0
tech_name = "scn4m_subm" tech_name = "scn4m_subm"
nominal_corner_only = True nominal_corner_only = True
route_supplies = False route_supplies = "tree"
check_lvsdrc = False check_lvsdrc = True
perimeter_pins = False perimeter_pins = False
#netlist_only = True #netlist_only = True
#analytical_delay = False #analytical_delay = False

View File

@ -27,13 +27,14 @@ 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, rail_track_width=1): def __init__(self, layers, design, gds_filename=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
considered. considered.
""" """
router_tech.__init__(self, layers, rail_track_width)
router_tech.__init__(self, layers, route_track_width)
self.cell = design self.cell = design
@ -1165,6 +1166,14 @@ class router(router_tech):
return keep_pin return keep_pin
def check_all_routed(self, pin_name):
"""
Check that all pin groups are routed.
"""
for pg in self.pin_groups[pin_name]:
if not pg.is_routed():
return False
# FIXME: This should be replaced with vector.snap_to_grid at some point # FIXME: This should be replaced with vector.snap_to_grid at some point
def snap_to_grid(offset): def snap_to_grid(offset):

View File

@ -16,13 +16,13 @@ class router_tech:
""" """
This is a class to hold the router tech constants. This is a class to hold the router tech constants.
""" """
def __init__(self, layers, rail_track_width): def __init__(self, layers, route_track_width):
""" """
Allows us to change the layers that we are routing on. Allows us to change the layers that we are routing on.
This uses the preferreed directions. This uses the preferreed directions.
""" """
self.layers = layers self.layers = layers
self.rail_track_width = rail_track_width self.route_track_width = route_track_width
if len(self.layers) == 1: if len(self.layers) == 1:
self.horiz_layer_name = self.vert_layer_name = self.layers[0] self.horiz_layer_name = self.vert_layer_name = self.layers[0]
@ -55,7 +55,7 @@ class router_tech:
"preferred_directions '{}' and '{}'.") "preferred_directions '{}' and '{}'.")
via_connect = contact(self.layers, (1, 1)) via_connect = contact(self.layers, (1, 1))
max_via_size = max(via_connect.width,via_connect.height) max_via_size = max(via_connect.width, via_connect.height)
self.horiz_lpp = layer[self.horiz_layer_name] self.horiz_lpp = layer[self.horiz_layer_name]
self.vert_lpp = layer[self.vert_layer_name] self.vert_lpp = layer[self.vert_layer_name]
@ -71,16 +71,16 @@ class router_tech:
self.vert_track_width = self.vert_layer_minwidth + self.vert_layer_spacing self.vert_track_width = self.vert_layer_minwidth + self.vert_layer_spacing
# We'll keep horizontal and vertical tracks the same for simplicity. # We'll keep horizontal and vertical tracks the same for simplicity.
self.track_width = max(self.horiz_track_width,self.vert_track_width) self.track_width = max(self.horiz_track_width, self.vert_track_width)
debug.info(1,"Track width: {:.3f}".format(self.track_width)) debug.info(1, "Track width: {:.3f}".format(self.track_width))
self.track_space = max(self.horiz_layer_spacing,self.vert_layer_spacing) self.track_space = max(self.horiz_layer_spacing, self.vert_layer_spacing)
debug.info(1,"Track space: {:.3f}".format(self.track_space)) debug.info(1, "Track space: {:.3f}".format(self.track_space))
self.track_wire = self.track_width - self.track_space self.track_wire = self.track_width - self.track_space
debug.info(1,"Track wire width: {:.3f}".format(self.track_wire)) debug.info(1, "Track wire width: {:.3f}".format(self.track_wire))
self.track_widths = vector([self.track_width] * 2) self.track_widths = vector([self.track_width] * 2)
self.track_factor = vector([1/self.track_width] * 2) self.track_factor = vector([1/self.track_width] * 2)
debug.info(2,"Track factor: {}".format(self.track_factor)) debug.info(2, "Track factor: {}".format(self.track_factor))
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side) # When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
self.layer_widths = [self.track_wire, 1, self.track_wire] self.layer_widths = [self.track_wire, 1, self.track_wire]
@ -107,7 +107,7 @@ class router_tech:
elif zindex==0: elif zindex==0:
return self.horiz_layer_name return self.horiz_layer_name
else: else:
debug.error("Invalid zindex {}".format(zindex),-1) debug.error("Invalid zindex {}".format(zindex), -1)
def get_supply_layer_width_space(self, zindex): def get_supply_layer_width_space(self, zindex):
""" """
@ -123,9 +123,9 @@ class router_tech:
min_wire_width = drc("minwidth_{0}".format(layer_name), 0, math.inf) min_wire_width = drc("minwidth_{0}".format(layer_name), 0, math.inf)
min_width = drc("minwidth_{0}".format(layer_name), self.rail_track_width*min_wire_width, math.inf) min_width = drc("minwidth_{0}".format(layer_name), self.route_track_width * min_wire_width, math.inf)
min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), self.rail_track_width*min_wire_width, math.inf) min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), self.route_track_width * min_wire_width, math.inf)
return (min_width,min_spacing) return (min_width, min_spacing)

View File

@ -5,7 +5,6 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from itertools import tee
import debug import debug
from heapq import heappush,heappop from heapq import heappush,heappop
from copy import deepcopy from copy import deepcopy
@ -14,6 +13,7 @@ from grid import grid
from grid_path import grid_path from grid_path import grid_path
from vector3d import vector3d from vector3d import vector3d
class signal_grid(grid): class signal_grid(grid):
""" """
Expand the two layer grid to include A* search functions for a source and target. Expand the two layer grid to include A* search functions for a source and target.
@ -34,11 +34,11 @@ class signal_grid(grid):
p.reset() p.reset()
# clear source and target pins # clear source and target pins
self.source=[] self.source = set()
self.target=[] self.target = set()
# Clear the queue # Clear the queue
while len(self.q)>0: while len(self.q) > 0:
heappop(self.q) heappop(self.q)
self.counter = 0 self.counter = 0
@ -49,19 +49,18 @@ class signal_grid(grid):
We will use an A* search, so this cost must be pessimistic. We will use an A* search, so this cost must be pessimistic.
Cost so far will be the length of the path. Cost so far will be the length of the path.
""" """
#debug.info(3,"Initializing queue.") #debug.info(3, "Initializing queue.")
# Counter is used to not require data comparison in Python 3.x # Counter is used to not require data comparison in Python 3.x
# Items will be returned in order they are added during cost ties # Items will be returned in order they are added during cost ties
self.counter = 0 self.counter = 0
for s in self.source: for s in self.source:
cost = self.cost_to_target(s) cost = self.cost_to_target(s)
debug.info(3,"Init: cost=" + str(cost) + " " + str([s])) debug.info(3, "Init: cost=" + str(cost) + " " + str([s]))
heappush(self.q,(cost,self.counter,grid_path([vector3d(s)]))) heappush(self.q, (cost, self.counter, grid_path([vector3d(s)])))
self.counter+=1 self.counter+=1
def route(self, detour_scale):
def route(self,detour_scale):
""" """
This does the A* maze routing with preferred direction routing. This does the A* maze routing with preferred direction routing.
This only works for 1 track wide routes! This only works for 1 track wide routes!
@ -70,7 +69,7 @@ class signal_grid(grid):
# We set a cost bound of the HPWL for run-time. This can be # We set a cost bound of the HPWL for run-time. This can be
# over-ridden if the route fails due to pruning a feasible solution. # over-ridden if the route fails due to pruning a feasible solution.
any_source_element = next(iter(self.source)) any_source_element = next(iter(self.source))
cost_bound = detour_scale*self.cost_to_target(any_source_element)*grid.PREFERRED_COST cost_bound = detour_scale * self.cost_to_target(any_source_element) * grid.PREFERRED_COST
# Check if something in the queue is already a source and a target! # Check if something in the queue is already a source and a target!
for s in self.source: for s in self.source:
@ -83,20 +82,17 @@ class signal_grid(grid):
# Put the source items into the queue # Put the source items into the queue
self.init_queue() self.init_queue()
cheapest_path = None
cheapest_cost = None
# Keep expanding and adding to the priority queue until we are done # Keep expanding and adding to the priority queue until we are done
while len(self.q)>0: while len(self.q)>0:
# should we keep the path in the queue as well or just the final node? # should we keep the path in the queue as well or just the final node?
(cost,count,curpath) = heappop(self.q) (cost, count, curpath) = heappop(self.q)
debug.info(3,"Queue size: size=" + str(len(self.q)) + " " + str(cost)) debug.info(3, "Queue size: size=" + str(len(self.q)) + " " + str(cost))
debug.info(4,"Expanding: cost=" + str(cost) + " " + str(curpath)) debug.info(4, "Expanding: cost=" + str(cost) + " " + str(curpath))
# expand the last element # expand the last element
neighbors = self.expand_dirs(curpath) neighbors = self.expand_dirs(curpath)
debug.info(4,"Neighbors: " + str(neighbors)) debug.info(4, "Neighbors: " + str(neighbors))
for n in neighbors: for n in neighbors:
# make a new copy of the path to not update the old ones # make a new copy of the path to not update the old ones
@ -105,7 +101,7 @@ class signal_grid(grid):
newpath.append(n) newpath.append(n)
# check if we hit the target and are done # check if we hit the target and are done
if self.is_target(n[0]): # This uses the [0] item because we are assuming 1-track wide if self.is_target(n[0]): # This uses the [0] item because we are assuming 1-track wide
return (newpath,newpath.cost()) return (newpath, newpath.cost())
else: else:
# current path cost + predicted cost # current path cost + predicted cost
current_cost = newpath.cost() current_cost = newpath.cost()
@ -116,18 +112,18 @@ class signal_grid(grid):
if (self.map[n[0]].min_cost==-1 or predicted_cost<self.map[n[0]].min_cost): if (self.map[n[0]].min_cost==-1 or predicted_cost<self.map[n[0]].min_cost):
self.map[n[0]].min_path = newpath self.map[n[0]].min_path = newpath
self.map[n[0]].min_cost = predicted_cost self.map[n[0]].min_cost = predicted_cost
debug.info(4,"Enqueuing: cost=" + str(current_cost) + "+" + str(target_cost) + " " + str(newpath)) debug.info(4, "Enqueuing: cost=" + str(current_cost) + "+" + str(target_cost) + " " + str(newpath))
# add the cost to get to this point if we haven't reached it yet # add the cost to get to this point if we haven't reached it yet
heappush(self.q,(predicted_cost,self.counter,newpath)) heappush(self.q, (predicted_cost, self.counter, newpath))
self.counter += 1 self.counter += 1
#else: #else:
# print("Better previous cost.") # print("Better previous cost.")
#else: #else:
# print("Cost bounded") # print("Cost bounded")
return (None,None) return (None, None)
def expand_dirs(self,curpath): def expand_dirs(self, curpath):
""" """
Expand each of the four cardinal directions plus up or down Expand each of the four cardinal directions plus up or down
but not expanding to blocked cells. Expands in all directions but not expanding to blocked cells. Expands in all directions
@ -142,33 +138,31 @@ class signal_grid(grid):
return unblocked_neighbors return unblocked_neighbors
def hpwl(self, src, dest): def hpwl(self, src, dest):
""" """
Return half perimeter wire length from point to another. Return half perimeter wire length from point to another.
Either point can have positive or negative coordinates. Either point can have positive or negative coordinates.
Include the via penalty if there is one. Include the via penalty if there is one.
""" """
hpwl = abs(src.x-dest.x) hpwl = abs(src.x - dest.x)
hpwl += abs(src.y-dest.y) hpwl += abs(src.y - dest.y)
if src.x!=dest.x and src.y!=dest.y: if src.x!=dest.x and src.y!=dest.y:
hpwl += grid.VIA_COST hpwl += grid.VIA_COST
return hpwl return hpwl
def cost_to_target(self,source): def cost_to_target(self, source):
""" """
Find the cheapest HPWL distance to any target point ignoring Find the cheapest HPWL distance to any target point ignoring
blockages for A* search. blockages for A* search.
""" """
any_target_element = next(iter(self.target)) any_target_element = next(iter(self.target))
cost = self.hpwl(source,any_target_element) cost = self.hpwl(source, any_target_element)
for t in self.target: for t in self.target:
cost = min(self.hpwl(source,t),cost) cost = min(self.hpwl(source, t), cost)
return cost return cost
def get_inertia(self, p0, p1):
def get_inertia(self,p0,p1):
""" """
Sets the direction based on the previous direction we came from. Sets the direction based on the previous direction we came from.
""" """

View File

@ -5,15 +5,10 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import gdsMill
import tech
from contact import contact
import math
import debug import debug
from pin_layout import pin_layout
from globals import OPTS
from router import router from router import router
class signal_router(router): class signal_router(router):
""" """
A router class to read an obstruction map from a gds and plan a A router class to read an obstruction map from a gds and plan a
@ -27,7 +22,6 @@ class signal_router(router):
""" """
router.__init__(self, layers, design, gds_filename) router.__init__(self, layers, design, gds_filename)
def create_routing_grid(self): def create_routing_grid(self):
""" """
Create a sprase routing grid with A* expansion functions. Create a sprase routing grid with A* expansion functions.
@ -35,11 +29,10 @@ class signal_router(router):
# We will add a halo around the boundary # We will add a halo around the boundary
# of this many tracks # of this many tracks
size = self.ur - self.ll size = self.ur - self.ll
debug.info(1,"Size: {0} x {1}".format(size.x,size.y)) debug.info(1, "Size: {0} x {1}".format(size.x, size.y))
import signal_grid import signal_grid
self.rg = signal_grid.signal_grid(self.ll, self.ur, self.track_width) 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):
""" """
@ -47,13 +40,13 @@ class signal_router(router):
the simplified rectilinear path. Cost factor is how sub-optimal to explore for a feasible route. the simplified rectilinear path. Cost factor is how sub-optimal to explore for a feasible route.
This is used to speed up the routing when there is not much detouring needed. This is used to speed up the routing when there is not much detouring needed.
""" """
debug.info(1,"Running signal router from {0} to {1}...".format(src,dest)) debug.info(1, "Running signal router from {0} to {1}...".format(src, dest))
self.pins[src] = [] self.pins[src] = []
self.pins[dest] = [] self.pins[dest] = []
# Clear the pins if we have previously routed # Clear the pins if we have previously routed
if (hasattr(self,'rg')): if (hasattr(self, 'rg')):
self.clear_pins() self.clear_pins()
else: else:
# Creat a routing grid over the entire area # Creat a routing grid over the entire area
@ -67,8 +60,8 @@ class signal_router(router):
# Block everything # Block everything
self.prepare_blockages() self.prepare_blockages()
# Clear the pins we are routing # Clear the pins we are routing
self.set_blockages(self.pin_components[src],False) self.set_blockages(self.pin_components[src], False)
self.set_blockages(self.pin_components[dest],False) self.set_blockages(self.pin_components[dest], False)
# Now add the src/tgt if they are not blocked by other shapes # Now add the src/tgt if they are not blocked by other shapes
self.add_source(src) self.add_source(src)

View File

@ -5,12 +5,8 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import debug
from vector3d import vector3d
from grid import grid
from signal_grid import signal_grid from signal_grid import signal_grid
from grid_path import grid_path from grid_path import grid_path
from direction import direction
class supply_grid(signal_grid): class supply_grid(signal_grid):
@ -27,13 +23,14 @@ class supply_grid(signal_grid):
def reinit(self): def reinit(self):
""" Reinitialize everything for a new route. """ """ Reinitialize everything for a new route. """
self.source = set() self.source = set()
self.target = set() self.target = set()
# Reset all the cells in the map # Reset all the cells in the map
for p in self.map.values(): for p in self.map.values():
p.reset() p.reset()
def find_start_wave(self, wave, direct): def find_start_wave(self, wave, direct):
""" """
Finds the first loc starting at loc and up that is open. Finds the first loc starting at loc and up that is open.
@ -46,8 +43,8 @@ class supply_grid(signal_grid):
return None return None
while wave and self.is_wave_blocked(wave): while wave and self.is_wave_blocked(wave):
wf=grid_path(wave) wf = grid_path(wave)
wave=wf.neighbor(direct) wave = wf.neighbor(direct)
# Bail out if we couldn't increment futher # Bail out if we couldn't increment futher
if wave[0].x > self.ur.x or wave[-1].y > self.ur.y: if wave[0].x > self.ur.x or wave[-1].y > self.ur.y:
return None return None
@ -57,7 +54,6 @@ class supply_grid(signal_grid):
return wave return wave
def is_wave_blocked(self, wave): def is_wave_blocked(self, wave):
""" """
Checks if any of the locations are blocked Checks if any of the locations are blocked
@ -68,7 +64,6 @@ class supply_grid(signal_grid):
else: else:
return False return False
def probe(self, wave, direct): def probe(self, wave, direct):
""" """
Expand the wave until there is a blockage and return Expand the wave until there is a blockage and return

View File

@ -28,9 +28,9 @@ class supply_grid_router(router):
start_time = datetime.now() start_time = datetime.now()
# Power rail width in minimum wire widths # Power rail width in minimum wire widths
self.rail_track_width = 3 self.route_track_width = 3
router.__init__(self, layers, design, gds_filename, self.rail_track_width) router.__init__(self, layers, design, gds_filename, 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 = {}
@ -47,7 +47,7 @@ class supply_grid_router(router):
debug.info(1, "Size: {0} x {1}".format(size.x, size.y)) debug.info(1, "Size: {0} x {1}".format(size.x, size.y))
import supply_grid import supply_grid
self.rg = supply_grid.supply_grid(self.ll, self.ur, self.track_width) 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"):
""" """
@ -104,14 +104,6 @@ class supply_grid_router(router):
return True return True
def check_all_routed(self, pin_name):
"""
Check that all pin groups are routed.
"""
for pg in self.pin_groups[pin_name]:
if not pg.is_routed():
return False
def route_simple_overlaps(self, pin_name): def route_simple_overlaps(self, pin_name):
""" """
This checks for simple cases where a pin component already overlaps a supply rail. This checks for simple cases where a pin component already overlaps a supply rail.
@ -317,7 +309,7 @@ class supply_grid_router(router):
data structure. Return whether it was added or not. data structure. Return whether it was added or not.
""" """
# We must have at least 2 tracks to drop plus 2 tracks for a via # We must have at least 2 tracks to drop plus 2 tracks for a via
if len(wave_path) >= 4 * self.rail_track_width: if len(wave_path) >= 4 * self.route_track_width:
grid_set = wave_path.get_grids() grid_set = wave_path.get_grids()
self.supply_rails[name].append(grid_set) self.supply_rails[name].append(grid_set)
return True return True

View File

@ -1,9 +1,9 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
#Copyright (c) 2016-2019 Regents of the University of California and The Board # Copyright (c) 2016-2019 Regents of the University of California and The Board
#of Regents for the Oklahoma Agricultural and Mechanical College # of Regents for the Oklahoma Agricultural and Mechanical College
#(acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
#All rights reserved. # All rights reserved.
# #
import debug import debug
from globals import print_time from globals import print_time
@ -26,9 +26,9 @@ class supply_tree_router(router):
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.rail_track_width = 3 self.route_track_width = 3
router.__init__(self, layers, design, gds_filename, self.rail_track_width) router.__init__(self, layers, design, gds_filename, self.route_track_width)
def create_routing_grid(self): def create_routing_grid(self):
""" """
@ -37,8 +37,8 @@ class supply_tree_router(router):
size = self.ur - self.ll size = self.ur - self.ll
debug.info(1,"Size: {0} x {1}".format(size.x,size.y)) debug.info(1,"Size: {0} x {1}".format(size.x,size.y))
import supply_grid import signal_grid
self.rg = supply_grid.supply_grid(self.ll, self.ur, self.track_width) self.rg = signal_grid.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"):
""" """
@ -85,15 +85,6 @@ class supply_tree_router(router):
return True return True
def check_all_routed(self, pin_name):
"""
Check that all pin groups are routed.
"""
for pg in self.pin_groups[pin_name]:
if not pg.is_routed():
return False
def prepare_blockages(self, pin_name): def prepare_blockages(self, pin_name):
""" """
Reset and add all of the blockages in the design. Reset and add all of the blockages in the design.
@ -125,7 +116,6 @@ class supply_tree_router(router):
blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids} blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
self.set_blockages(blockage_grids,False) self.set_blockages(blockage_grids,False)
def route_pins(self, pin_name): def route_pins(self, pin_name):
""" """
This will route each of the remaining pin components to the other pins. This will route each of the remaining pin components to the other pins.
@ -137,6 +127,7 @@ class supply_tree_router(router):
remaining_components)) remaining_components))
# Create full graph # Create full graph
debug.info(2,"Creating adjacency matrix")
pin_size = len(self.pin_groups[pin_name]) pin_size = len(self.pin_groups[pin_name])
adj_matrix = [[0] * pin_size for i in range(pin_size)] adj_matrix = [[0] * pin_size for i in range(pin_size)]
@ -148,6 +139,7 @@ class supply_tree_router(router):
adj_matrix[index1][index2] = dist adj_matrix[index1][index2] = dist
# Find MST # Find MST
debug.info(2,"Finding MinimumSpanning Tree")
X = csr_matrix(adj_matrix) X = csr_matrix(adj_matrix)
Tcsr = minimum_spanning_tree(X) Tcsr = minimum_spanning_tree(X)
mst = Tcsr.toarray().astype(int) mst = Tcsr.toarray().astype(int)

View File

@ -87,6 +87,17 @@ class sram():
def save(self): def save(self):
""" Save all the output files while reporting time to do it as well. """ """ Save all the output files while reporting time to do it as well. """
# Save the spice file
start_time = datetime.datetime.now()
spname = OPTS.output_path + self.s.name + ".sp"
debug.print_raw("SP: Writing to {0}".format(spname))
self.sp_write(spname)
functional(self.s,
os.path.basename(spname),
cycles=200,
output_path=OPTS.output_path)
print_time("Spice writing", datetime.datetime.now(), start_time)
if not OPTS.netlist_only: if not OPTS.netlist_only:
# Write the layout # Write the layout
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
@ -107,17 +118,6 @@ class sram():
self.lef_write(lefname) self.lef_write(lefname)
print_time("LEF", datetime.datetime.now(), start_time) print_time("LEF", datetime.datetime.now(), start_time)
# Save the spice file
start_time = datetime.datetime.now()
spname = OPTS.output_path + self.s.name + ".sp"
debug.print_raw("SP: Writing to {0}".format(spname))
self.sp_write(spname)
functional(self.s,
os.path.basename(spname),
cycles=200,
output_path=OPTS.output_path)
print_time("Spice writing", datetime.datetime.now(), start_time)
# Save the LVS file # Save the LVS file
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
lvsname = OPTS.output_path + self.s.name + ".lvs.sp" lvsname = OPTS.output_path + self.s.name + ".lvs.sp"

View File

@ -5,7 +5,6 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import debug
from vector import vector 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
@ -102,12 +101,17 @@ class sram_1bank(sram_base):
# Place with an initial wide channel (from above) # Place with an initial wide channel (from above)
self.place_dffs() self.place_dffs()
# Route the channel and set to the new data bus size # Route the channel and set to the new data bus size
# We need to temporarily add some pins for the x offsets
# but we'll remove them so that they have the right y
# offsets after the DFF placement.
self.add_layout_pins()
self.route_dffs(add_routes=False) self.route_dffs(add_routes=False)
self.remove_layout_pins()
# Re-place with the new channel size # Re-place with the new channel size
self.place_dffs() self.place_dffs()
# Now route the channel
self.route_dffs()
def place_row_addr_dffs(self): def place_row_addr_dffs(self):
""" """
@ -298,15 +302,20 @@ class sram_1bank(sram_base):
"din{0}[{1}]".format(port, bit)) "din{0}[{1}]".format(port, bit))
# Data output pins go to BOTTOM/TOP # Data output pins go to BOTTOM/TOP
if port in self.readwrite_ports and OPTS.perimeter_pins: if port in self.readwrite_ports:
for bit in range(self.word_size + self.num_spare_cols): for bit in range(self.word_size + self.num_spare_cols):
# This should be routed next to the din pin if OPTS.perimeter_pins:
p = din_ports[bit] # This should be routed next to the din pin
self.add_layout_pin_rect_center(text="dout{0}[{1}]".format(port, bit), p = din_ports[bit]
layer=p.layer, self.add_layout_pin_rect_center(text="dout{0}[{1}]".format(port, bit),
offset=p.center() + vector(self.m3_pitch, 0), layer=p.layer,
width=p.width(), offset=p.center() + vector(self.m3_pitch, 0),
height=p.height()) 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: elif port in self.read_ports:
for bit in range(self.word_size + self.num_spare_cols): for bit in range(self.word_size + self.num_spare_cols):
if OPTS.perimeter_pins: if OPTS.perimeter_pins:
@ -384,6 +393,8 @@ class sram_1bank(sram_base):
self.route_row_addr_dff() self.route_row_addr_dff()
self.route_dffs()
def route_dffs(self, add_routes=True): def route_dffs(self, add_routes=True):
for port in self.all_ports: for port in self.all_ports:

View File

@ -11,7 +11,9 @@ num_words = 16
tech_name = OPTS.tech_name tech_name = OPTS.tech_name
# perimeter_pins = True
nominal_corner_only = True nominal_corner_only = True
route_supplies = "tree" route_supplies = "grid"
check_lvsdrc = True check_lvsdrc = True

View File

@ -23,7 +23,6 @@ from tech import lvs_name
from tech import pex_name from tech import pex_name
debug.info(1, "Initializing verify...") debug.info(1, "Initializing verify...")
if not OPTS.check_lvsdrc: if not OPTS.check_lvsdrc:
debug.info(1, "LVS/DRC/PEX disabled.") debug.info(1, "LVS/DRC/PEX disabled.")
OPTS.drc_exe = None OPTS.drc_exe = None

View File

@ -68,7 +68,6 @@ num_pex_runs = 0
def write_drc_script(cell_name, gds_name, extract, final_verification, output_path, sp_name=None): def write_drc_script(cell_name, gds_name, extract, final_verification, output_path, sp_name=None):
""" Write a magic script to perform DRC and optionally extraction. """ """ Write a magic script to perform DRC and optionally extraction. """
global OPTS global OPTS
# Copy .magicrc file into the output directory # Copy .magicrc file into the output directory

View File

@ -17,8 +17,8 @@ lvs_warned = False
pex_warned = False pex_warned = False
def write_drc_script(cell_name, gds_name, extract, final_verification=False, output_path=None): def write_drc_script(cell_name, gds_name, extract, final_verification=False, output_path=None, sp_name=None):
pass debug.error("Cannot write DRC script for unknown tool", -1)
def run_drc(cell_name, gds_name, sp_name, extract=False, final_verification=False, output_path=None): def run_drc(cell_name, gds_name, sp_name, extract=False, final_verification=False, output_path=None):