Add sketch for power grid routing code

This commit is contained in:
Matt Guthaus
2018-08-28 10:43:44 -07:00
parent 718897e123
commit ea52af3747
94 changed files with 1326 additions and 197 deletions
+1 -1
View File
@@ -275,7 +275,7 @@ def setup_paths():
# Add all of the subdirs to the python path
# These subdirs are modules and don't need to be added: characterizer, verify
for subdir in ["gdsMill", "tests", "router", "modules", "base", "pgates"]:
for subdir in ["gdsMill", "tests", "modules", "base", "pgates"]:
full_path = "{0}/{1}".format(OPENRAM_HOME,subdir)
debug.check(os.path.isdir(full_path),
"$OPENRAM_HOME/{0} does not exist: {1}".format(subdir,full_path))
-45
View File
@@ -1,45 +0,0 @@
class cell:
"""
A single cell that can be occupied in a given layer, blocked,
visited, etc.
"""
def __init__(self):
self.visited = False
self.path = False
self.blocked = False
self.source = False
self.target = False
# -1 means it isn't visited yet
self.min_cost = -1
def reset(self):
"""
Reset the dynamic info about routing. The pins/blockages are not reset so
that they can be reused.
"""
self.visited=False
self.min_cost=-1
self.min_path=None
self.blocked=False
self.source=False
self.target=False
def get_type(self):
if self.blocked:
return "X"
if self.source:
return "S"
if self.target:
return "T"
if self.path:
return "P"
# We can display the cost of the frontier
if self.min_cost > 0:
return self.min_cost
return None
-299
View File
@@ -1,299 +0,0 @@
import numpy as np
import string
from itertools import tee
import debug
from vector3d import vector3d
from cell import cell
import os
try:
import Queue as Q # ver. < 3.0
except ImportError:
import queue as Q
class grid:
"""A two layer routing map. Each cell can be blocked in the vertical
or horizontal layer.
"""
def __init__(self):
""" Create a routing map of width x height cells and 2 in the z-axis. """
# costs are relative to a unit grid
# non-preferred cost allows an off-direction jog of 1 grid
# rather than 2 vias + preferred direction (cost 5)
self.VIA_COST = 2
self.NONPREFERRED_COST = 4
self.PREFERRED_COST = 1
# list of the source/target grid coordinates
self.source = []
self.target = []
# let's leave the map sparse, cells are created on demand to reduce memory
self.map={}
# priority queue for the maze routing
self.q = Q.PriorityQueue()
def set_blocked(self,n):
self.add_map(n)
self.map[n].blocked=True
def is_blocked(self,n):
self.add_map(n)
return self.map[n].blocked
def set_source(self,n):
self.add_map(n)
self.map[n].source=True
self.source.append(n)
def set_target(self,n):
self.add_map(n)
self.map[n].target=True
self.target.append(n)
def reinit(self):
""" Reinitialize everything for a new route. """
self.reset_cells()
# clear source and target pins
self.source=[]
self.target=[]
# clear the queue
while (not self.q.empty()):
self.q.get(False)
def add_blockage_shape(self,ll,ur,z):
debug.info(3,"Adding blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
for x in range(int(ll[0]),int(ur[0])+1):
for y in range(int(ll[1]),int(ur[1])+1):
n = vector3d(x,y,z)
self.set_blocked(n)
def add_blockage(self,block_list):
debug.info(3,"Adding blockage list={0}".format(str(block_list)))
for n in block_list:
self.set_blocked(n)
def add_source(self,track_list):
debug.info(3,"Adding source list={0}".format(str(track_list)))
for n in track_list:
if not self.is_blocked(n):
self.set_source(n)
def add_target(self,track_list):
debug.info(3,"Adding target list={0}".format(str(track_list)))
for n in track_list:
if not self.is_blocked(n):
self.set_target(n)
def reset_cells(self):
"""
Reset the path and costs for all the grid cells.
"""
for p in self.map.values():
p.reset()
def add_path(self,path):
"""
Mark the path in the routing grid for visualization
"""
self.path=path
for p in path:
self.map[p].path=True
def route(self,detour_scale):
"""
This does the A* maze routing with preferred direction routing.
"""
# 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.
cost_bound = detour_scale*self.cost_to_target(self.source[0])*self.PREFERRED_COST
# Make sure the queue is empty if we run another route
while not self.q.empty():
self.q.get()
# 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 not self.q.empty():
# should we keep the path in the queue as well or just the final node?
(cost,path) = self.q.get()
debug.info(2,"Queue size: size=" + str(self.q.qsize()) + " " + str(cost))
debug.info(3,"Expanding: cost=" + str(cost) + " " + str(path))
# expand the last element
neighbors = self.expand_dirs(path)
debug.info(3,"Neighbors: " + str(neighbors))
for n in neighbors:
# node is added to the map by the expand routine
newpath = path + [n]
# check if we hit the target and are done
if self.is_target(n):
return (newpath,self.cost(newpath))
elif not self.map[n].visited:
# current path cost + predicted cost
current_cost = self.cost(newpath)
target_cost = self.cost_to_target(n)
predicted_cost = current_cost + target_cost
# only add the cost if it is less than our bound
if (predicted_cost < cost_bound):
if (self.map[n].min_cost==-1 or current_cost<self.map[n].min_cost):
self.map[n].visited=True
self.map[n].min_path = newpath
self.map[n].min_cost = predicted_cost
debug.info(3,"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
self.q.put((predicted_cost,newpath))
debug.warning("Unable to route path. Expand the detour_scale to allow detours.")
return (None,None)
def is_target(self,point):
"""
Point is in the target set, so we are done.
"""
return point in self.target
def expand_dirs(self,path):
"""
Expand each of the four cardinal directions plus up or down
but not expanding to blocked cells. Expands in all directions
regardless of preferred directions.
"""
# expand from the last point
point = path[-1]
neighbors = []
east = point + vector3d(1,0,0)
if not self.is_blocked(east) and not east in path:
neighbors.append(east)
west= point + vector3d(-1,0,0)
if not self.is_blocked(west) and not west in path:
neighbors.append(west)
up = point + vector3d(0,0,1)
if up.z<2 and not self.is_blocked(up) and not up in path:
neighbors.append(up)
north = point + vector3d(0,1,0)
if not self.is_blocked(north) and not north in path:
neighbors.append(north)
south = point + vector3d(0,-1,0)
if not self.is_blocked(south) and not south in path:
neighbors.append(south)
down = point + vector3d(0,0,-1)
if down.z>=0 and not self.is_blocked(down) and not down in path:
neighbors.append(down)
return neighbors
def add_map(self,p):
"""
Add a point to the map if it doesn't exist.
"""
if p not in self.map.keys():
self.map[p]=cell()
def init_queue(self):
"""
Populate the queue with all the source pins with cost
to the target. Each item is a path of the grid cells.
We will use an A* search, so this cost must be pessimistic.
Cost so far will be the length of the path.
"""
debug.info(4,"Initializing queue.")
# uniquify the source (and target while we are at it)
self.source = list(set(self.source))
self.target = list(set(self.target))
for s in self.source:
cost = self.cost_to_target(s)
debug.info(4,"Init: cost=" + str(cost) + " " + str([s]))
self.q.put((cost,[s]))
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 = max(abs(src.x-dest.x),abs(dest.x-src.x))
hpwl += max(abs(src.y-dest.y),abs(dest.y-src.y))
hpwl += max(abs(src.z-dest.z),abs(dest.z-src.z))
if src.x!=dest.x or src.y!=dest.y:
hpwl += self.VIA_COST
return hpwl
def cost_to_target(self,source):
"""
Find the cheapest HPWL distance to any target point ignoring
blockages for A* search.
"""
cost = self.hpwl(source,self.target[0])
for t in self.target:
cost = min(self.hpwl(source,t),cost)
return cost
def cost(self,path):
"""
The cost of the path is the length plus a penalty for the number
of vias. We assume that non-preferred direction is penalized.
"""
# Ignore the source pin layer change, FIXME?
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
plist = pairwise(path)
cost = 0
for p0,p1 in plist:
if p0.z != p1.z: # via
cost += self.VIA_COST
elif p0.x != p1.x: # horizontal
cost += self.NONPREFERRED_COST if (p0.z == 1) else self.PREFERRED_COST
elif p0.y != p1.y: # vertical
cost += self.NONPREFERRED_COST if (p0.z == 0) else self.PREFERRED_COST
else:
debug.error("Non-changing direction!")
return cost
def get_inertia(self,p0,p1):
"""
Sets the direction based on the previous direction we came from.
"""
# direction (index) of movement
if p0.x==p1.x:
return 1
elif p0.y==p1.y:
return 0
else:
# z direction
return 2
-3
View File
@@ -1,3 +0,0 @@
#!/bin/bash
python tests/regress.py -t freepdk45
python tests/regress.py -t scn3me_subm
-631
View File
@@ -1,631 +0,0 @@
import gdsMill
import tech
from contact import contact
import math
import debug
import grid
from vector import vector
from vector3d import vector3d
from globals import OPTS
class router:
"""A router class to read an obstruction map from a gds and plan a
route on a given layer. This is limited to two layer routes.
"""
def __init__(self, gds_name):
"""Use the gds file for the blockages with the top module topName and
layers for the layers to route on
"""
# Load the gds file and read in all the shapes
self.gds_name = gds_name
self.layout = gdsMill.VlsiLayout(units=tech.GDS["unit"])
self.reader = gdsMill.Gds2reader(self.layout)
self.reader.loadFromFile(gds_name)
self.top_name = self.layout.rootStructureName
self.source_pin_shapes = []
self.source_pin_zindex = None
self.target_pin_shapes = []
self.target_pin_zindex = None
# the list of all blockage shapes
self.blockages = []
# all thepaths we've routed so far (to supplement the blockages)
self.paths = []
# The boundary will determine the limits to the size of the routing grid
self.boundary = self.layout.measureBoundary(self.top_name)
self.ll = vector(self.boundary[0])
self.ur = vector(self.boundary[1])
def set_top(self,top_name):
""" If we want to route something besides the top-level cell."""
self.top_name = top_name
def set_layers(self, layers):
"""Allows us to change the layers that we are routing on. First layer
is always horizontal, middle is via, and last is always
vertical.
"""
self.layers = layers
(horiz_layer, via_layer, vert_layer) = self.layers
self.vert_layer_name = vert_layer
self.vert_layer_width = tech.drc["minwidth_{0}".format(vert_layer)]
self.vert_layer_spacing = tech.drc[str(self.vert_layer_name)+"_to_"+str(self.vert_layer_name)]
self.vert_layer_number = tech.layer[vert_layer]
self.horiz_layer_name = horiz_layer
self.horiz_layer_width = tech.drc["minwidth_{0}".format(horiz_layer)]
self.horiz_layer_spacing = tech.drc[str(self.horiz_layer_name)+"_to_"+str(self.horiz_layer_name)]
self.horiz_layer_number = tech.layer[horiz_layer]
# Contacted track spacing.
via_connect = contact(self.layers, (1, 1))
self.max_via_size = max(via_connect.width,via_connect.height)
self.horiz_track_width = self.max_via_size + self.horiz_layer_spacing
self.vert_track_width = self.max_via_size + 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: "+str(self.track_width))
self.track_widths = [self.track_width] * 2
self.track_factor = [1/self.track_width] * 2
debug.info(1,"Track factor: {0}".format(self.track_factor))
def create_routing_grid(self):
"""
Create a routing grid that spans given area. Wires cannot exist outside region.
"""
# 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))
self.rg = grid.grid()
def find_pin(self,pin):
"""
Finds the pin shapes and converts to tracks.
Pin can either be a label or a location,layer pair: [[x,y],layer].
"""
if type(pin)==str:
(pin_name,pin_layer,pin_shapes) = self.layout.getAllPinShapesByLabel(str(pin))
else:
(pin_name,pin_layer,pin_shapes) = self.layout.getAllPinShapesByLocLayer(pin[0],pin[1])
new_pin_shapes = []
for pin_shape in pin_shapes:
debug.info(2,"Find pin {0} layer {1} shape {2}".format(pin_name,str(pin_layer),str(pin_shape)))
# repack the shape as a pair of vectors rather than four values
new_pin_shapes.append([vector(pin_shape[0],pin_shape[1]),vector(pin_shape[2],pin_shape[3])])
debug.check(len(new_pin_shapes)>0,"Did not find any pin shapes for {0}.".format(str(pin)))
return (pin_layer,new_pin_shapes)
def find_blockages(self):
"""
Iterate through all the layers and write the obstacles to the routing grid.
This doesn't consider whether the obstacles will be pins or not. They get reset later
if they are not actually a blockage.
"""
for layer in self.layers:
self.get_blockages(self.top_name)
def clear_pins(self):
"""
Reset the source and destination pins to start a new routing.
Convert the source/dest pins to blockages.
Convert the routed path to blockages.
Keep the other blockages unchanged.
"""
self.source_pin = None
self.source_pin_shapes = []
self.source_pin_zindex = None
self.target_pin = None
self.target_pin_shapes = []
self.target_pin_zindex = None
# DO NOT clear the blockages as these don't change
self.rg.reinit()
def route(self, cell, layers, src, dest, detour_scale=2):
"""
Route a single source-destination net and return
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.
"""
self.cell = cell
# Clear the pins if we have previously routed
if (hasattr(self,'rg')):
self.clear_pins()
else:
# Set up layers and track sizes
self.set_layers(layers)
# Creat a routing grid over the entire area
# FIXME: This could be created only over the routing region,
# but this is simplest for now.
self.create_routing_grid()
# This will get all shapes as blockages
self.find_blockages()
# Get the pin shapes
self.get_source(src)
self.get_target(dest)
# Now add the blockages (all shapes except the src/tgt pins)
self.add_blockages()
# Add blockages from previous paths
self.add_path_blockages()
# Now add the src/tgt if they are not blocked by other shapes
self.add_source()
self.add_target()
# returns the path in tracks
(path,cost) = self.rg.route(detour_scale)
if path:
debug.info(1,"Found path: cost={0} ".format(cost))
debug.info(2,str(path))
self.add_route(path)
return True
else:
self.write_debug_gds()
# clean up so we can try a reroute
self.clear_pins()
return False
def write_debug_gds(self,):
"""
Write out a GDS file with the routing grid and search information annotated on it.
"""
# Only add the debug info to the gds file if we have any debugging on.
# This is because we may reroute a wire with detours and don't want the debug information.
if OPTS.debug_level==0: return
self.add_router_info()
debug.error("Writing debug_route.gds from {0} to {1}".format(self.source_pin,self.target_pin))
self.cell.gds_write("debug_route.gds")
def add_router_info(self):
"""
Write the routing grid and router cost, blockage, pins on
the boundary layer for debugging purposes. This can only be
called once or the labels will overlap.
"""
debug.info(0,"Adding router info for {0} to {1}".format(self.source_pin,self.target_pin))
grid_keys=self.rg.map.keys()
partial_track=vector(0,self.track_width/6.0)
for g in grid_keys:
shape = self.convert_full_track_to_shape(g)
self.cell.add_rect(layer="boundary",
offset=shape[0],
width=shape[1].x-shape[0].x,
height=shape[1].y-shape[0].y)
# These are the on grid pins
#rect = self.convert_track_to_pin(g)
#self.cell.add_rect(layer="boundary",
# offset=rect[0],
# width=rect[1].x-rect[0].x,
# height=rect[1].y-rect[0].y)
t=self.rg.map[g].get_type()
# midpoint offset
off=vector((shape[1].x+shape[0].x)/2,
(shape[1].y+shape[0].y)/2)
if g[2]==1:
# Upper layer is upper right label
type_off=off+partial_track
else:
# Lower layer is lower left label
type_off=off-partial_track
if t!=None:
self.cell.add_label(text=str(t),
layer="text",
offset=type_off)
self.cell.add_label(text="{0},{1}".format(g[0],g[1]),
layer="text",
offset=shape[0])
def add_route(self,path):
"""
Add the current wire route to the given design instance.
"""
debug.info(3,"Set path: " + str(path))
# Keep track of path for future blockages
self.paths.append(path)
# This is marked for debug
self.rg.add_path(path)
# For debugging... if the path failed to route.
if False or path==None:
self.write_debug_gds()
if 'Xout_4_1' in [self.source_pin, self.target_pin]:
self.write_debug_gds()
# First, simplify the path for
#debug.info(1,str(self.path))
contracted_path = self.contract_path(path)
debug.info(1,str(contracted_path))
# Make sure there's a pin enclosure on the source and dest
add_src_via = contracted_path[0].z!=self.source_pin_zindex
self.add_grid_pin(contracted_path[0],add_src_via)
add_tgt_via = contracted_path[-1].z!=self.target_pin_zindex
self.add_grid_pin(contracted_path[-1],add_tgt_via)
# convert the path back to absolute units from tracks
abs_path = map(self.convert_point_to_units,contracted_path)
debug.info(1,str(abs_path))
self.cell.add_route(self.layers,abs_path)
def add_grid_pin(self,point,add_via=False):
"""
Create a rectangle at the grid 3D point that is 1/2 DRC smaller
than the routing grid on all sides.
"""
pin = self.convert_track_to_pin(point)
self.cell.add_rect(layer=self.layers[2*point.z],
offset=pin[0],
width=pin[1].x-pin[0].x,
height=pin[1].y-pin[0].y)
if add_via:
# offset this by 1/2 the via size
c=contact(self.layers, (1, 1))
via_offset = vector(-0.5*c.width,-0.5*c.height)
self.cell.add_via(self.layers,vector(point[0],point[1])+via_offset)
def create_steiner_routes(self,pins):
"""
Find a set of steiner points and then return the list of
point-to-point routes.
"""
pass
def find_steiner_points(self,pins):
"""
Find the set of steiner points and return them.
"""
pass
def translate_coordinates(self, coord, mirr, angle, xyShift):
"""
Calculate coordinates after flip, rotate, and shift
"""
coordinate = []
for item in coord:
x = (item[0]*math.cos(angle)-item[1]*mirr*math.sin(angle)+xyShift[0])
y = (item[0]*math.sin(angle)+item[1]*mirr*math.cos(angle)+xyShift[1])
coordinate += [(x, y)]
return coordinate
def convert_shape_to_units(self, shape):
"""
Scale a shape (two vector list) to user units
"""
unit_factor = [tech.GDS["unit"][0]] * 2
ll=shape[0].scale(unit_factor)
ur=shape[1].scale(unit_factor)
return [ll,ur]
def min_max_coord(self, coord):
"""
Find the lowest and highest corner of a Rectangle
"""
coordinate = []
minx = min(coord[0][0], coord[1][0], coord[2][0], coord[3][0])
maxx = max(coord[0][0], coord[1][0], coord[2][0], coord[3][0])
miny = min(coord[0][1], coord[1][1], coord[2][1], coord[3][1])
maxy = max(coord[0][1], coord[1][1], coord[2][1], coord[3][1])
coordinate += [vector(minx, miny)]
coordinate += [vector(maxx, maxy)]
return coordinate
def get_inertia(self,p0,p1):
"""
Sets the direction based on the previous direction we came from.
"""
# direction (index) of movement
if p0.x!=p1.x:
return 0
elif p0.y!=p1.y:
return 1
else:
# z direction
return 2
def contract_path(self,path):
"""
Remove intermediate points in a rectilinear path.
"""
newpath = [path[0]]
for i in range(1,len(path)-1):
prev_inertia=self.get_inertia(path[i-1],path[i])
next_inertia=self.get_inertia(path[i],path[i+1])
# if we switch directions, add the point, otherwise don't
if prev_inertia!=next_inertia:
newpath.append(path[i])
# always add the last path
newpath.append(path[-1])
return newpath
def add_path_blockages(self):
"""
Go through all of the past paths and add them as blockages.
This is so we don't have to write/reload the GDS.
"""
for path in self.paths:
for grid in path:
self.rg.set_blocked(grid)
def get_source(self,pin):
"""
Gets the source pin shapes only. Doesn't add to grid.
"""
self.source_pin = pin
(self.source_pin_layer,self.source_pin_shapes) = self.find_pin(pin)
zindex = 0 if self.source_pin_layer==self.horiz_layer_number else 1
self.source_pin_zindex = zindex
def add_source(self):
"""
Mark the grids that are in the pin rectangle ranges to have the source property.
pin can be a location or a label.
"""
found_pin = False
for shape in self.source_pin_shapes:
(pin_in_tracks,blockage_in_tracks)=self.convert_pin_to_tracks(shape,self.source_pin_zindex,self.source_pin)
if (len(pin_in_tracks)>0): found_pin=True
debug.info(1,"Set source: " + str(self.source_pin) + " " + str(pin_in_tracks) + " z=" + str(self.source_pin_zindex))
self.rg.add_source(pin_in_tracks)
self.rg.add_blockage(blockage_in_tracks)
if not found_pin:
self.write_debug_gds()
debug.check(found_pin,"Unable to find source pin on grid.")
def get_target(self,pin):
"""
Gets the target pin shapes only. Doesn't add to grid.
"""
self.target_pin = pin
(self.target_pin_layer,self.target_pin_shapes) = self.find_pin(pin)
zindex = 0 if self.target_pin_layer==self.horiz_layer_number else 1
self.target_pin_zindex = zindex
def add_target(self):
"""
Mark the grids that are in the pin rectangle ranges to have the target property.
pin can be a location or a label.
"""
found_pin=False
for shape in self.target_pin_shapes:
(pin_in_tracks,blockage_in_tracks)=self.convert_pin_to_tracks(shape,self.target_pin_zindex,self.target_pin)
if (len(pin_in_tracks)>0): found_pin=True
debug.info(1,"Set target: " + str(self.target_pin) + " " + str(pin_in_tracks) + " z=" + str(self.target_pin_zindex))
self.rg.add_target(pin_in_tracks)
self.rg.add_blockage(blockage_in_tracks)
if not found_pin:
self.write_debug_gds()
debug.check(found_pin,"Unable to find target pin on grid.")
def add_blockages(self):
""" Add the blockages except the pin shapes """
for blockage in self.blockages:
(shape,zlayer) = blockage
# Skip source pin shapes
if zlayer==self.source_pin_zindex and shape in self.source_pin_shapes:
continue
# Skip target pin shapes
if zlayer==self.target_pin_zindex and shape in self.target_pin_shapes:
continue
[ll,ur]=self.convert_blockage_to_tracks(shape)
self.rg.add_blockage_shape(ll,ur,zlayer)
def get_blockages(self, sref, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0)):
"""
Recursive find boundaries as blockages to the routing grid.
Recurses for each Structure in GDS.
"""
for boundary in self.layout.structures[sref].boundaries:
coord_trans = self.translate_coordinates(boundary.coordinates, mirr, angle, xyShift)
shape_coords = self.min_max_coord(coord_trans)
shape = self.convert_shape_to_units(shape_coords)
# only consider the two layers that we are routing on
if boundary.drawingLayer in [self.vert_layer_number,self.horiz_layer_number]:
zlayer = 0 if boundary.drawingLayer==self.horiz_layer_number else 1
self.blockages.append((shape,zlayer))
# recurse given the mirror, angle, etc.
for cur_sref in self.layout.structures[sref].srefs:
sMirr = 1
if cur_sref.transFlags[0] == True:
sMirr = -1
sAngle = math.radians(float(0))
if cur_sref.rotateAngle:
sAngle = math.radians(float(cur_sref.rotateAngle))
sAngle += angle
x = cur_sref.coordinates[0]
y = cur_sref.coordinates[1]
newX = (x)*math.cos(angle) - mirr*(y)*math.sin(angle) + xyShift[0]
newY = (x)*math.sin(angle) + mirr*(y)*math.cos(angle) + xyShift[1]
sxyShift = (newX, newY)
self.get_blockages(cur_sref.sName, sMirr, sAngle, sxyShift)
def convert_point_to_units(self,p):
"""
Convert a path set of tracks to center line path.
"""
pt = vector3d(p)
pt=pt.scale(self.track_widths[0],self.track_widths[1],1)
return pt
def convert_blockage_to_tracks(self,shape,round_bigger=False):
"""
Convert a rectangular blockage shape into track units.
"""
[ll,ur] = shape
ll = snap_to_grid(ll)
ur = snap_to_grid(ur)
# to scale coordinates to tracks
#debug.info(1,"Converting [ {0} , {1} ]".format(ll,ur))
ll=ll.scale(self.track_factor)
ur=ur.scale(self.track_factor)
ll = ll.floor() if round_bigger else ll.round()
ur = ur.ceil() if round_bigger else ur.round()
#debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur))
return [ll,ur]
def convert_pin_to_tracks(self,shape,zindex,pin):
"""
Convert a rectangular pin shape into a list of track locations,layers.
If no on-grid pins are found, it searches for the nearest off-grid pin(s).
If a pin has insufficent overlap, it returns the blockage list to avoid it.
"""
[ll,ur] = shape
ll = snap_to_grid(ll)
ur = snap_to_grid(ur)
#debug.info(1,"Converting [ {0} , {1} ]".format(ll,ur))
# scale the size bigger to include neaby tracks
ll=ll.scale(self.track_factor).floor()
ur=ur.scale(self.track_factor).ceil()
# width depends on which layer it is
if zindex==0:
width = self.horiz_layer_width
else:
width = self.vert_layer_width
track_list = []
block_list = []
# include +- 1 so when a shape is less than one grid
for x in range(ll[0]-1,ur[0]+1):
for y in range(ll[1]-1,ur[1]+1):
#debug.info(1,"Converting [ {0} , {1} ]".format(x,y))
# get the rectangular pin at a track location
# if dimension of overlap is greater than min width in any dimension,
# it will be an on-grid pin
rect = self.convert_track_to_pin(vector3d(x,y,zindex))
max_overlap=max(self.compute_overlap(shape,rect))
# however, if there is not enough overlap, then if there is any overlap at all,
# we need to block it to prevent routes coming in on that grid
full_rect = self.convert_full_track_to_shape(vector3d(x,y,zindex))
full_overlap=max(self.compute_overlap(shape,full_rect))
#debug.info(1,"Check overlap: {0} {1} max={2}".format(shape,rect,max_overlap))
if max_overlap >= width:
track_list.append(vector3d(x,y,zindex))
elif full_overlap>0:
block_list.append(vector3d(x,y,zindex))
else:
debug.info(1,"No overlap: {0} {1} max={2}".format(shape,rect,max_overlap))
#debug.warning("Off-grid pin for {0}.".format(str(pin)))
#debug.info(1,"Converted [ {0} , {1} ]".format(ll,ur))
return (track_list,block_list)
def compute_overlap(self,r1,r2):
""" Calculate the rectangular overlap of two rectangles. """
(r1_ll,r1_ur) = r1
(r2_ll,r2_ur) = r2
#ov_ur = vector(min(r1_ur.x,r2_ur.x),min(r1_ur.y,r2_ur.y))
#ov_ll = vector(max(r1_ll.x,r2_ll.x),max(r1_ll.y,r2_ll.y))
dy = min(r1_ur.y,r2_ur.y)-max(r1_ll.y,r2_ll.y)
dx = min(r1_ur.x,r2_ur.x)-max(r1_ll.x,r2_ll.x)
if dx>0 and dy>0:
return [dx,dy]
else:
return [0,0]
def convert_track_to_pin(self,track):
"""
Convert a grid point into a rectangle shape that is centered
track in the track and leaves half a DRC space in each direction.
"""
# space depends on which layer it is
if track[2]==0:
space = 0.5*self.horiz_layer_spacing
else:
space = 0.5*self.vert_layer_spacing
# calculate lower left
x = track.x*self.track_width - 0.5*self.track_width + space
y = track.y*self.track_width - 0.5*self.track_width + space
ll = snap_to_grid(vector(x,y))
# calculate upper right
x = track.x*self.track_width + 0.5*self.track_width - space
y = track.y*self.track_width + 0.5*self.track_width - space
ur = snap_to_grid(vector(x,y))
return [ll,ur]
def convert_full_track_to_shape(self,track):
"""
Convert a grid point into a rectangle shape that occupies the entire centered
track.
"""
# to scale coordinates to tracks
x = track.x*self.track_width - 0.5*self.track_width
y = track.y*self.track_width - 0.5*self.track_width
# offset lowest corner object to to (-track halo,-track halo)
ll = snap_to_grid(vector(x,y))
ur = snap_to_grid(ll + vector(self.track_width,self.track_width))
return [ll,ur]
# FIXME: This should be replaced with vector.snap_to_grid at some point
def snap_to_grid(offset):
"""
Changes the coodrinate to match the grid settings
"""
grid = tech.drc["grid"]
x = offset[0]
y = offset[1]
# this gets the nearest integer value
xgrid = int(round(round((x / grid), 2), 0))
ygrid = int(round(round((y / grid), 2), 0))
xoff = xgrid * grid
yoff = ygrid * grid
return vector(xoff, yoff)
@@ -1,80 +0,0 @@
#!/usr/bin/env python2.7
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],"../.."))
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.OPTS
class no_blockages_test(unittest.TestCase):
"""
Simplest two pin route test with no blockages.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
import design
import router
class gdscell(design.design):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
#design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
self.name = name
self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name)
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
r = routing("01_no_blockages_test_{0}".format(OPTS.tech_name))
self.local_check(r)
# fails if there are any DRC errors on any cells
globals.end_openram()
def local_check(self, r):
tempgds = OPTS.openram_temp + "temp.gds"
r.gds_write(tempgds)
self.assertFalse(calibre.run_drc(r.name, tempgds))
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()
-3
View File
@@ -1,3 +0,0 @@
.SUBCKT cell
.ENDS cell
@@ -1,80 +0,0 @@
#!/usr/bin/env python2.7
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],"../.."))
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.OPTS
class blockages_test(unittest.TestCase):
"""
Simple two pin route test with multilayer blockages.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
import design
import router
class gdscell(design.design):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
#design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
self.name = name
self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name)
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
r = routing("02_blockages_test_{0}".format(OPTS.tech_name))
self.local_check(r)
# fails if there are any DRC errors on any cells
globals.end_openram()
def local_check(self, r):
tempgds = OPTS.openram_temp + "temp.gds"
r.gds_write(tempgds)
self.assertFalse(calibre.run_drc(r.name, tempgds))
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()
-3
View File
@@ -1,3 +0,0 @@
.SUBCKT cell
.ENDS cell
@@ -1,80 +0,0 @@
#!/usr/bin/env python2.7
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],"../.."))
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.OPTS
class same_layer_pins_test(unittest.TestCase):
"""
Checks two pins on the same layer with positive and negative coordinates.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
import design
import router
class gdscell(design.design):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
#design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
self.name = name
self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name)
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
r = routing("03_same_layer_pins_test_{0}".format(OPTS.tech_name))
self.local_check(r)
# fails if there are any DRC errors on any cells
globals.end_openram()
def local_check(self, r):
tempgds = OPTS.openram_temp + "temp.gds"
r.gds_write(tempgds)
self.assertFalse(calibre.run_drc(r.name, tempgds))
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()
-3
View File
@@ -1,3 +0,0 @@
.SUBCKT cell
.ENDS cell
@@ -1,81 +0,0 @@
#!/usr/bin/env python2.7
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],"../.."))
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.OPTS
class diff_layer_pins_test(unittest.TestCase):
"""
Two pin route test with pins on different layers and blockages.
Pins are smaller than grid size.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
import design
import router
class gdscell(design.design):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
#design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
self.name = name
self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name)
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
r = routing("04_diff_layer_pins_test_{0}".format(OPTS.tech_name))
self.local_check(r)
# fails if there are any DRC errors on any cells
globals.end_openram()
def local_check(self, r):
tempgds = OPTS.openram_temp + "temp.gds"
r.gds_write(tempgds)
self.assertFalse(calibre.run_drc(r.name, tempgds))
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()
-3
View File
@@ -1,3 +0,0 @@
.SUBCKT cell
.ENDS cell
-82
View File
@@ -1,82 +0,0 @@
#!/usr/bin/env python2.7
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],"../.."))
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.OPTS
class two_nets_test(unittest.TestCase):
"""
Route two nets in the same GDS file. The routes will interact,
so they must block eachother.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
import design
import router
class gdscell(design.design):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
#design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
self.name = name
self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name)
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
self.assertTrue(r.route(self,layer_stack,src="A",dest="B"))
self.assertTrue(r.route(self,layer_stack,src="C",dest="D"))
r = routing("05_two_nets_test_{0}".format(OPTS.tech_name))
self.local_check(r)
# fails if there are any DRC errors on any cells
globals.end_openram()
def local_check(self, r):
tempgds = OPTS.openram_temp + "temp.gds"
r.gds_write(tempgds)
self.assertFalse(calibre.run_drc(r.name, tempgds))
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()
-3
View File
@@ -1,3 +0,0 @@
.SUBCKT cell
.ENDS cell
Binary file not shown.
@@ -1,88 +0,0 @@
#!/usr/bin/env python2.7
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],"../.."))
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.OPTS
class pin_location_test(unittest.TestCase):
"""
Simplest two pin route test with no blockages using the pin locations instead of labels.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
import design
import router
class gdscell(design.design):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
#design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
self.name = name
self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name)
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
# these are user coordinates and layers
src_pin = [[0.52, 4.099],11]
tgt_pin = [[3.533, 1.087],11]
#r.route(layer_stack,src="A",dest="B")
self.assertTrue(r.route(self,layer_stack,src=src_pin,dest=tgt_pin))
# This only works for freepdk45 since the coordinates are hard coded
if OPTS.tech_name == "freepdk45":
r = routing("06_pin_location_test_{0}".format(OPTS.tech_name))
self.local_check(r)
else:
debug.warning("This test does not support technology {0}".format(OPTS.tech_name))
# fails if there are any DRC errors on any cells
globals.end_openram()
def local_check(self, r):
tempgds = OPTS.openram_temp + "temp.gds"
r.gds_write(tempgds)
self.assertFalse(calibre.run_drc(r.name, tempgds))
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()
-106
View File
@@ -1,106 +0,0 @@
#!/usr/bin/env python2.7
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],"../.."))
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.OPTS
class big_test(unittest.TestCase):
"""
Simplest two pin route test with no blockages using the pin locations instead of labels.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
import design
import router
class gdscell(design.design):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
#design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
self.name = name
self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name)
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
r=router.router(self.gdsname)
layer_stack =("metal3","via2","metal2")
connections=[('out_0_2', 'a_0_0'),
('out_0_3', 'b_0_0'),
('out_0_0', 'a_0_1'),
('out_1_2', 'a_1_0'),
('out_1_3', 'b_1_0'),
('out_1_0', 'a_1_1'),
('out_2_1', 'a_2_0'),
('out_2_2', 'b_2_0'),
('out_3_1', 'a_3_0'),
('out_3_2', 'b_3_0'),
('out_4_6', 'a_4_0'),
('out_4_7', 'b_4_0'),
('out_4_8', 'a_4_2'),
('out_4_9', 'b_4_2'),
('out_4_10', 'a_4_4'),
('out_4_11', 'b_4_4'),
('out_4_0', 'a_4_1'),
('out_4_2', 'b_4_1'),
('out_4_4', 'a_4_5'),
('out_4_1', 'a_4_3'),
('out_4_5', 'b_4_3')]
for (src,tgt) in connections:
self.assertTrue(r.route(self,layer_stack,src=src,dest=tgt))
# This test only runs on scn3me_subm tech
if OPTS.tech_name=="scn3me_subm":
r = routing("07_big_test_{0}".format(OPTS.tech_name))
self.local_check(r)
else:
debug.warning("This test does not support technology {0}".format(OPTS.tech_name))
# fails if there are any DRC errors on any cells
globals.end_openram()
def local_check(self, r):
tempgds = OPTS.openram_temp + "temp.gds"
r.gds_write(tempgds)
self.assertFalse(calibre.run_drc(r.name, tempgds))
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()
Binary file not shown.
@@ -1,83 +0,0 @@
#!/usr/bin/env python2.7
"Run a regresion test the library cells for DRC"
import unittest
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],"../.."))
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.OPTS
class expand_region_test(unittest.TestCase):
"""
Test an infeasible route followed by a feasible route with an expanded region.
"""
def runTest(self):
globals.init_openram("config_{0}".format(OPTS.tech_name))
import design
import router
class gdscell(design.design):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
#design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
self.name = name
self.gds_file = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
self.sp_file = "{0}/{1}.sp".format(os.path.dirname(os.path.realpath(__file__)),name)
design.hierarchy_layout.layout.__init__(self, name)
design.hierarchy_spice.spice.__init__(self, name)
class routing(design.design,unittest.TestCase):
"""
A generic GDS design that we can route on.
"""
def __init__(self, name):
design.design.__init__(self, name)
debug.info(2, "Create {0} object".format(name))
cell = gdscell(name)
self.add_inst(name=name,
mod=cell,
offset=[0,0])
self.connect_inst([])
self.gdsname = "{0}/{1}.gds".format(os.path.dirname(os.path.realpath(__file__)),name)
r=router.router(self.gdsname)
layer_stack =("metal1","via1","metal2")
# This should be infeasible because it is blocked without a detour.
self.assertFalse(r.route(self,layer_stack,src="A",dest="B",detour_scale=1))
# This should be feasible because we allow it to detour
self.assertTrue(r.route(self,layer_stack,src="A",dest="B",detour_scale=3))
r = routing("08_expand_region_test_{0}".format(OPTS.tech_name))
self.local_check(r)
# fails if there are any DRC errors on any cells
globals.end_openram()
def local_check(self, r):
tempgds = OPTS.openram_temp + "temp.gds"
r.gds_write(tempgds)
self.assertFalse(calibre.run_drc(r.name, tempgds))
os.remove(tempgds)
# instantiate a copy of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()
-23
View File
@@ -1,23 +0,0 @@
word_size = 1
num_words = 16
num_banks = 1
tech_name = "freepdk45"
decoder = "hierarchical_decoder"
ms_flop = "ms_flop"
ms_flop_array = "ms_flop_array"
control_logic = "control_logic"
bitcell_array = "bitcell_array"
sense_amp = "sense_amp"
sense_amp_array = "sense_amp_array"
precharge_array = "precharge_array"
column_mux_array = "single_level_column_mux_array"
write_driver = "write_driver"
write_driver_array = "write_driver_array"
tri_gate = "tri_gate"
tri_gate_array = "tri_gate_array"
wordline_driver = "wordline_driver"
replica_bitcell = "replica_bitcell"
bitcell = "bitcell"
delay_chain = "logic_effort_dc"
@@ -1,23 +0,0 @@
word_size = 1
num_words = 16
num_banks = 1
tech_name = "scn3me_subm"
decoder = "hierarchical_decoder"
ms_flop = "ms_flop"
ms_flop_array = "ms_flop_array"
control_logic = "control_logic"
bitcell_array = "bitcell_array"
sense_amp = "sense_amp"
sense_amp_array = "sense_amp_array"
precharge_array = "precharge_array"
column_mux_array = "single_level_column_mux_array"
write_driver = "write_driver"
write_driver_array = "write_driver_array"
tri_gate = "tri_gate"
tri_gate_array = "tri_gate_array"
wordline_driver = "wordline_driver"
replica_bitcell = "replica_bitcell"
bitcell = "bitcell"
delay_chain = "logic_effort_dc"
-31
View File
@@ -1,31 +0,0 @@
#!/usr/bin/env python2.7
import re
import unittest
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
sys.path.append(os.path.join(sys.path[0],"../.."))
import globals
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
from testutils import header
header(__file__, OPTS.tech_name)
# get a list of all files in the tests directory
files = os.listdir(sys.path[0])
# assume any file that ends in "test.py" in it is a regression test
nametest = re.compile("test\.py$", re.IGNORECASE)
tests = filter(nametest.search, files)
tests.sort()
# import all of the modules
filenameToModuleName = lambda f: os.path.splitext(f)[0]
moduleNames = map(filenameToModuleName, tests)
modules = map(__import__, moduleNames)
suite = unittest.TestSuite()
load = unittest.defaultTestLoader.loadTestsFromModule
suite.addTests(map(load, modules))
unittest.TextTestRunner(verbosity=2).run(suite)
-43
View File
@@ -1,43 +0,0 @@
def isclose(value1,value2,error_tolerance=1e-2):
""" This is used to compare relative values. """
import debug
relative_diff = abs(value1 - value2) / max(value1,value2)
check = relative_diff <= error_tolerance
if not check:
debug.info(1,"NOT CLOSE {0} {1} relative diff={2}".format(value1,value2,relative_diff))
else:
debug.info(2,"CLOSE {0} {1} relative diff={2}".format(value1,value2,relative_diff))
return (check)
def isdiff(file1,file2):
""" This is used to compare two files and display the diff if they are different.. """
import debug
import filecmp
import difflib
check = filecmp.cmp(file1,file2)
if not check:
debug.info(2,"MISMATCH {0} {1}".format(file1,file2))
f1 = open(file1,"r")
s1 = f1.readlines()
f2 = open(file2,"r")
s2 = f2.readlines()
for line in difflib.unified_diff(s1, s2):
debug.error(line)
else:
debug.info(2,"MATCH {0} {1}".format(file1,file2))
return (check)
def header(filename, technology):
tst = "Running Test for:"
print "\n"
print " ______________________________________________________________________________ "
print "|==============================================================================|"
print "|=========" + tst.center(60) + "=========|"
print "|=========" + technology.center(60) + "=========|"
print "|=========" + filename.center(60) + "=========|"
import globals
OPTS = globals.get_opts()
print "|=========" + OPTS.openram_temp.center(60) + "=========|"
print "|==============================================================================|"
-138
View File
@@ -1,138 +0,0 @@
import debug
import math
class vector3d():
"""
This is the vector3d class to represent a 3D coordinate.
It needs to override several operators to support
concise vector3d operations, output, and other more complex
data structures like lists.
"""
def __init__(self, x, y=None, z=None):
""" init function support two init method"""
# will take single input as a coordinate
if y==None:
self.x = x[0]
self.y = x[1]
self.z = x[2]
#will take two inputs as the values of a coordinate
else:
self.x = x
self.y = y
self.z = z
self.tpl=(x,y,z)
def __str__(self):
""" override print function output """
return "vector3d:["+str(self.x)+", "+str(self.y)+", "+str(self.z)+"]"
def __repr__(self):
""" override print function output """
return "["+str(self.x)+", "+str(self.y)+", "+str(self.z)+"]"
def __setitem__(self, index, value):
"""
override setitem function
can set value by vector3d[index]=value
"""
if index==0:
self.x=value
elif index==1:
self.y=value
elif index==2:
self.z=value
else:
self.x=value[0]
self.y=value[1]
self.z=value[2]
def __getitem__(self, index):
"""
override getitem function
can get value by value=vector3d[index]
"""
if index==0:
return self.x
elif index==1:
return self.y
elif index==2:
return self.z
else:
return self
def __add__(self, other):
"""
Override + function (left add)
Can add by vector3d(x1,y1,z1)+vector(x2,y2,z2)
"""
return vector3d(self.x + other[0], self.y + other[1], self.z + other[2])
def __radd__(self, other):
"""
Override + function (right add)
"""
if other == 0:
return self
else:
return self.__add__(other)
def __sub__(self, other):
"""
Override - function (left)
"""
return vector3d(self.x - other[0], self.y - other[1], self.z - other[2])
def __hash__(self):
"""
Override - function (hash)
Note: This assumes that you DON'T CHANGE THE VECTOR or it will
break things.
"""
return hash(self.tpl)
def __rsub__(self, other):
"""
Override - function (right)
"""
return vector3d(other[0]- self.x, other[1] - self.y, other[2] - self.z)
def rotate(self):
""" pass a copy of rotated vector3d, without altering the vector3d! """
return vector3d(self.y,self.x,self.z)
def scale(self, x_factor, y_factor=None,z_factor=None):
""" pass a copy of scaled vector3d, without altering the vector3d! """
if y_factor==None:
z_factor=x_factor[2]
y_factor=x_factor[1]
x_factor=x_factor[0]
return vector3d(self.x*x_factor,self.y*y_factor,self.z*z_factor)
def rotate_scale(self, x_factor, y_factor=None, z_factor=None):
""" pass a copy of scaled vector3d, without altering the vector3d! """
if y_factor==None:
z_factor=x_factor[2]
y_factor=x_factor[1]
x_factor=x_factor[0]
return vector3d(self.y*x_factor,self.x*y_factor,self.z*z_factor)
def __eq__(self, other):
"""Override the default Equals behavior"""
if isinstance(other, self.__class__):
return self.__dict__ == other.__dict__
return False
def __ne__(self, other):
"""Override the default non-equality behavior"""
return not self.__eq__(other)
def max(self, other):
""" Max of both values """
return vector3d(max(self.x,other.x),max(self.y,other.y),max(self.z,other.z))
def min(self, other):
""" Min of both values """
return vector3d(min(self.x,other.x),min(self.y,other.y),min(self.z,other.z))
+79 -1
View File
@@ -4,6 +4,7 @@ import debug
from math import log,sqrt,ceil
import datetime
import getpass
import numpy as np
from vector import vector
from globals import OPTS, print_time
@@ -175,7 +176,6 @@ class sram_1bank(sram_base):
# the control logic to the bank
self.add_wire(("metal3","via2","metal2"),[row_addr_clk_pos, mid1_pos, mid2_pos, control_clk_buf_pos])
def route_vdd_gnd(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
@@ -192,6 +192,84 @@ class sram_1bank(sram_base):
self.copy_layout_pin(inst, "vdd")
self.copy_layout_pin(inst, "gnd")
def new_route_vdd_gnd(self):
""" Propagate all vdd/gnd pins up to this level for all modules """
# These are the instances that every bank has
top_instances = [self.bank_inst,
self.row_addr_dff_inst,
self.data_dff_inst,
self.control_logic_inst]
if self.col_addr_dff:
top_instances.append(self.col_addr_dff_inst)
# for inst in top_instances:
# self.copy_layout_pin(inst, "vdd")
# self.copy_layout_pin(inst, "gnd")
blockages=self.get_blockages("metal3", top_level=True)
# Gather all of the vdd/gnd pins
vdd_pins=[]
gnd_pins=[]
for inst in top_instances:
vdd_pins.extend([x for x in inst.get_pins("vdd") if x.layer == "metal3"])
gnd_pins.extend([x for x in inst.get_pins("gnd") if x.layer == "metal3"])
# Create candidate stripes on M3/M4
lowest=self.find_lowest_coords()
highest=self.find_highest_coords()
m3_y_coords = np.arange(lowest[1],highest[1],self.m2_pitch)
# These are the rails that will be available for vdd/gnd
m3_rects = []
# These are the "inflated" shapes for DRC checks
m3_drc_rects = []
for y in m3_y_coords:
# This is just what metal will be drawn
ll = vector(lowest[0], y - 0.5*self.m3_width)
ur = vector(highest[0], y + 0.5*self.m3_width)
m3_rects.append([ll, ur])
# This is a full m3 pitch for DRC conflict checking
ll = vector(lowest[0], y - 0.5*self.m3_pitch )
ur = vector(highest[0], y + 0.5*self.m3_pitch)
m3_drc_rects.append([ll, ur])
vdd_rects = []
gnd_rects = []
# Now, figure how if the rails intersect a blockage, vdd, or gnd pin
# Divide the rails up alternately
# This should be done in less than n^2 using a kd-tree or something
# for drc_rect,rect in zip(m3_drc_rects,m3_rects):
# for b in blockages:
# if rect_overlaps(b,drc_rect):
# break
# else:
# gnd_rects.append(rect)
# Create the vdd and gnd rails
for rect in m3_rects:
(ll,ur) = rect
for rect in gnd_rects:
(ll,ur) = rect
self.add_layout_pin(text="gnd",
layer="metal3",
offset=ll,
width=ur.x-ll.x,
height=ur.y-ll.y)
for rect in vdd_rects:
(ll,ur) = rect
self.add_layout_pin(text="vdd",
layer="metal3",
offset=ll,
width=ur.x-ll.x,
height=ur.y-ll.y)
def route_control_logic(self):
""" Route the outputs from the control logic module """
for n in self.control_logic_outputs:
-3
View File
@@ -13,9 +13,6 @@ class contact_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import contact
-3
View File
@@ -13,9 +13,6 @@ class path_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import path
import tech
import design
@@ -13,9 +13,6 @@ class ptx_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import ptx
import tech
@@ -13,9 +13,6 @@ class ptx_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import ptx
import tech
@@ -13,9 +13,6 @@ class ptx_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import ptx
import tech
@@ -13,9 +13,6 @@ class ptx_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import ptx
import tech
@@ -13,9 +13,6 @@ class ptx_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import ptx
import tech
@@ -13,9 +13,6 @@ class ptx_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import ptx
import tech
-3
View File
@@ -13,9 +13,6 @@ class wire_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import wire
import tech
import design
-3
View File
@@ -20,9 +20,6 @@ class pbitcell_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import pbitcell
import tech
-3
View File
@@ -15,9 +15,6 @@ class pinv_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import pinv
import tech
-3
View File
@@ -15,9 +15,6 @@ class pinv_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import pinv
import tech
-4
View File
@@ -14,10 +14,6 @@ class pinv_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import pinv
import tech
-3
View File
@@ -15,9 +15,6 @@ class pinv_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import pinv
import tech
-3
View File
@@ -15,9 +15,6 @@ class pinvbuf_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import pinvbuf
debug.info(2, "Testing inverter/buffer 4x 8x")
-3
View File
@@ -17,9 +17,6 @@ class pnand2_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import pnand2
import tech
-3
View File
@@ -17,9 +17,6 @@ class pnand3_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import pnand3
import tech
-3
View File
@@ -17,9 +17,6 @@ class pnor2_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import pnor2
import tech
-3
View File
@@ -15,9 +15,6 @@ class precharge_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import precharge
import tech
@@ -17,9 +17,6 @@ class single_level_column_mux_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import single_level_column_mux
import tech
-3
View File
@@ -17,9 +17,6 @@ class array_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import bitcell_array
debug.info(2, "Testing 4x4 array for 6t_cell")
-3
View File
@@ -16,9 +16,6 @@ class pbitcell_array_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import bitcell_array
debug.info(2, "Testing 4x4 array for multiport bitcell, with read ports at the edge of the bit cell")
@@ -15,9 +15,6 @@ class hierarchical_decoder_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import hierarchical_decoder
import tech
@@ -15,9 +15,6 @@ class hierarchical_predecode2x4_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import hierarchical_predecode2x4 as pre
import tech
@@ -15,9 +15,6 @@ class hierarchical_predecode3x8_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import hierarchical_predecode3x8 as pre
import tech
@@ -14,9 +14,6 @@ class single_level_column_mux_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import single_level_column_mux_array
debug.info(1, "Testing sample for 2-way column_mux_array")
@@ -15,9 +15,6 @@ class precharge_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import precharge_array
import tech
@@ -17,9 +17,6 @@ class wordline_driver_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import wordline_driver
import tech
@@ -15,9 +15,6 @@ class sense_amp_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import sense_amp_array
@@ -15,9 +15,6 @@ class write_driver_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import write_driver_array
debug.info(2, "Testing write_driver_array for columns=8, word_size=8")
-3
View File
@@ -15,9 +15,6 @@ class dff_array_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import dff_array
debug.info(2, "Testing dff_array for 3x3")
-3
View File
@@ -15,9 +15,6 @@ class dff_buf_array_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import dff_buf_array
debug.info(2, "Testing dff_buf_array for 3x3")
-3
View File
@@ -15,9 +15,6 @@ class dff_buf_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import dff_buf
debug.info(2, "Testing dff_buf 4x 8x")
-3
View File
@@ -15,9 +15,6 @@ class dff_inv_array_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import dff_inv_array
debug.info(2, "Testing dff_inv_array for 3x3")
-3
View File
@@ -15,9 +15,6 @@ class dff_inv_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import dff_inv
debug.info(2, "Testing dff_inv 4x")
-3
View File
@@ -15,9 +15,6 @@ class dff_array_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import ms_flop_array
debug.info(2, "Testing ms_flop_array for columns=8, word_size=8")
-3
View File
@@ -15,9 +15,6 @@ class tri_gate_array_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import tri_gate_array
debug.info(1, "Testing tri_gate_array for columns=8, word_size=8")
-3
View File
@@ -15,9 +15,6 @@ class delay_chain_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import delay_chain
debug.info(2, "Testing delay_chain")
@@ -15,9 +15,6 @@ class replica_bitline_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import replica_bitline
stages=4
-3
View File
@@ -15,9 +15,6 @@ class control_logic_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import control_logic
import tech
-3
View File
@@ -15,9 +15,6 @@ class bank_select_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
import bank_select
debug.info(1, "No column mux")
-3
View File
@@ -15,9 +15,6 @@ class multi_bank_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
from bank import bank
debug.info(1, "No column mux")
-3
View File
@@ -15,9 +15,6 @@ class single_bank_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
from bank import bank
debug.info(1, "No column mux")
-3
View File
@@ -15,9 +15,6 @@ class sram_1bank_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
from sram import sram
debug.info(1, "Single bank, no column mux with control logic")
-3
View File
@@ -16,9 +16,6 @@ class sram_2bank_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
from sram import sram
debug.info(1, "Two bank, no column mux with control logic")
-3
View File
@@ -16,9 +16,6 @@ class sram_4bank_test(openram_test):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
global verify
import verify
from sram import sram
debug.info(1, "Four bank, no column mux with control logic")
-3
View File
@@ -27,9 +27,6 @@ class sram_func_test(openram_test):
if not OPTS.spice_exe:
debug.error("Could not find {} simulator.".format(OPTS.spice_name),-1)
global verify
import verify
self.func_test(bank_num=1)
self.func_test(bank_num=2)
self.func_test(bank_num=4)
+4
View File
@@ -0,0 +1,4 @@
BSIM3v3.3.0 Parameter Checking.
Model = p
Warning: Pd = 0 is less than W.
Warning: Ps = 0 is less than W.
Binary file not shown.
View File
Binary file not shown.
+19
View File
@@ -0,0 +1,19 @@
VERSION 5.4 ;
NAMESCASESENSITIVE ON ;
BUSBITCHARS "[]" ;
DIVIDERCHAR "/" ;
UNITS
DATABASE MICRONS 1000 ;
END UNITS
SITE MacroSite
CLASS Core ;
SIZE 324000.0 by 421500.0 ;
END MacroSite
MACRO sram1
CLASS BLOCK ;
SIZE 324000.0 BY 421500.0 ;
SYMMETRY X Y R90 ;
SITE MacroSite ;
PIN DIN[0]
DIRECTION INPUT ;
PORT
+602
View File
@@ -0,0 +1,602 @@
**************************************************
* OpenRAM generated memory.
* Words: 16
* Data bits: 4
* Banks: 1
* Column mux: 1:1
**************************************************
* Positive edge-triggered FF
.subckt dff D Q clk vdd gnd
M0 vdd clk a_2_6# vdd p w=12u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M1 a_17_74# D vdd vdd p w=6u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M2 a_22_6# clk a_17_74# vdd p w=6u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M3 a_31_74# a_2_6# a_22_6# vdd p w=6u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M4 vdd a_34_4# a_31_74# vdd p w=6u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M5 a_34_4# a_22_6# vdd vdd p w=6u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M6 a_61_74# a_34_4# vdd vdd p w=6u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M7 a_66_6# a_2_6# a_61_74# vdd p w=6u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M8 a_76_84# clk a_66_6# vdd p w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M9 vdd Q a_76_84# vdd p w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M10 gnd clk a_2_6# gnd n w=6u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M11 Q a_66_6# vdd vdd p w=12u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M12 a_17_6# D gnd gnd n w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M13 a_22_6# a_2_6# a_17_6# gnd n w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M14 a_31_6# clk a_22_6# gnd n w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M15 gnd a_34_4# a_31_6# gnd n w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M16 a_34_4# a_22_6# gnd gnd n w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M17 a_61_6# a_34_4# gnd gnd n w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M18 a_66_6# clk a_61_6# gnd n w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M19 a_76_6# a_2_6# a_66_6# gnd n w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M20 gnd Q a_76_6# gnd n w=3u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
M21 Q a_66_6# gnd gnd n w=6u l=0.6u
+ ad=0p pd=0u as=0p ps=0u
.ends dff
* ptx M{0} {1} n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
* ptx M{0} {1} p m=1 w=4.8u l=0.6u pd=10.799999999999999u ps=10.799999999999999u as=7.199999999999999p ad=7.199999999999999p
.SUBCKT pinv_2 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=1 w=4.8u l=0.6u pd=10.799999999999999u ps=10.799999999999999u as=7.199999999999999p ad=7.199999999999999p
Mpinv_nmos Z A gnd gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
.ENDS pinv_2
.SUBCKT dff_inv_2 D Q Qb clk vdd gnd
Xdff_inv_dff D Q clk vdd gnd dff
Xdff_inv_inv1 Q Qb vdd gnd pinv_2
.ENDS dff_inv_2
.SUBCKT dff_array_3x1 din[0] din[1] din[2] dout[0] dout_bar[0] dout[1] dout_bar[1] dout[2] dout_bar[2] clk vdd gnd
XXdff_r0_c0 din[0] dout[0] dout_bar[0] clk vdd gnd dff_inv_2
XXdff_r1_c0 din[1] dout[1] dout_bar[1] clk vdd gnd dff_inv_2
XXdff_r2_c0 din[2] dout[2] dout_bar[2] clk vdd gnd dff_inv_2
.ENDS dff_array_3x1
* ptx M{0} {1} p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
.SUBCKT pnand2_1 A B Z vdd gnd
Mpnand2_pmos1 vdd A Z vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand2_pmos2 Z B vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand2_nmos1 Z B net1 gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand2_nmos2 net1 A gnd gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
.ENDS pnand2_1
.SUBCKT pnand3_1 A B C Z vdd gnd
Mpnand3_pmos1 vdd A Z vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_pmos2 Z B vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_pmos3 Z C vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_nmos1 Z C net1 gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_nmos2 net1 B net2 gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_nmos3 net2 A gnd gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
.ENDS pnand3_1
* ptx M{0} {1} n m=1 w=1.2u l=0.6u pd=3.5999999999999996u ps=3.5999999999999996u as=1.7999999999999998p ad=1.7999999999999998p
.SUBCKT pinv_3 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpinv_nmos Z A gnd gnd n m=1 w=1.2u l=0.6u pd=3.5999999999999996u ps=3.5999999999999996u as=1.7999999999999998p ad=1.7999999999999998p
.ENDS pinv_3
* ptx M{0} {1} n m=1 w=4.8u l=0.6u pd=10.799999999999999u ps=10.799999999999999u as=7.199999999999999p ad=7.199999999999999p
* ptx M{0} {1} p m=1 w=9.6u l=0.6u pd=20.4u ps=20.4u as=14.399999999999999p ad=14.399999999999999p
.SUBCKT pinv_4 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=1 w=9.6u l=0.6u pd=20.4u ps=20.4u as=14.399999999999999p ad=14.399999999999999p
Mpinv_nmos Z A gnd gnd n m=1 w=4.8u l=0.6u pd=10.799999999999999u ps=10.799999999999999u as=7.199999999999999p ad=7.199999999999999p
.ENDS pinv_4
* ptx M{0} {1} n m=4 w=4.8u l=0.6u pd=10.799999999999999u ps=10.799999999999999u as=7.199999999999999p ad=7.199999999999999p
* ptx M{0} {1} p m=4 w=9.6u l=0.6u pd=20.4u ps=20.4u as=14.399999999999999p ad=14.399999999999999p
.SUBCKT pinv_5 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=4 w=9.6u l=0.6u pd=20.4u ps=20.4u as=14.399999999999999p ad=14.399999999999999p
Mpinv_nmos Z A gnd gnd n m=4 w=4.8u l=0.6u pd=10.799999999999999u ps=10.799999999999999u as=7.199999999999999p ad=7.199999999999999p
.ENDS pinv_5
.SUBCKT pinvbuf_4_16 A Zb Z vdd gnd
Xbuf_inv1 A zb_int vdd gnd pinv_3
Xbuf_inv2 zb_int z_int vdd gnd pinv_4
Xbuf_inv3 z_int Zb vdd gnd pinv_5
Xbuf_inv4 zb_int Z vdd gnd pinv_5
.ENDS pinvbuf_4_16
.SUBCKT pinv_6 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpinv_nmos Z A gnd gnd n m=1 w=1.2u l=0.6u pd=3.5999999999999996u ps=3.5999999999999996u as=1.7999999999999998p ad=1.7999999999999998p
.ENDS pinv_6
.SUBCKT pinv_7 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=1 w=9.6u l=0.6u pd=20.4u ps=20.4u as=14.399999999999999p ad=14.399999999999999p
Mpinv_nmos Z A gnd gnd n m=1 w=4.8u l=0.6u pd=10.799999999999999u ps=10.799999999999999u as=7.199999999999999p ad=7.199999999999999p
.ENDS pinv_7
.SUBCKT pinv_8 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=4 w=9.6u l=0.6u pd=20.4u ps=20.4u as=14.399999999999999p ad=14.399999999999999p
Mpinv_nmos Z A gnd gnd n m=4 w=4.8u l=0.6u pd=10.799999999999999u ps=10.799999999999999u as=7.199999999999999p ad=7.199999999999999p
.ENDS pinv_8
*********************** "cell_6t" ******************************
.SUBCKT replica_cell_6t bl br wl vdd gnd
M_1 gnd net_2 vdd vdd p W='0.9u' L=1.2u
M_2 net_2 gnd vdd vdd p W='0.9u' L=1.2u
M_3 br wl net_2 gnd n W='1.2u' L=0.6u
M_4 bl wl gnd gnd n W='1.2u' L=0.6u
M_5 net_2 gnd gnd gnd n W='2.4u' L=0.6u
M_6 gnd net_2 gnd gnd n W='2.4u' L=0.6u
.ENDS $ replica_cell_6t
*********************** "cell_6t" ******************************
.SUBCKT cell_6t bl br wl vdd gnd
M_1 net_1 net_2 vdd vdd p W='0.9u' L=1.2u
M_2 net_2 net_1 vdd vdd p W='0.9u' L=1.2u
M_3 br wl net_2 gnd n W='1.2u' L=0.6u
M_4 bl wl net_1 gnd n W='1.2u' L=0.6u
M_5 net_2 net_1 gnd gnd n W='2.4u' L=0.6u
M_6 net_1 net_2 gnd gnd n W='2.4u' L=0.6u
.ENDS $ cell_6t
.SUBCKT bitline_load bl[0] br[0] wl[0] wl[1] wl[2] wl[3] vdd gnd
Xbit_r0_c0 bl[0] br[0] wl[0] vdd gnd cell_6t
Xbit_r1_c0 bl[0] br[0] wl[1] vdd gnd cell_6t
Xbit_r2_c0 bl[0] br[0] wl[2] vdd gnd cell_6t
Xbit_r3_c0 bl[0] br[0] wl[3] vdd gnd cell_6t
.ENDS bitline_load
.SUBCKT pinv_9 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpinv_nmos Z A gnd gnd n m=1 w=1.2u l=0.6u pd=3.5999999999999996u ps=3.5999999999999996u as=1.7999999999999998p ad=1.7999999999999998p
.ENDS pinv_9
.SUBCKT delay_chain in out vdd gnd
Xdinv0 in dout_1 vdd gnd pinv_9
Xdload_0_0 dout_1 n_0_0 vdd gnd pinv_9
Xdload_0_1 dout_1 n_0_1 vdd gnd pinv_9
Xdload_0_2 dout_1 n_0_2 vdd gnd pinv_9
Xdinv1 dout_1 dout_2 vdd gnd pinv_9
Xdload_1_0 dout_2 n_1_0 vdd gnd pinv_9
Xdload_1_1 dout_2 n_1_1 vdd gnd pinv_9
Xdload_1_2 dout_2 n_1_2 vdd gnd pinv_9
Xdinv2 dout_2 out vdd gnd pinv_9
Xdload_2_0 out n_2_0 vdd gnd pinv_9
Xdload_2_1 out n_2_1 vdd gnd pinv_9
Xdload_2_2 out n_2_2 vdd gnd pinv_9
.ENDS delay_chain
.SUBCKT pinv_10 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpinv_nmos Z A gnd gnd n m=1 w=1.2u l=0.6u pd=3.5999999999999996u ps=3.5999999999999996u as=1.7999999999999998p ad=1.7999999999999998p
.ENDS pinv_10
* ptx M{0} {1} p m=1 w=1.2u l=0.6u pd=3.5999999999999996u ps=3.5999999999999996u as=1.7999999999999998p ad=1.7999999999999998p
.SUBCKT replica_bitline en out vdd gnd
Xrbl_inv bl[0] out vdd gnd pinv_10
Mrbl_access_tx vdd delayed_en bl[0] vdd p m=1 w=1.2u l=0.6u pd=3.5999999999999996u ps=3.5999999999999996u as=1.7999999999999998p ad=1.7999999999999998p
Xdelay_chain en delayed_en vdd gnd delay_chain
Xbitcell bl[0] br[0] delayed_en vdd gnd replica_cell_6t
Xload bl[0] br[0] gnd gnd gnd gnd vdd gnd bitline_load
.ENDS replica_bitline
.SUBCKT control_logic csb web oeb clk s_en w_en tri_en tri_en_bar clk_buf_bar clk_buf vdd gnd
Xctrl_dffs csb web oeb cs_bar cs we_bar we oe_bar oe clk_buf vdd gnd dff_array_3x1
Xclkbuf clk clk_buf_bar clk_buf vdd gnd pinvbuf_4_16
Xnand3_w_en_bar clk_buf_bar cs we w_en_bar vdd gnd pnand3_1
Xinv_pre_w_en w_en_bar pre_w_en vdd gnd pinv_6
Xinv_pre_w_en_bar pre_w_en pre_w_en_bar vdd gnd pinv_7
Xinv_w_en2 pre_w_en_bar w_en vdd gnd pinv_8
Xinv_tri_en1 pre_tri_en_bar pre_tri_en1 vdd gnd pinv_7
Xtri_en_buf1 pre_tri_en1 pre_tri_en_bar1 vdd gnd pinv_7
Xtri_en_buf2 pre_tri_en_bar1 tri_en vdd gnd pinv_8
Xnand2_tri_en clk_buf_bar oe pre_tri_en_bar vdd gnd pnand2_1
Xtri_en_bar_buf1 pre_tri_en_bar pre_tri_en2 vdd gnd pinv_7
Xtri_en_bar_buf2 pre_tri_en2 tri_en_bar vdd gnd pinv_8
Xnand3_rblk_bar clk_buf_bar oe cs rblk_bar vdd gnd pnand3_1
Xinv_rblk rblk_bar rblk vdd gnd pinv_6
Xinv_s_en pre_s_en_bar s_en vdd gnd pinv_8
Xinv_pre_s_en_bar pre_s_en pre_s_en_bar vdd gnd pinv_7
Xreplica_bitline rblk pre_s_en vdd gnd replica_bitline
.ENDS control_logic
.SUBCKT dff_array din[0] din[1] din[2] din[3] dout[0] dout[1] dout[2] dout[3] clk vdd gnd
XXdff_r0_c0 din[0] dout[0] clk vdd gnd dff
XXdff_r1_c0 din[1] dout[1] clk vdd gnd dff
XXdff_r2_c0 din[2] dout[2] clk vdd gnd dff
XXdff_r3_c0 din[3] dout[3] clk vdd gnd dff
.ENDS dff_array
.SUBCKT bitcell_array bl[0] br[0] bl[1] br[1] bl[2] br[2] bl[3] br[3] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] vdd gnd
Xbit_r0_c0 bl[0] br[0] wl[0] vdd gnd cell_6t
Xbit_r1_c0 bl[0] br[0] wl[1] vdd gnd cell_6t
Xbit_r2_c0 bl[0] br[0] wl[2] vdd gnd cell_6t
Xbit_r3_c0 bl[0] br[0] wl[3] vdd gnd cell_6t
Xbit_r4_c0 bl[0] br[0] wl[4] vdd gnd cell_6t
Xbit_r5_c0 bl[0] br[0] wl[5] vdd gnd cell_6t
Xbit_r6_c0 bl[0] br[0] wl[6] vdd gnd cell_6t
Xbit_r7_c0 bl[0] br[0] wl[7] vdd gnd cell_6t
Xbit_r8_c0 bl[0] br[0] wl[8] vdd gnd cell_6t
Xbit_r9_c0 bl[0] br[0] wl[9] vdd gnd cell_6t
Xbit_r10_c0 bl[0] br[0] wl[10] vdd gnd cell_6t
Xbit_r11_c0 bl[0] br[0] wl[11] vdd gnd cell_6t
Xbit_r12_c0 bl[0] br[0] wl[12] vdd gnd cell_6t
Xbit_r13_c0 bl[0] br[0] wl[13] vdd gnd cell_6t
Xbit_r14_c0 bl[0] br[0] wl[14] vdd gnd cell_6t
Xbit_r15_c0 bl[0] br[0] wl[15] vdd gnd cell_6t
Xbit_r0_c1 bl[1] br[1] wl[0] vdd gnd cell_6t
Xbit_r1_c1 bl[1] br[1] wl[1] vdd gnd cell_6t
Xbit_r2_c1 bl[1] br[1] wl[2] vdd gnd cell_6t
Xbit_r3_c1 bl[1] br[1] wl[3] vdd gnd cell_6t
Xbit_r4_c1 bl[1] br[1] wl[4] vdd gnd cell_6t
Xbit_r5_c1 bl[1] br[1] wl[5] vdd gnd cell_6t
Xbit_r6_c1 bl[1] br[1] wl[6] vdd gnd cell_6t
Xbit_r7_c1 bl[1] br[1] wl[7] vdd gnd cell_6t
Xbit_r8_c1 bl[1] br[1] wl[8] vdd gnd cell_6t
Xbit_r9_c1 bl[1] br[1] wl[9] vdd gnd cell_6t
Xbit_r10_c1 bl[1] br[1] wl[10] vdd gnd cell_6t
Xbit_r11_c1 bl[1] br[1] wl[11] vdd gnd cell_6t
Xbit_r12_c1 bl[1] br[1] wl[12] vdd gnd cell_6t
Xbit_r13_c1 bl[1] br[1] wl[13] vdd gnd cell_6t
Xbit_r14_c1 bl[1] br[1] wl[14] vdd gnd cell_6t
Xbit_r15_c1 bl[1] br[1] wl[15] vdd gnd cell_6t
Xbit_r0_c2 bl[2] br[2] wl[0] vdd gnd cell_6t
Xbit_r1_c2 bl[2] br[2] wl[1] vdd gnd cell_6t
Xbit_r2_c2 bl[2] br[2] wl[2] vdd gnd cell_6t
Xbit_r3_c2 bl[2] br[2] wl[3] vdd gnd cell_6t
Xbit_r4_c2 bl[2] br[2] wl[4] vdd gnd cell_6t
Xbit_r5_c2 bl[2] br[2] wl[5] vdd gnd cell_6t
Xbit_r6_c2 bl[2] br[2] wl[6] vdd gnd cell_6t
Xbit_r7_c2 bl[2] br[2] wl[7] vdd gnd cell_6t
Xbit_r8_c2 bl[2] br[2] wl[8] vdd gnd cell_6t
Xbit_r9_c2 bl[2] br[2] wl[9] vdd gnd cell_6t
Xbit_r10_c2 bl[2] br[2] wl[10] vdd gnd cell_6t
Xbit_r11_c2 bl[2] br[2] wl[11] vdd gnd cell_6t
Xbit_r12_c2 bl[2] br[2] wl[12] vdd gnd cell_6t
Xbit_r13_c2 bl[2] br[2] wl[13] vdd gnd cell_6t
Xbit_r14_c2 bl[2] br[2] wl[14] vdd gnd cell_6t
Xbit_r15_c2 bl[2] br[2] wl[15] vdd gnd cell_6t
Xbit_r0_c3 bl[3] br[3] wl[0] vdd gnd cell_6t
Xbit_r1_c3 bl[3] br[3] wl[1] vdd gnd cell_6t
Xbit_r2_c3 bl[3] br[3] wl[2] vdd gnd cell_6t
Xbit_r3_c3 bl[3] br[3] wl[3] vdd gnd cell_6t
Xbit_r4_c3 bl[3] br[3] wl[4] vdd gnd cell_6t
Xbit_r5_c3 bl[3] br[3] wl[5] vdd gnd cell_6t
Xbit_r6_c3 bl[3] br[3] wl[6] vdd gnd cell_6t
Xbit_r7_c3 bl[3] br[3] wl[7] vdd gnd cell_6t
Xbit_r8_c3 bl[3] br[3] wl[8] vdd gnd cell_6t
Xbit_r9_c3 bl[3] br[3] wl[9] vdd gnd cell_6t
Xbit_r10_c3 bl[3] br[3] wl[10] vdd gnd cell_6t
Xbit_r11_c3 bl[3] br[3] wl[11] vdd gnd cell_6t
Xbit_r12_c3 bl[3] br[3] wl[12] vdd gnd cell_6t
Xbit_r13_c3 bl[3] br[3] wl[13] vdd gnd cell_6t
Xbit_r14_c3 bl[3] br[3] wl[14] vdd gnd cell_6t
Xbit_r15_c3 bl[3] br[3] wl[15] vdd gnd cell_6t
.ENDS bitcell_array
* ptx M{0} {1} p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
.SUBCKT precharge bl br en vdd
Mlower_pmos bl en br vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mupper_pmos1 bl en vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mupper_pmos2 br en vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
.ENDS precharge
.SUBCKT precharge_array bl[0] br[0] bl[1] br[1] bl[2] br[2] bl[3] br[3] en vdd
Xpre_column_0 bl[0] br[0] en vdd precharge
Xpre_column_1 bl[1] br[1] en vdd precharge
Xpre_column_2 bl[2] br[2] en vdd precharge
Xpre_column_3 bl[3] br[3] en vdd precharge
.ENDS precharge_array
*********************** "sense_amp" ******************************
.SUBCKT sense_amp bl br dout en vdd gnd
M_1 dout net_1 vdd vdd p W='5.4*1u' L=0.6u
M_2 dout net_1 net_2 gnd n W='2.7*1u' L=0.6u
M_3 net_1 dout vdd vdd p W='5.4*1u' L=0.6u
M_4 net_1 dout net_2 gnd n W='2.7*1u' L=0.6u
M_5 bl en dout vdd p W='7.2*1u' L=0.6u
M_6 br en net_1 vdd p W='7.2*1u' L=0.6u
M_7 net_2 en gnd gnd n W='2.7*1u' L=0.6u
.ENDS sense_amp
.SUBCKT sense_amp_array data[0] bl[0] br[0] data[1] bl[1] br[1] data[2] bl[2] br[2] data[3] bl[3] br[3] en vdd gnd
Xsa_d0 bl[0] br[0] data[0] en vdd gnd sense_amp
Xsa_d1 bl[1] br[1] data[1] en vdd gnd sense_amp
Xsa_d2 bl[2] br[2] data[2] en vdd gnd sense_amp
Xsa_d3 bl[3] br[3] data[3] en vdd gnd sense_amp
.ENDS sense_amp_array
*********************** Write_Driver ******************************
.SUBCKT write_driver din bl br en vdd gnd
**** Inverter to conver Data_in to data_in_bar ******
M_1 net_3 din gnd gnd n W='1.2*1u' L=0.6u
M_2 net_3 din vdd vdd p W='2.1*1u' L=0.6u
**** 2input nand gate follwed by inverter to drive BL ******
M_3 net_2 en net_7 gnd n W='2.1*1u' L=0.6u
M_4 net_7 din gnd gnd n W='2.1*1u' L=0.6u
M_5 net_2 en vdd vdd p W='2.1*1u' L=0.6u
M_6 net_2 din vdd vdd p W='2.1*1u' L=0.6u
M_7 net_1 net_2 vdd vdd p W='2.1*1u' L=0.6u
M_8 net_1 net_2 gnd gnd n W='1.2*1u' L=0.6u
**** 2input nand gate follwed by inverter to drive BR******
M_9 net_4 en vdd vdd p W='2.1*1u' L=0.6u
M_10 net_4 en net_8 gnd n W='2.1*1u' L=0.6u
M_11 net_8 net_3 gnd gnd n W='2.1*1u' L=0.6u
M_12 net_4 net_3 vdd vdd p W='2.1*1u' L=0.6u
M_13 net_6 net_4 vdd vdd p W='2.1*1u' L=0.6u
M_14 net_6 net_4 gnd gnd n W='1.2*1u' L=0.6u
************************************************
M_15 bl net_6 net_5 gnd n W='3.6*1u' L=0.6u
M_16 br net_1 net_5 gnd n W='3.6*1u' L=0.6u
M_17 net_5 en gnd gnd n W='3.6*1u' L=0.6u
.ENDS $ write_driver
.SUBCKT write_driver_array data[0] data[1] data[2] data[3] bl[0] br[0] bl[1] br[1] bl[2] br[2] bl[3] br[3] en vdd gnd
XXwrite_driver0 data[0] bl[0] br[0] en vdd gnd write_driver
XXwrite_driver1 data[1] bl[1] br[1] en vdd gnd write_driver
XXwrite_driver2 data[2] bl[2] br[2] en vdd gnd write_driver
XXwrite_driver3 data[3] bl[3] br[3] en vdd gnd write_driver
.ENDS write_driver_array
.SUBCKT pinv_11 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpinv_nmos Z A gnd gnd n m=1 w=1.2u l=0.6u pd=3.5999999999999996u ps=3.5999999999999996u as=1.7999999999999998p ad=1.7999999999999998p
.ENDS pinv_11
.SUBCKT pnand2_2 A B Z vdd gnd
Mpnand2_pmos1 vdd A Z vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand2_pmos2 Z B vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand2_nmos1 Z B net1 gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand2_nmos2 net1 A gnd gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
.ENDS pnand2_2
.SUBCKT pnand3_2 A B C Z vdd gnd
Mpnand3_pmos1 vdd A Z vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_pmos2 Z B vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_pmos3 Z C vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_nmos1 Z C net1 gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_nmos2 net1 B net2 gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_nmos3 net2 A gnd gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
.ENDS pnand3_2
.SUBCKT pinv_12 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpinv_nmos Z A gnd gnd n m=1 w=1.2u l=0.6u pd=3.5999999999999996u ps=3.5999999999999996u as=1.7999999999999998p ad=1.7999999999999998p
.ENDS pinv_12
.SUBCKT pnand2_3 A B Z vdd gnd
Mpnand2_pmos1 vdd A Z vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand2_pmos2 Z B vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand2_nmos1 Z B net1 gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand2_nmos2 net1 A gnd gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
.ENDS pnand2_3
.SUBCKT pre2x4 in[0] in[1] out[0] out[1] out[2] out[3] vdd gnd
XXpre_inv[0] in[0] inbar[0] vdd gnd pinv_12
XXpre_inv[1] in[1] inbar[1] vdd gnd pinv_12
XXpre_nand_inv[0] Z[0] out[0] vdd gnd pinv_12
XXpre_nand_inv[1] Z[1] out[1] vdd gnd pinv_12
XXpre_nand_inv[2] Z[2] out[2] vdd gnd pinv_12
XXpre_nand_inv[3] Z[3] out[3] vdd gnd pinv_12
XXpre2x4_nand[0] inbar[0] inbar[1] Z[0] vdd gnd pnand2_3
XXpre2x4_nand[1] in[0] inbar[1] Z[1] vdd gnd pnand2_3
XXpre2x4_nand[2] inbar[0] in[1] Z[2] vdd gnd pnand2_3
XXpre2x4_nand[3] in[0] in[1] Z[3] vdd gnd pnand2_3
.ENDS pre2x4
.SUBCKT pinv_13 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpinv_nmos Z A gnd gnd n m=1 w=1.2u l=0.6u pd=3.5999999999999996u ps=3.5999999999999996u as=1.7999999999999998p ad=1.7999999999999998p
.ENDS pinv_13
.SUBCKT pnand3_3 A B C Z vdd gnd
Mpnand3_pmos1 vdd A Z vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_pmos2 Z B vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_pmos3 Z C vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_nmos1 Z C net1 gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_nmos2 net1 B net2 gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand3_nmos3 net2 A gnd gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
.ENDS pnand3_3
.SUBCKT pre3x8 in[0] in[1] in[2] out[0] out[1] out[2] out[3] out[4] out[5] out[6] out[7] vdd gnd
XXpre_inv[0] in[0] inbar[0] vdd gnd pinv_13
XXpre_inv[1] in[1] inbar[1] vdd gnd pinv_13
XXpre_inv[2] in[2] inbar[2] vdd gnd pinv_13
XXpre_nand_inv[0] Z[0] out[0] vdd gnd pinv_13
XXpre_nand_inv[1] Z[1] out[1] vdd gnd pinv_13
XXpre_nand_inv[2] Z[2] out[2] vdd gnd pinv_13
XXpre_nand_inv[3] Z[3] out[3] vdd gnd pinv_13
XXpre_nand_inv[4] Z[4] out[4] vdd gnd pinv_13
XXpre_nand_inv[5] Z[5] out[5] vdd gnd pinv_13
XXpre_nand_inv[6] Z[6] out[6] vdd gnd pinv_13
XXpre_nand_inv[7] Z[7] out[7] vdd gnd pinv_13
XXpre3x8_nand[0] inbar[0] inbar[1] inbar[2] Z[0] vdd gnd pnand3_3
XXpre3x8_nand[1] in[0] inbar[1] inbar[2] Z[1] vdd gnd pnand3_3
XXpre3x8_nand[2] inbar[0] in[1] inbar[2] Z[2] vdd gnd pnand3_3
XXpre3x8_nand[3] in[0] in[1] inbar[2] Z[3] vdd gnd pnand3_3
XXpre3x8_nand[4] inbar[0] inbar[1] in[2] Z[4] vdd gnd pnand3_3
XXpre3x8_nand[5] in[0] inbar[1] in[2] Z[5] vdd gnd pnand3_3
XXpre3x8_nand[6] inbar[0] in[1] in[2] Z[6] vdd gnd pnand3_3
XXpre3x8_nand[7] in[0] in[1] in[2] Z[7] vdd gnd pnand3_3
.ENDS pre3x8
.SUBCKT hierarchical_decoder_16rows A[0] A[1] A[2] A[3] decode[0] decode[1] decode[2] decode[3] decode[4] decode[5] decode[6] decode[7] decode[8] decode[9] decode[10] decode[11] decode[12] decode[13] decode[14] decode[15] vdd gnd
Xpre[0] A[0] A[1] out[0] out[1] out[2] out[3] vdd gnd pre2x4
Xpre[1] A[2] A[3] out[4] out[5] out[6] out[7] vdd gnd pre2x4
XDEC_NAND[0] out[0] out[4] Z[0] vdd gnd pnand2_2
XDEC_NAND[1] out[0] out[5] Z[1] vdd gnd pnand2_2
XDEC_NAND[2] out[0] out[6] Z[2] vdd gnd pnand2_2
XDEC_NAND[3] out[0] out[7] Z[3] vdd gnd pnand2_2
XDEC_NAND[4] out[1] out[4] Z[4] vdd gnd pnand2_2
XDEC_NAND[5] out[1] out[5] Z[5] vdd gnd pnand2_2
XDEC_NAND[6] out[1] out[6] Z[6] vdd gnd pnand2_2
XDEC_NAND[7] out[1] out[7] Z[7] vdd gnd pnand2_2
XDEC_NAND[8] out[2] out[4] Z[8] vdd gnd pnand2_2
XDEC_NAND[9] out[2] out[5] Z[9] vdd gnd pnand2_2
XDEC_NAND[10] out[2] out[6] Z[10] vdd gnd pnand2_2
XDEC_NAND[11] out[2] out[7] Z[11] vdd gnd pnand2_2
XDEC_NAND[12] out[3] out[4] Z[12] vdd gnd pnand2_2
XDEC_NAND[13] out[3] out[5] Z[13] vdd gnd pnand2_2
XDEC_NAND[14] out[3] out[6] Z[14] vdd gnd pnand2_2
XDEC_NAND[15] out[3] out[7] Z[15] vdd gnd pnand2_2
XDEC_INV_[0] Z[0] decode[0] vdd gnd pinv_11
XDEC_INV_[1] Z[1] decode[1] vdd gnd pinv_11
XDEC_INV_[2] Z[2] decode[2] vdd gnd pinv_11
XDEC_INV_[3] Z[3] decode[3] vdd gnd pinv_11
XDEC_INV_[4] Z[4] decode[4] vdd gnd pinv_11
XDEC_INV_[5] Z[5] decode[5] vdd gnd pinv_11
XDEC_INV_[6] Z[6] decode[6] vdd gnd pinv_11
XDEC_INV_[7] Z[7] decode[7] vdd gnd pinv_11
XDEC_INV_[8] Z[8] decode[8] vdd gnd pinv_11
XDEC_INV_[9] Z[9] decode[9] vdd gnd pinv_11
XDEC_INV_[10] Z[10] decode[10] vdd gnd pinv_11
XDEC_INV_[11] Z[11] decode[11] vdd gnd pinv_11
XDEC_INV_[12] Z[12] decode[12] vdd gnd pinv_11
XDEC_INV_[13] Z[13] decode[13] vdd gnd pinv_11
XDEC_INV_[14] Z[14] decode[14] vdd gnd pinv_11
XDEC_INV_[15] Z[15] decode[15] vdd gnd pinv_11
.ENDS hierarchical_decoder_16rows
*********************** tri_gate ******************************
.SUBCKT tri_gate in out en en_bar vdd gnd
M_1 net_2 in_inv gnd gnd n W='1.2*1u' L=0.6u
M_2 net_3 in_inv vdd vdd p W='2.4*1u' L=0.6u
M_3 out en_bar net_3 vdd p W='2.4*1u' L=0.6u
M_4 out en net_2 gnd n W='1.2*1u' L=0.6u
M_5 in_inv in vdd vdd p W='2.4*1u' L=0.6u
M_6 in_inv in gnd gnd n W='1.2*1u' L=0.6u
.ENDS
.SUBCKT tri_gate_array in[0] in[1] in[2] in[3] out[0] out[1] out[2] out[3] en en_bar vdd gnd
XXtri_gate0 in[0] out[0] en en_bar vdd gnd tri_gate
XXtri_gate1 in[1] out[1] en en_bar vdd gnd tri_gate
XXtri_gate2 in[2] out[2] en en_bar vdd gnd tri_gate
XXtri_gate3 in[3] out[3] en en_bar vdd gnd tri_gate
.ENDS tri_gate_array
.SUBCKT pinv_14 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpinv_nmos Z A gnd gnd n m=1 w=1.2u l=0.6u pd=3.5999999999999996u ps=3.5999999999999996u as=1.7999999999999998p ad=1.7999999999999998p
.ENDS pinv_14
.SUBCKT pinv_15 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpinv_nmos Z A gnd gnd n m=1 w=1.2u l=0.6u pd=3.5999999999999996u ps=3.5999999999999996u as=1.7999999999999998p ad=1.7999999999999998p
.ENDS pinv_15
.SUBCKT pnand2_4 A B Z vdd gnd
Mpnand2_pmos1 vdd A Z vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand2_pmos2 Z B vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand2_nmos1 Z B net1 gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpnand2_nmos2 net1 A gnd gnd n m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
.ENDS pnand2_4
.SUBCKT wordline_driver in[0] in[1] in[2] in[3] in[4] in[5] in[6] in[7] in[8] in[9] in[10] in[11] in[12] in[13] in[14] in[15] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] en vdd gnd
Xwl_driver_inv_en0 en en_bar[0] vdd gnd pinv_15
Xwl_driver_nand0 en_bar[0] in[0] net[0] vdd gnd pnand2_4
Xwl_driver_inv0 net[0] wl[0] vdd gnd pinv_14
Xwl_driver_inv_en1 en en_bar[1] vdd gnd pinv_15
Xwl_driver_nand1 en_bar[1] in[1] net[1] vdd gnd pnand2_4
Xwl_driver_inv1 net[1] wl[1] vdd gnd pinv_14
Xwl_driver_inv_en2 en en_bar[2] vdd gnd pinv_15
Xwl_driver_nand2 en_bar[2] in[2] net[2] vdd gnd pnand2_4
Xwl_driver_inv2 net[2] wl[2] vdd gnd pinv_14
Xwl_driver_inv_en3 en en_bar[3] vdd gnd pinv_15
Xwl_driver_nand3 en_bar[3] in[3] net[3] vdd gnd pnand2_4
Xwl_driver_inv3 net[3] wl[3] vdd gnd pinv_14
Xwl_driver_inv_en4 en en_bar[4] vdd gnd pinv_15
Xwl_driver_nand4 en_bar[4] in[4] net[4] vdd gnd pnand2_4
Xwl_driver_inv4 net[4] wl[4] vdd gnd pinv_14
Xwl_driver_inv_en5 en en_bar[5] vdd gnd pinv_15
Xwl_driver_nand5 en_bar[5] in[5] net[5] vdd gnd pnand2_4
Xwl_driver_inv5 net[5] wl[5] vdd gnd pinv_14
Xwl_driver_inv_en6 en en_bar[6] vdd gnd pinv_15
Xwl_driver_nand6 en_bar[6] in[6] net[6] vdd gnd pnand2_4
Xwl_driver_inv6 net[6] wl[6] vdd gnd pinv_14
Xwl_driver_inv_en7 en en_bar[7] vdd gnd pinv_15
Xwl_driver_nand7 en_bar[7] in[7] net[7] vdd gnd pnand2_4
Xwl_driver_inv7 net[7] wl[7] vdd gnd pinv_14
Xwl_driver_inv_en8 en en_bar[8] vdd gnd pinv_15
Xwl_driver_nand8 en_bar[8] in[8] net[8] vdd gnd pnand2_4
Xwl_driver_inv8 net[8] wl[8] vdd gnd pinv_14
Xwl_driver_inv_en9 en en_bar[9] vdd gnd pinv_15
Xwl_driver_nand9 en_bar[9] in[9] net[9] vdd gnd pnand2_4
Xwl_driver_inv9 net[9] wl[9] vdd gnd pinv_14
Xwl_driver_inv_en10 en en_bar[10] vdd gnd pinv_15
Xwl_driver_nand10 en_bar[10] in[10] net[10] vdd gnd pnand2_4
Xwl_driver_inv10 net[10] wl[10] vdd gnd pinv_14
Xwl_driver_inv_en11 en en_bar[11] vdd gnd pinv_15
Xwl_driver_nand11 en_bar[11] in[11] net[11] vdd gnd pnand2_4
Xwl_driver_inv11 net[11] wl[11] vdd gnd pinv_14
Xwl_driver_inv_en12 en en_bar[12] vdd gnd pinv_15
Xwl_driver_nand12 en_bar[12] in[12] net[12] vdd gnd pnand2_4
Xwl_driver_inv12 net[12] wl[12] vdd gnd pinv_14
Xwl_driver_inv_en13 en en_bar[13] vdd gnd pinv_15
Xwl_driver_nand13 en_bar[13] in[13] net[13] vdd gnd pnand2_4
Xwl_driver_inv13 net[13] wl[13] vdd gnd pinv_14
Xwl_driver_inv_en14 en en_bar[14] vdd gnd pinv_15
Xwl_driver_nand14 en_bar[14] in[14] net[14] vdd gnd pnand2_4
Xwl_driver_inv14 net[14] wl[14] vdd gnd pinv_14
Xwl_driver_inv_en15 en en_bar[15] vdd gnd pinv_15
Xwl_driver_nand15 en_bar[15] in[15] net[15] vdd gnd pnand2_4
Xwl_driver_inv15 net[15] wl[15] vdd gnd pinv_14
.ENDS wordline_driver
.SUBCKT pinv_16 A Z vdd gnd
Mpinv_pmos Z A vdd vdd p m=1 w=2.4u l=0.6u pd=6.0u ps=6.0u as=3.5999999999999996p ad=3.5999999999999996p
Mpinv_nmos Z A gnd gnd n m=1 w=1.2u l=0.6u pd=3.5999999999999996u ps=3.5999999999999996u as=1.7999999999999998p ad=1.7999999999999998p
.ENDS pinv_16
.SUBCKT bank DOUT[0] DOUT[1] DOUT[2] DOUT[3] DIN[0] DIN[1] DIN[2] DIN[3] A[0] A[1] A[2] A[3] s_en w_en tri_en_bar tri_en clk_buf_bar clk_buf vdd gnd
Xbitcell_array bl[0] br[0] bl[1] br[1] bl[2] br[2] bl[3] br[3] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] vdd gnd bitcell_array
Xprecharge_array bl[0] br[0] bl[1] br[1] bl[2] br[2] bl[3] br[3] clk_buf_bar vdd precharge_array
Xsense_amp_array sa_out[0] bl[0] br[0] sa_out[1] bl[1] br[1] sa_out[2] bl[2] br[2] sa_out[3] bl[3] br[3] s_en vdd gnd sense_amp_array
Xwrite_driver_array DIN[0] DIN[1] DIN[2] DIN[3] bl[0] br[0] bl[1] br[1] bl[2] br[2] bl[3] br[3] w_en vdd gnd write_driver_array
Xtri_gate_array sa_out[0] sa_out[1] sa_out[2] sa_out[3] DOUT[0] DOUT[1] DOUT[2] DOUT[3] tri_en tri_en_bar vdd gnd tri_gate_array
Xrow_decoder A[0] A[1] A[2] A[3] dec_out[0] dec_out[1] dec_out[2] dec_out[3] dec_out[4] dec_out[5] dec_out[6] dec_out[7] dec_out[8] dec_out[9] dec_out[10] dec_out[11] dec_out[12] dec_out[13] dec_out[14] dec_out[15] vdd gnd hierarchical_decoder_16rows
Xwordline_driver dec_out[0] dec_out[1] dec_out[2] dec_out[3] dec_out[4] dec_out[5] dec_out[6] dec_out[7] dec_out[8] dec_out[9] dec_out[10] dec_out[11] dec_out[12] dec_out[13] dec_out[14] dec_out[15] wl[0] wl[1] wl[2] wl[3] wl[4] wl[5] wl[6] wl[7] wl[8] wl[9] wl[10] wl[11] wl[12] wl[13] wl[14] wl[15] clk_buf vdd gnd wordline_driver
.ENDS bank
.SUBCKT sram1 DIN[0] DIN[1] DIN[2] DIN[3] ADDR[0] ADDR[1] ADDR[2] ADDR[3] csb web oeb clk DOUT[0] DOUT[1] DOUT[2] DOUT[3] vdd gnd
Xbank0 DOUT[0] DOUT[1] DOUT[2] DOUT[3] DIN[0] DIN[1] DIN[2] DIN[3] A[0] A[1] A[2] A[3] s_en w_en tri_en_bar tri_en clk_buf_bar clk_buf vdd gnd bank
Xcontrol csb_s web_s oeb_s clk s_en w_en tri_en tri_en_bar clk_buf_bar clk_buf vdd gnd control_logic
Xaddress ADDR[0] ADDR[1] ADDR[2] ADDR[3] A[0] A[1] A[2] A[3] clk_buf vdd gnd dff_array
Xaddress ADDR[0] ADDR[1] ADDR[2] ADDR[3] A[0] A[1] A[2] A[3] clk_buf vdd gnd dff_array
.ENDS sram1
+347
View File
@@ -0,0 +1,347 @@
library (sram1_TT_5p0V_25C_lib){
delay_model : "table_lookup";
time_unit : "1ns" ;
voltage_unit : "1v" ;
current_unit : "1mA" ;
resistance_unit : "1kohm" ;
capacitive_load_unit(1 ,fF) ;
leakage_power_unit : "1mW" ;
pulling_resistance_unit :"1kohm" ;
operating_conditions(OC){
process : 1.0 ;
voltage : 5.0 ;
temperature : 25;
}
input_threshold_pct_fall : 50.0 ;
output_threshold_pct_fall : 50.0 ;
input_threshold_pct_rise : 50.0 ;
output_threshold_pct_rise : 50.0 ;
slew_lower_threshold_pct_fall : 10.0 ;
slew_upper_threshold_pct_fall : 90.0 ;
slew_lower_threshold_pct_rise : 10.0 ;
slew_upper_threshold_pct_rise : 90.0 ;
nom_voltage : 5.0;
nom_temperature : 25;
nom_process : 1.0;
default_cell_leakage_power : 0.0 ;
default_leakage_power_density : 0.0 ;
default_input_pin_cap : 1.0 ;
default_inout_pin_cap : 1.0 ;
default_output_pin_cap : 0.0 ;
default_max_transition : 0.5 ;
default_fanout_load : 1.0 ;
default_max_fanout : 4.0 ;
default_connection_class : universal ;
lu_table_template(CELL_TABLE){
variable_1 : input_net_transition;
variable_2 : total_output_net_capacitance;
index_1("0.0125, 0.05, 0.4");
index_2("2.45605, 9.8242, 78.5936");
}
lu_table_template(CONSTRAINT_TABLE){
variable_1 : related_pin_transition;
variable_2 : constrained_pin_transition;
index_1("0.0125, 0.05, 0.4");
index_2("0.0125, 0.05, 0.4");
}
default_operating_conditions : OC;
type (DATA){
base_type : array;
data_type : bit;
bit_width : 4;
bit_from : 0;
bit_to : 3;
}
type (ADDR){
base_type : array;
data_type : bit;
bit_width : 4;
bit_from : 0;
bit_to : 3;
}
cell (sram1){
memory(){
type : ram;
address_width : 4;
word_width : 4;
}
interface_timing : true;
dont_use : true;
map_only : true;
dont_touch : true;
area : 136566.0;
leakage_power () {
when : "CSb";
value : 0.000202;
}
cell_leakage_power : 0;
bus(DATA){
bus_type : DATA;
direction : inout;
max_capacitance : 78.5936;
min_capacitance : 2.45605;
three_state : "!OEb & !clk";
memory_write(){
address : ADDR;
clocked_on : clk;
}
memory_read(){
address : ADDR;
}
pin(DATA[3:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
timing(){
timing_sense : non_unate;
related_pin : "clk";
timing_type : falling_edge;
cell_rise(CELL_TABLE) {
values("0.612, 0.66, 1.1",\
"0.612, 0.66, 1.1",\
"0.612, 0.66, 1.1");
}
cell_fall(CELL_TABLE) {
values("0.612, 0.66, 1.1",\
"0.612, 0.66, 1.1",\
"0.612, 0.66, 1.1");
}
rise_transition(CELL_TABLE) {
values("0.024, 0.081, 0.61",\
"0.024, 0.081, 0.61",\
"0.024, 0.081, 0.61");
}
fall_transition(CELL_TABLE) {
values("0.024, 0.081, 0.61",\
"0.024, 0.081, 0.61",\
"0.024, 0.081, 0.61");
}
}
}
}
bus(ADDR){
bus_type : ADDR;
direction : input;
capacitance : 9.8242;
max_transition : 0.4;
pin(ADDR[3:0]){
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
}
}
pin(CSb){
direction : input;
capacitance : 9.8242;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
}
pin(OEb){
direction : input;
capacitance : 9.8242;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
}
pin(WEb){
direction : input;
capacitance : 9.8242;
timing(){
timing_type : setup_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009",\
"0.009, 0.009, 0.009");
}
}
timing(){
timing_type : hold_rising;
related_pin : "clk";
rise_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
fall_constraint(CONSTRAINT_TABLE) {
values("0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001",\
"0.001, 0.001, 0.001");
}
}
}
pin(clk){
clock : true;
direction : input;
capacitance : 9.8242;
internal_power(){
when : "!CSb & clk & !WEb";
rise_power(scalar){
values("10.812808757533329");
}
fall_power(scalar){
values("10.812808757533329");
}
}
internal_power(){
when : "!CSb & !clk & WEb";
rise_power(scalar){
values("10.812808757533329");
}
fall_power(scalar){
values("10.812808757533329");
}
}
internal_power(){
when : "CSb";
rise_power(scalar){
values("0");
}
fall_power(scalar){
values("0");
}
}
timing(){
timing_type :"min_pulse_width";
related_pin : clk;
rise_constraint(scalar) {
values("0.0");
}
fall_constraint(scalar) {
values("0.0");
}
}
timing(){
timing_type :"minimum_period";
related_pin : clk;
rise_constraint(scalar) {
values("0");
}
fall_constraint(scalar) {
values("0");
}
}
}
}
}