mirror of https://github.com/VLSIDA/OpenRAM.git
Supply tree uses signal grid. PEP8 cleanup.
This commit is contained in:
parent
98250cf115
commit
348001b1c8
|
|
@ -11,7 +11,7 @@ nominal_corner_only = True
|
|||
|
||||
route_supplies = True
|
||||
check_lvsdrc = True
|
||||
perimeter_pins = True
|
||||
perimeter_pins = False
|
||||
#netlist_only = True
|
||||
#analytical_delay = False
|
||||
output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports,
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ num_w_ports = 0
|
|||
tech_name = "scn4m_subm"
|
||||
nominal_corner_only = True
|
||||
|
||||
route_supplies = False
|
||||
check_lvsdrc = False
|
||||
route_supplies = "tree"
|
||||
check_lvsdrc = True
|
||||
perimeter_pins = False
|
||||
#netlist_only = True
|
||||
#analytical_delay = False
|
||||
|
|
|
|||
|
|
@ -27,13 +27,14 @@ class router(router_tech):
|
|||
route on a given layer. This is limited to two layer routes.
|
||||
It populates blockages on a grid class.
|
||||
"""
|
||||
def __init__(self, layers, design, gds_filename=None, 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
|
||||
route on top of this. The blockages from the gds/module will be
|
||||
considered.
|
||||
"""
|
||||
router_tech.__init__(self, layers, rail_track_width)
|
||||
|
||||
router_tech.__init__(self, layers, route_track_width)
|
||||
|
||||
self.cell = design
|
||||
|
||||
|
|
@ -1165,6 +1166,14 @@ class router(router_tech):
|
|||
|
||||
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
|
||||
def snap_to_grid(offset):
|
||||
|
|
|
|||
|
|
@ -16,13 +16,13 @@ class router_tech:
|
|||
"""
|
||||
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.
|
||||
This uses the preferreed directions.
|
||||
"""
|
||||
self.layers = layers
|
||||
self.rail_track_width = rail_track_width
|
||||
self.route_track_width = route_track_width
|
||||
|
||||
if len(self.layers) == 1:
|
||||
self.horiz_layer_name = self.vert_layer_name = self.layers[0]
|
||||
|
|
@ -55,7 +55,7 @@ class router_tech:
|
|||
"preferred_directions '{}' and '{}'.")
|
||||
|
||||
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.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
|
||||
|
||||
# We'll keep horizontal and vertical tracks the same for simplicity.
|
||||
self.track_width = max(self.horiz_track_width,self.vert_track_width)
|
||||
debug.info(1,"Track width: {:.3f}".format(self.track_width))
|
||||
self.track_space = max(self.horiz_layer_spacing,self.vert_layer_spacing)
|
||||
debug.info(1,"Track space: {:.3f}".format(self.track_space))
|
||||
self.track_width = max(self.horiz_track_width, self.vert_track_width)
|
||||
debug.info(1, "Track width: {:.3f}".format(self.track_width))
|
||||
self.track_space = max(self.horiz_layer_spacing, self.vert_layer_spacing)
|
||||
debug.info(1, "Track space: {:.3f}".format(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_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)
|
||||
self.layer_widths = [self.track_wire, 1, self.track_wire]
|
||||
|
|
@ -107,7 +107,7 @@ class router_tech:
|
|||
elif zindex==0:
|
||||
return self.horiz_layer_name
|
||||
else:
|
||||
debug.error("Invalid zindex {}".format(zindex),-1)
|
||||
debug.error("Invalid zindex {}".format(zindex), -1)
|
||||
|
||||
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_width = drc("minwidth_{0}".format(layer_name), self.rail_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_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.route_track_width * min_wire_width, math.inf)
|
||||
|
||||
return (min_width,min_spacing)
|
||||
return (min_width, min_spacing)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
from itertools import tee
|
||||
import debug
|
||||
from heapq import heappush,heappop
|
||||
from copy import deepcopy
|
||||
|
|
@ -14,6 +13,7 @@ from grid import grid
|
|||
from grid_path import grid_path
|
||||
from vector3d import vector3d
|
||||
|
||||
|
||||
class signal_grid(grid):
|
||||
"""
|
||||
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()
|
||||
|
||||
# clear source and target pins
|
||||
self.source=[]
|
||||
self.target=[]
|
||||
self.source = set()
|
||||
self.target = set()
|
||||
|
||||
# Clear the queue
|
||||
while len(self.q)>0:
|
||||
while len(self.q) > 0:
|
||||
heappop(self.q)
|
||||
self.counter = 0
|
||||
|
||||
|
|
@ -49,19 +49,18 @@ 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.")
|
||||
#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
|
||||
for s in self.source:
|
||||
cost = self.cost_to_target(s)
|
||||
debug.info(3,"Init: cost=" + str(cost) + " " + str([s]))
|
||||
heappush(self.q,(cost,self.counter,grid_path([vector3d(s)])))
|
||||
debug.info(3, "Init: cost=" + str(cost) + " " + str([s]))
|
||||
heappush(self.q, (cost, self.counter, grid_path([vector3d(s)])))
|
||||
self.counter+=1
|
||||
|
||||
|
||||
def route(self,detour_scale):
|
||||
def route(self, detour_scale):
|
||||
"""
|
||||
This does the A* maze routing with preferred direction routing.
|
||||
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
|
||||
# over-ridden if the route fails due to pruning a feasible solution.
|
||||
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!
|
||||
for s in self.source:
|
||||
|
|
@ -83,20 +82,17 @@ class signal_grid(grid):
|
|||
|
||||
# Put the source items into the queue
|
||||
self.init_queue()
|
||||
cheapest_path = None
|
||||
cheapest_cost = None
|
||||
|
||||
|
||||
# Keep expanding and adding to the priority queue until we are done
|
||||
while len(self.q)>0:
|
||||
# should we keep the path in the queue as well or just the final node?
|
||||
(cost,count,curpath) = heappop(self.q)
|
||||
debug.info(3,"Queue size: size=" + str(len(self.q)) + " " + str(cost))
|
||||
debug.info(4,"Expanding: cost=" + str(cost) + " " + str(curpath))
|
||||
(cost, count, curpath) = heappop(self.q)
|
||||
debug.info(3, "Queue size: size=" + str(len(self.q)) + " " + str(cost))
|
||||
debug.info(4, "Expanding: cost=" + str(cost) + " " + str(curpath))
|
||||
|
||||
# expand the last element
|
||||
neighbors = self.expand_dirs(curpath)
|
||||
debug.info(4,"Neighbors: " + str(neighbors))
|
||||
debug.info(4, "Neighbors: " + str(neighbors))
|
||||
|
||||
for n in neighbors:
|
||||
# make a new copy of the path to not update the old ones
|
||||
|
|
@ -105,7 +101,7 @@ class signal_grid(grid):
|
|||
newpath.append(n)
|
||||
# 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
|
||||
return (newpath,newpath.cost())
|
||||
return (newpath, newpath.cost())
|
||||
else:
|
||||
# current path cost + predicted 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):
|
||||
self.map[n[0]].min_path = newpath
|
||||
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
|
||||
heappush(self.q,(predicted_cost,self.counter,newpath))
|
||||
heappush(self.q, (predicted_cost, self.counter, newpath))
|
||||
self.counter += 1
|
||||
#else:
|
||||
# print("Better previous cost.")
|
||||
#else:
|
||||
# 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
|
||||
but not expanding to blocked cells. Expands in all directions
|
||||
|
|
@ -142,33 +138,31 @@ class signal_grid(grid):
|
|||
|
||||
return unblocked_neighbors
|
||||
|
||||
|
||||
def hpwl(self, src, dest):
|
||||
"""
|
||||
Return half perimeter wire length from point to another.
|
||||
Either point can have positive or negative coordinates.
|
||||
Include the via penalty if there is one.
|
||||
"""
|
||||
hpwl = abs(src.x-dest.x)
|
||||
hpwl += abs(src.y-dest.y)
|
||||
hpwl = abs(src.x - dest.x)
|
||||
hpwl += abs(src.y - dest.y)
|
||||
if src.x!=dest.x and src.y!=dest.y:
|
||||
hpwl += grid.VIA_COST
|
||||
return hpwl
|
||||
|
||||
def cost_to_target(self,source):
|
||||
def cost_to_target(self, source):
|
||||
"""
|
||||
Find the cheapest HPWL distance to any target point ignoring
|
||||
blockages for A* search.
|
||||
"""
|
||||
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:
|
||||
cost = min(self.hpwl(source,t),cost)
|
||||
cost = min(self.hpwl(source, t), 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.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -5,15 +5,10 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import gdsMill
|
||||
import tech
|
||||
from contact import contact
|
||||
import math
|
||||
import debug
|
||||
from pin_layout import pin_layout
|
||||
from globals import OPTS
|
||||
from router import router
|
||||
|
||||
|
||||
class signal_router(router):
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
def create_routing_grid(self):
|
||||
"""
|
||||
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
|
||||
# of this many tracks
|
||||
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
|
||||
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):
|
||||
"""
|
||||
|
|
@ -47,13 +40,13 @@ class signal_router(router):
|
|||
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.
|
||||
"""
|
||||
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[dest] = []
|
||||
|
||||
# Clear the pins if we have previously routed
|
||||
if (hasattr(self,'rg')):
|
||||
if (hasattr(self, 'rg')):
|
||||
self.clear_pins()
|
||||
else:
|
||||
# Creat a routing grid over the entire area
|
||||
|
|
@ -67,8 +60,8 @@ class signal_router(router):
|
|||
# Block everything
|
||||
self.prepare_blockages()
|
||||
# Clear the pins we are routing
|
||||
self.set_blockages(self.pin_components[src],False)
|
||||
self.set_blockages(self.pin_components[dest],False)
|
||||
self.set_blockages(self.pin_components[src], False)
|
||||
self.set_blockages(self.pin_components[dest], False)
|
||||
|
||||
# Now add the src/tgt if they are not blocked by other shapes
|
||||
self.add_source(src)
|
||||
|
|
|
|||
|
|
@ -5,12 +5,8 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from vector3d import vector3d
|
||||
from grid import grid
|
||||
from signal_grid import signal_grid
|
||||
from grid_path import grid_path
|
||||
from direction import direction
|
||||
|
||||
|
||||
class supply_grid(signal_grid):
|
||||
|
|
@ -27,13 +23,14 @@ class supply_grid(signal_grid):
|
|||
|
||||
def reinit(self):
|
||||
""" Reinitialize everything for a new route. """
|
||||
|
||||
self.source = set()
|
||||
self.target = set()
|
||||
|
||||
# Reset all the cells in the map
|
||||
for p in self.map.values():
|
||||
p.reset()
|
||||
|
||||
|
||||
def find_start_wave(self, wave, direct):
|
||||
"""
|
||||
Finds the first loc starting at loc and up that is open.
|
||||
|
|
@ -46,8 +43,8 @@ class supply_grid(signal_grid):
|
|||
return None
|
||||
|
||||
while wave and self.is_wave_blocked(wave):
|
||||
wf=grid_path(wave)
|
||||
wave=wf.neighbor(direct)
|
||||
wf = grid_path(wave)
|
||||
wave = wf.neighbor(direct)
|
||||
# Bail out if we couldn't increment futher
|
||||
if wave[0].x > self.ur.x or wave[-1].y > self.ur.y:
|
||||
return None
|
||||
|
|
@ -57,7 +54,6 @@ class supply_grid(signal_grid):
|
|||
|
||||
return wave
|
||||
|
||||
|
||||
def is_wave_blocked(self, wave):
|
||||
"""
|
||||
Checks if any of the locations are blocked
|
||||
|
|
@ -68,7 +64,6 @@ class supply_grid(signal_grid):
|
|||
else:
|
||||
return False
|
||||
|
||||
|
||||
def probe(self, wave, direct):
|
||||
"""
|
||||
Expand the wave until there is a blockage and return
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@ class supply_grid_router(router):
|
|||
start_time = datetime.now()
|
||||
|
||||
# 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
|
||||
self.supply_rails = {}
|
||||
|
|
@ -47,7 +47,7 @@ class supply_grid_router(router):
|
|||
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.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"):
|
||||
"""
|
||||
|
|
@ -104,14 +104,6 @@ class supply_grid_router(router):
|
|||
|
||||
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):
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
# 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()
|
||||
self.supply_rails[name].append(grid_set)
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
# See LICENSE for licensing information.
|
||||
#
|
||||
#Copyright (c) 2016-2019 Regents of the University of California and The Board
|
||||
#of Regents for the Oklahoma Agricultural and Mechanical College
|
||||
#(acting for and on behalf of Oklahoma State University)
|
||||
#All rights reserved.
|
||||
# Copyright (c) 2016-2019 Regents of the University of California and The Board
|
||||
# of Regents for the Oklahoma Agricultural and Mechanical College
|
||||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
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).
|
||||
"""
|
||||
# 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):
|
||||
"""
|
||||
|
|
@ -37,8 +37,8 @@ class supply_tree_router(router):
|
|||
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.track_width)
|
||||
import signal_grid
|
||||
self.rg = signal_grid.signal_grid(self.ll, self.ur, self.route_track_width)
|
||||
|
||||
def route(self, vdd_name="vdd", gnd_name="gnd"):
|
||||
"""
|
||||
|
|
@ -85,15 +85,6 @@ class supply_tree_router(router):
|
|||
|
||||
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):
|
||||
"""
|
||||
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}
|
||||
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.
|
||||
|
|
@ -137,6 +127,7 @@ class supply_tree_router(router):
|
|||
remaining_components))
|
||||
|
||||
# Create full graph
|
||||
debug.info(2,"Creating adjacency matrix")
|
||||
pin_size = len(self.pin_groups[pin_name])
|
||||
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
|
||||
|
||||
# Find MST
|
||||
debug.info(2,"Finding MinimumSpanning Tree")
|
||||
X = csr_matrix(adj_matrix)
|
||||
Tcsr = minimum_spanning_tree(X)
|
||||
mst = Tcsr.toarray().astype(int)
|
||||
|
|
|
|||
|
|
@ -87,6 +87,17 @@ class sram():
|
|||
def save(self):
|
||||
""" 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:
|
||||
# Write the layout
|
||||
start_time = datetime.datetime.now()
|
||||
|
|
@ -107,17 +118,6 @@ class sram():
|
|||
self.lef_write(lefname)
|
||||
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
|
||||
start_time = datetime.datetime.now()
|
||||
lvsname = OPTS.output_path + self.s.name + ".lvs.sp"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
# (acting for and on behalf of Oklahoma State University)
|
||||
# All rights reserved.
|
||||
#
|
||||
import debug
|
||||
from vector import vector
|
||||
from sram_base import sram_base
|
||||
from contact import m2_via
|
||||
|
|
@ -102,12 +101,17 @@ class sram_1bank(sram_base):
|
|||
|
||||
# Place with an initial wide channel (from above)
|
||||
self.place_dffs()
|
||||
|
||||
# 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.remove_layout_pins()
|
||||
|
||||
# Re-place with the new channel size
|
||||
self.place_dffs()
|
||||
# Now route the channel
|
||||
self.route_dffs()
|
||||
|
||||
def place_row_addr_dffs(self):
|
||||
"""
|
||||
|
|
@ -298,15 +302,20 @@ class sram_1bank(sram_base):
|
|||
"din{0}[{1}]".format(port, bit))
|
||||
|
||||
# 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):
|
||||
# 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())
|
||||
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:
|
||||
|
|
@ -384,6 +393,8 @@ class sram_1bank(sram_base):
|
|||
|
||||
self.route_row_addr_dff()
|
||||
|
||||
self.route_dffs()
|
||||
|
||||
def route_dffs(self, add_routes=True):
|
||||
|
||||
for port in self.all_ports:
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ num_words = 16
|
|||
|
||||
tech_name = OPTS.tech_name
|
||||
|
||||
# perimeter_pins = True
|
||||
|
||||
nominal_corner_only = True
|
||||
route_supplies = "tree"
|
||||
route_supplies = "grid"
|
||||
check_lvsdrc = True
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ from tech import lvs_name
|
|||
from tech import pex_name
|
||||
|
||||
debug.info(1, "Initializing verify...")
|
||||
|
||||
if not OPTS.check_lvsdrc:
|
||||
debug.info(1, "LVS/DRC/PEX disabled.")
|
||||
OPTS.drc_exe = None
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ num_pex_runs = 0
|
|||
|
||||
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. """
|
||||
|
||||
global OPTS
|
||||
|
||||
# Copy .magicrc file into the output directory
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ lvs_warned = False
|
|||
pex_warned = False
|
||||
|
||||
|
||||
def write_drc_script(cell_name, gds_name, extract, final_verification=False, output_path=None):
|
||||
pass
|
||||
def write_drc_script(cell_name, gds_name, extract, final_verification=False, output_path=None, sp_name=None):
|
||||
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):
|
||||
|
|
|
|||
Loading…
Reference in New Issue