mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' of https://github.com/VLSIDA/PrivateRAM into multiport
This commit is contained in:
commit
7c3375fd4b
|
|
@ -20,7 +20,7 @@ other OpenRAM features. Please see the README.md file on how to run
|
||||||
the unit tests. Unit tests should work in all technologies. We will run
|
the unit tests. Unit tests should work in all technologies. We will run
|
||||||
the tests on your contributions before they will be accepted.
|
the tests on your contributions before they will be accepted.
|
||||||
|
|
||||||
# Internally Development
|
# Internal Development
|
||||||
|
|
||||||
For internal development, follow all of the following steps EXCEPT
|
For internal development, follow all of the following steps EXCEPT
|
||||||
do not fork your own copy. Instead, create a branch in our private repository
|
do not fork your own copy. Instead, create a branch in our private repository
|
||||||
|
|
@ -32,21 +32,21 @@ All unit tests should pass first.
|
||||||
1. One time, create a GitHub account at http://github.com
|
1. One time, create a GitHub account at http://github.com
|
||||||
|
|
||||||
2. Create a fork of the OpenRAM project on the github web page:
|
2. Create a fork of the OpenRAM project on the github web page:
|
||||||
https://github.com/mguthaus/OpenRAM
|
https://github.com/vlsida/openram
|
||||||
It is on the upper right and says "Fork": This will make your own
|
It is on the upper right and says "Fork": This will make your own
|
||||||
OpenRAM repository on GitHub in your account.
|
OpenRAM repository on GitHub in your account.
|
||||||
|
|
||||||
3. Clone your repository (or use an existing cloned copy if you've
|
3. Clone your repository (or use an existing cloned copy if you've
|
||||||
already done this once):
|
already done this once):
|
||||||
```
|
```
|
||||||
git clone https://github.com/<youruser>/OpenRAM.git
|
git clone https://github.com/<youruser>/oepnram.git
|
||||||
cd OpenRAM
|
cd openram
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Set up a new upstream that points to MY OpenRAM repository that you
|
4. Set up a new upstream that points to MY OpenRAM repository that you
|
||||||
forked (only first time):
|
forked (only first time):
|
||||||
```
|
```
|
||||||
git remote add upstream https://github.com/mguthaus/OpenRAM.git
|
git remote add upstream https://github.com/vlsida/openram.git
|
||||||
```
|
```
|
||||||
You now have two remotes for this project:
|
You now have two remotes for this project:
|
||||||
* origin which points to your GitHub fork of the project. You can read
|
* origin which points to your GitHub fork of the project. You can read
|
||||||
|
|
|
||||||
|
|
@ -88,9 +88,9 @@ def get_libcell_size(name, units, layer):
|
||||||
return(get_gds_size(name, cell_gds, units, layer))
|
return(get_gds_size(name, cell_gds, units, layer))
|
||||||
|
|
||||||
|
|
||||||
def get_gds_pins(pin_list, name, gds_filename, units, layer):
|
def get_gds_pins(pin_names, name, gds_filename, units):
|
||||||
"""
|
"""
|
||||||
Open a GDS file and find the pins in pin_list as text on a given layer.
|
Open a GDS file and find the pins in pin_names as text on a given layer.
|
||||||
Return these as a rectangle layer pair for each pin.
|
Return these as a rectangle layer pair for each pin.
|
||||||
"""
|
"""
|
||||||
cell_vlsi = gdsMill.VlsiLayout(units=units)
|
cell_vlsi = gdsMill.VlsiLayout(units=units)
|
||||||
|
|
@ -98,23 +98,23 @@ def get_gds_pins(pin_list, name, gds_filename, units, layer):
|
||||||
reader.loadFromFile(gds_filename)
|
reader.loadFromFile(gds_filename)
|
||||||
|
|
||||||
cell = {}
|
cell = {}
|
||||||
for pin in pin_list:
|
for pin_name in pin_names:
|
||||||
cell[str(pin)]=[]
|
cell[str(pin_name)]=[]
|
||||||
label_list=cell_vlsi.getPinShapeByLabel(str(pin))
|
pin_list=cell_vlsi.getPinShape(str(pin_name))
|
||||||
for label in label_list:
|
for pin_shape in pin_list:
|
||||||
(name,layer,boundary)=label
|
(layer,boundary)=pin_shape
|
||||||
rect=[vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])]
|
rect=[vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])]
|
||||||
# this is a list because other cells/designs may have must-connect pins
|
# this is a list because other cells/designs may have must-connect pins
|
||||||
cell[str(pin)].append(pin_layout(pin, rect, layer))
|
cell[str(pin_name)].append(pin_layout(pin_name, rect, layer))
|
||||||
return cell
|
return cell
|
||||||
|
|
||||||
def get_libcell_pins(pin_list, name, units, layer):
|
def get_libcell_pins(pin_list, name, units):
|
||||||
"""
|
"""
|
||||||
Open a GDS file and find the pins in pin_list as text on a given layer.
|
Open a GDS file and find the pins in pin_list as text on a given layer.
|
||||||
Return these as a rectangle layer pair for each pin.
|
Return these as a rectangle layer pair for each pin.
|
||||||
"""
|
"""
|
||||||
cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds"
|
cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds"
|
||||||
return(get_gds_pins(pin_list, name, cell_gds, units, layer))
|
return(get_gds_pins(pin_list, name, cell_gds, units))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ class bitcell(design.design):
|
||||||
|
|
||||||
pin_names = ["bl", "br", "wl", "vdd", "gnd"]
|
pin_names = ["bl", "br", "wl", "vdd", "gnd"]
|
||||||
(width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"])
|
(width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"])
|
||||||
pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"], layer["boundary"])
|
pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"])
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
design.design.__init__(self, "cell_6t")
|
design.design.__init__(self, "cell_6t")
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ class bitcell_1rw_1r(design.design):
|
||||||
|
|
||||||
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
|
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
|
||||||
(width,height) = utils.get_libcell_size("cell_1rw_1r", GDS["unit"], layer["boundary"])
|
(width,height) = utils.get_libcell_size("cell_1rw_1r", GDS["unit"], layer["boundary"])
|
||||||
pin_map = utils.get_libcell_pins(pin_names, "cell_1rw_1r", GDS["unit"], layer["boundary"])
|
pin_map = utils.get_libcell_pins(pin_names, "cell_1rw_1r", GDS["unit"])
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
design.design.__init__(self, "cell_1rw_1r")
|
design.design.__init__(self, "cell_1rw_1r")
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ class replica_bitcell(design.design):
|
||||||
|
|
||||||
pin_names = ["bl", "br", "wl", "vdd", "gnd"]
|
pin_names = ["bl", "br", "wl", "vdd", "gnd"]
|
||||||
(width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"])
|
(width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"])
|
||||||
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"], layer["boundary"])
|
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"])
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
design.design.__init__(self, "replica_cell_6t")
|
design.design.__init__(self, "replica_cell_6t")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import design
|
||||||
|
import debug
|
||||||
|
import utils
|
||||||
|
from tech import GDS,layer
|
||||||
|
|
||||||
|
class replica_bitcell_1rw_1r(design.design):
|
||||||
|
"""
|
||||||
|
A single bit cell which is forced to store a 0.
|
||||||
|
This module implements the single memory cell used in the design. It
|
||||||
|
is a hand-made cell, so the layout and netlist should be available in
|
||||||
|
the technology library. """
|
||||||
|
|
||||||
|
pin_names = ["bl0", "br0", "bl1", "br1", "wl0", "wl1", "vdd", "gnd"]
|
||||||
|
(width,height) = utils.get_libcell_size("replica_cell_1rw_1r", GDS["unit"], layer["boundary"])
|
||||||
|
pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1rw_1r", GDS["unit"])
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
design.design.__init__(self, "replica_cell_1rw_1r")
|
||||||
|
debug.info(2, "Create replica bitcell 1rw+1r object")
|
||||||
|
|
||||||
|
self.width = replica_bitcell_1rw_1r.width
|
||||||
|
self.height = replica_bitcell_1rw_1r.height
|
||||||
|
self.pin_map = replica_bitcell_1rw_1r.pin_map
|
||||||
|
|
@ -35,7 +35,15 @@ class functional(simulation):
|
||||||
self.stored_words = {}
|
self.stored_words = {}
|
||||||
self.write_check = []
|
self.write_check = []
|
||||||
self.read_check = []
|
self.read_check = []
|
||||||
|
|
||||||
|
def set_spice_constants(self):
|
||||||
|
"""Spice constants for functional test"""
|
||||||
|
simulation.set_spice_constants(self)
|
||||||
|
#Heuristic increase for functional period. Base feasible period typically does not pass the functional test
|
||||||
|
#for column mux of this size. Increase the feasible period by 20% for this case.
|
||||||
|
if self.sram.words_per_row >= 4:
|
||||||
|
self.period = self.period*1.2
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# Generate a random sequence of reads and writes
|
# Generate a random sequence of reads and writes
|
||||||
self.write_random_memory_sequence()
|
self.write_random_memory_sequence()
|
||||||
|
|
|
||||||
|
|
@ -208,14 +208,14 @@ class simulation():
|
||||||
t_current,
|
t_current,
|
||||||
t_current+self.period)
|
t_current+self.period)
|
||||||
elif op == "write":
|
elif op == "write":
|
||||||
comment = "\tWriting {0} to address {1} (from port {2}) during cylce {3} ({4}ns - {5}ns)".format(word,
|
comment = "\tWriting {0} to address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word,
|
||||||
addr,
|
addr,
|
||||||
port,
|
port,
|
||||||
int(t_current/self.period),
|
int(t_current/self.period),
|
||||||
t_current,
|
t_current,
|
||||||
t_current+self.period)
|
t_current+self.period)
|
||||||
else:
|
else:
|
||||||
comment = "\tReading {0} from address {1} (from port {2}) during cylce {3} ({4}ns - {5}ns)".format(word,
|
comment = "\tReading {0} from address {1} (from port {2}) during cycle {3} ({4}ns - {5}ns)".format(word,
|
||||||
addr,
|
addr,
|
||||||
port,
|
port,
|
||||||
int(t_current/self.period),
|
int(t_current/self.period),
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,3 @@ temperatures = [25]
|
||||||
output_path = "temp"
|
output_path = "temp"
|
||||||
output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name)
|
output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name)
|
||||||
|
|
||||||
#Setting for multiport
|
|
||||||
# netlist_only = True
|
|
||||||
# bitcell = "pbitcell"
|
|
||||||
# replica_bitcell="replica_pbitcell"
|
|
||||||
# num_rw_ports = 1
|
|
||||||
# num_r_ports = 0
|
|
||||||
# num_w_ports = 1
|
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,12 @@ num_words = 16
|
||||||
|
|
||||||
tech_name = "scn4m_subm"
|
tech_name = "scn4m_subm"
|
||||||
process_corners = ["TT"]
|
process_corners = ["TT"]
|
||||||
supply_voltages = [ 5.0 ]
|
supply_voltages = [ 3.3 ]
|
||||||
temperatures = [ 25 ]
|
temperatures = [ 25 ]
|
||||||
|
|
||||||
output_path = "temp"
|
output_path = "temp"
|
||||||
output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name)
|
output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name)
|
||||||
|
|
||||||
#Setting for multiport
|
drc_name = "magic"
|
||||||
netlist_only = True
|
lvs_name = "netgen"
|
||||||
bitcell = "pbitcell"
|
pex_name = "magic"
|
||||||
replica_bitcell="replica_pbitcell"
|
|
||||||
num_rw_ports = 1
|
|
||||||
num_r_ports = 1
|
|
||||||
num_w_ports = 1
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,11 @@ class VlsiLayout:
|
||||||
self.tempCoordinates=None
|
self.tempCoordinates=None
|
||||||
self.tempPassFail = True
|
self.tempPassFail = True
|
||||||
|
|
||||||
|
# This is a dict indexed by the pin labels.
|
||||||
|
# It contains a list of list of shapes, one for each occurance of the label.
|
||||||
|
# Multiple labels may be disconnected.
|
||||||
|
self.pins = {}
|
||||||
|
|
||||||
def rotatedCoordinates(self,coordinatesToRotate,rotateAngle):
|
def rotatedCoordinates(self,coordinatesToRotate,rotateAngle):
|
||||||
#helper method to rotate a list of coordinates
|
#helper method to rotate a list of coordinates
|
||||||
angle=math.radians(float(0))
|
angle=math.radians(float(0))
|
||||||
|
|
@ -206,7 +211,11 @@ class VlsiLayout:
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.deduceHierarchy()
|
self.deduceHierarchy()
|
||||||
#self.traverseTheHierarchy()
|
#self.traverseTheHierarchy()
|
||||||
self.populateCoordinateMap()
|
self.populateCoordinateMap()
|
||||||
|
|
||||||
|
for layerNumber in self.layerNumbersInUse:
|
||||||
|
self.processLabelPins(layerNumber)
|
||||||
|
|
||||||
|
|
||||||
def populateCoordinateMap(self):
|
def populateCoordinateMap(self):
|
||||||
def addToXyTree(startingStructureName = None,transformPath = None):
|
def addToXyTree(startingStructureName = None,transformPath = None):
|
||||||
|
|
@ -478,6 +487,10 @@ class VlsiLayout:
|
||||||
return False #these shapes are ok
|
return False #these shapes are ok
|
||||||
|
|
||||||
def isPointInsideOfBox(self,pointCoordinates,boxCoordinates):
|
def isPointInsideOfBox(self,pointCoordinates,boxCoordinates):
|
||||||
|
"""
|
||||||
|
Check if a point is contained in the shape
|
||||||
|
"""
|
||||||
|
debug.check(len(boxCoordinates)==4,"Invalid number of coordinates for box.")
|
||||||
leftBound = boxCoordinates[0][0]
|
leftBound = boxCoordinates[0][0]
|
||||||
rightBound = boxCoordinates[0][0]
|
rightBound = boxCoordinates[0][0]
|
||||||
topBound = boxCoordinates[0][1]
|
topBound = boxCoordinates[0][1]
|
||||||
|
|
@ -499,7 +512,9 @@ class VlsiLayout:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def isShapeInsideOfBox(self,shapeCoordinates, boxCoordinates):
|
def isShapeInsideOfBox(self,shapeCoordinates, boxCoordinates):
|
||||||
#go through every point in the shape to test if they are all inside the box
|
"""
|
||||||
|
Go through every point in the shape to test if they are all inside the box.
|
||||||
|
"""
|
||||||
for point in shapeCoordinates:
|
for point in shapeCoordinates:
|
||||||
if not self.isPointInsideOfBox(point,boxCoordinates):
|
if not self.isPointInsideOfBox(point,boxCoordinates):
|
||||||
return False
|
return False
|
||||||
|
|
@ -634,160 +649,89 @@ class VlsiLayout:
|
||||||
return cellBoundary
|
return cellBoundary
|
||||||
|
|
||||||
|
|
||||||
def getLabelDBInfo(self,label_name):
|
def getTexts(self, layer):
|
||||||
"""
|
"""
|
||||||
Return the coordinates in DB units and layer of all matching labels
|
Get all of the labels on a given layer only at the root level.
|
||||||
"""
|
"""
|
||||||
label_list = []
|
text_list = []
|
||||||
label_layer = None
|
|
||||||
label_coordinate = [None, None]
|
|
||||||
|
|
||||||
# Why must this be the last one found? It breaks if we return the first.
|
|
||||||
for Text in self.structures[self.rootStructureName].texts:
|
for Text in self.structures[self.rootStructureName].texts:
|
||||||
if Text.textString == label_name or Text.textString == label_name+"\x00":
|
if Text.drawingLayer == layer:
|
||||||
label_layer = Text.drawingLayer
|
text_list.append(Text)
|
||||||
label_coordinate = Text.coordinates[0]
|
return text_list
|
||||||
if label_layer!=None:
|
|
||||||
label_list.append((label_coordinate,label_layer))
|
|
||||||
|
|
||||||
debug.check(len(label_list)>0,"Did not find labels {0}.".format(label_name))
|
|
||||||
return label_list
|
|
||||||
|
|
||||||
|
|
||||||
def getLabelInfo(self,label_name):
|
|
||||||
"""
|
|
||||||
Return the coordinates in USER units and layer of a label
|
|
||||||
"""
|
|
||||||
label_list=self.getLabelDBInfo(label_name)
|
|
||||||
new_list=[]
|
|
||||||
for label in label_list:
|
|
||||||
(label_coordinate,label_layer)=label
|
|
||||||
user_coordinates = [x*self.units[0] for x in label_coordinate]
|
|
||||||
new_list.append(user_coordinates,label_layer)
|
|
||||||
return new_list
|
|
||||||
|
|
||||||
def getPinShapeByLocLayer(self, coordinate, layer):
|
def getPinShape(self, pin_name):
|
||||||
"""
|
|
||||||
Return the largest enclosing rectangle on a layer and at a location.
|
|
||||||
Coordinates should be in USER units.
|
|
||||||
"""
|
|
||||||
db_coordinate = [x/self.units[0] for x in coordinate]
|
|
||||||
return self.getPinShapeByDBLocLayer(db_coordinate, layer)
|
|
||||||
|
|
||||||
def getPinShapeByDBLocLayer(self, coordinate, layer):
|
|
||||||
"""
|
|
||||||
Return the largest enclosing rectangle on a layer and at a location.
|
|
||||||
Coordinates should be in DB units.
|
|
||||||
"""
|
|
||||||
pin_boundaries=self.getAllPinShapesInStructureList(coordinate, layer)
|
|
||||||
|
|
||||||
if len(pin_boundaries) == 0:
|
|
||||||
debug.warning("Did not find pin on layer {0} at coordinate {1}".format(layer, coordinate))
|
|
||||||
|
|
||||||
# sort the boundaries, return the max area pin boundary
|
|
||||||
pin_boundaries.sort(key=boundaryArea,reverse=True)
|
|
||||||
pin_boundary=pin_boundaries[0]
|
|
||||||
|
|
||||||
# Convert to USER units
|
|
||||||
pin_boundary=[pin_boundary[0]*self.units[0],pin_boundary[1]*self.units[0],
|
|
||||||
pin_boundary[2]*self.units[0],pin_boundary[3]*self.units[0]]
|
|
||||||
|
|
||||||
# Make a name if we don't have the pin name
|
|
||||||
return ["p"+str(coordinate)+"_"+str(layer), layer, pin_boundary]
|
|
||||||
|
|
||||||
def getAllPinShapesByLocLayer(self, coordinate, layer):
|
|
||||||
"""
|
|
||||||
Return ALL the enclosing rectangles on the same layer
|
|
||||||
at the given coordinate. Coordinates should be in USER units.
|
|
||||||
"""
|
|
||||||
db_coordinate = [int(x/self.units[0]) for x in coordinate]
|
|
||||||
return self.getAllPinShapesByDBLocLayer(db_coordinate, layer)
|
|
||||||
|
|
||||||
def getAllPinShapesByDBLocLayer(self, coordinate, layer):
|
|
||||||
"""
|
|
||||||
Return ALL the enclosing rectangles on the same layer
|
|
||||||
at the given coordinate. Input coordinates should be in DB units.
|
|
||||||
Returns user unit shapes.
|
|
||||||
"""
|
|
||||||
pin_boundaries=self.getAllPinShapesInStructureList(coordinate, layer)
|
|
||||||
|
|
||||||
# Convert to user units
|
|
||||||
new_boundaries = []
|
|
||||||
for pin_boundary in pin_boundaries:
|
|
||||||
new_pin_boundary = [pin_boundary[0]*self.units[0],pin_boundary[1]*self.units[0],
|
|
||||||
pin_boundary[2]*self.units[0],pin_boundary[3]*self.units[0]]
|
|
||||||
new_boundaries.append(["p"+str(coordinate)+"_"+str(layer), layer, new_pin_boundary])
|
|
||||||
return new_boundaries
|
|
||||||
|
|
||||||
def getPinShapeByLabel(self,label_name):
|
|
||||||
"""
|
"""
|
||||||
Search for a pin label and return the largest enclosing rectangle
|
Search for a pin label and return the largest enclosing rectangle
|
||||||
on the same layer as the pin label.
|
on the same layer as the pin label.
|
||||||
|
If there are multiple pin lists, return the max of each.
|
||||||
"""
|
"""
|
||||||
label_list=self.getLabelDBInfo(label_name)
|
pin_map = self.pins[pin_name]
|
||||||
shape_list=[]
|
max_pins = []
|
||||||
for label in label_list:
|
for pin_list in pin_map:
|
||||||
(label_coordinate,label_layer)=label
|
max_pin = None
|
||||||
shape = self.getPinShapeByDBLocLayer(label_coordinate, label_layer)
|
max_area = 0
|
||||||
shape_list.append(shape)
|
for pin in pin_list:
|
||||||
return shape_list
|
(layer,boundary) = pin
|
||||||
|
new_area = boundaryArea(boundary)
|
||||||
|
if max_pin == None or new_area>max_area:
|
||||||
|
max_pin = pin
|
||||||
|
max_area = new_area
|
||||||
|
max_pins.append(max_pin)
|
||||||
|
|
||||||
def getAllPinShapesByLabel(self,label_name):
|
return max_pins
|
||||||
|
|
||||||
|
|
||||||
|
def getAllPinShapes(self, pin_name):
|
||||||
"""
|
"""
|
||||||
Search for a pin label and return ALL the enclosing rectangles on the same layer
|
Search for a pin label and return ALL the enclosing rectangles on the same layer
|
||||||
as the pin label.
|
as the pin label.
|
||||||
"""
|
"""
|
||||||
|
shape_list = []
|
||||||
label_list=self.getLabelDBInfo(label_name)
|
pin_map = self.pins[pin_name]
|
||||||
shape_list=[]
|
for pin_list in pin_map:
|
||||||
for label in label_list:
|
for pin in pin_list:
|
||||||
(label_coordinate,label_layer)=label
|
(pin_layer, boundary) = pin
|
||||||
shape_list.extend(self.getAllPinShapesByDBLocLayer(label_coordinate, label_layer))
|
shape_list.append(pin)
|
||||||
|
|
||||||
return shape_list
|
return shape_list
|
||||||
|
|
||||||
def getAllPinShapesInStructureList(self,coordinates,layer):
|
|
||||||
|
def processLabelPins(self, layer):
|
||||||
"""
|
"""
|
||||||
Given a coordinate, search for enclosing structures on the given layer.
|
Find all text labels and create a map to a list of shapes that
|
||||||
Return all pin shapes.
|
they enclose on the given layer.
|
||||||
"""
|
"""
|
||||||
boundaries = []
|
# Get the labels on a layer in the root level
|
||||||
for TreeUnit in self.xyTree:
|
labels = self.getTexts(layer)
|
||||||
boundaries.extend(self.getPinInStructure(coordinates,layer,TreeUnit))
|
# Get all of the shapes on the layer at all levels
|
||||||
|
# and transform them to the current level
|
||||||
|
shapes = self.getAllShapes(layer)
|
||||||
|
|
||||||
return boundaries
|
for label in labels:
|
||||||
|
label_coordinate = label.coordinates[0]
|
||||||
|
user_coordinate = [x*self.units[0] for x in label_coordinate]
|
||||||
|
pin_shapes = []
|
||||||
|
for boundary in shapes:
|
||||||
|
if self.labelInRectangle(user_coordinate,boundary):
|
||||||
|
pin_shapes.append((layer, boundary))
|
||||||
|
|
||||||
|
label_text = label.textString
|
||||||
|
# Remove the padding if it exists
|
||||||
|
if label_text[-1] == "\x00":
|
||||||
|
label_text = label_text[0:-1]
|
||||||
|
|
||||||
def getPinInStructure(self,coordinates,layer,structure):
|
try:
|
||||||
"""
|
self.pins[label_text]
|
||||||
Go through all the shapes in a structure and return the list of shapes
|
except KeyError:
|
||||||
that the label coordinates are inside.
|
self.pins[label_text] = []
|
||||||
|
self.pins[label_text].append(pin_shapes)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def getAllShapes(self,layer):
|
||||||
"""
|
"""
|
||||||
|
Return all gshapes on a given layer in [llx, lly, urx, ury] format and
|
||||||
(structureName,structureOrigin,structureuVector,structurevVector)=structure
|
user units.
|
||||||
boundaries = []
|
|
||||||
for boundary in self.structures[str(structureName)].boundaries:
|
|
||||||
# Pin enclosures only work on rectangular pins so ignore any non rectangle
|
|
||||||
# This may report not finding pins, but the user should fix this by adding a rectangle.
|
|
||||||
if len(boundary.coordinates)!=5:
|
|
||||||
continue
|
|
||||||
if layer==boundary.drawingLayer:
|
|
||||||
left_bottom=boundary.coordinates[0]
|
|
||||||
right_top=boundary.coordinates[2]
|
|
||||||
# Rectangle is [leftx, bottomy, rightx, topy].
|
|
||||||
boundaryRect=[left_bottom[0],left_bottom[1],right_top[0],right_top[1]]
|
|
||||||
boundaryRect=self.transformRectangle(boundaryRect,structureuVector,structurevVector)
|
|
||||||
boundaryRect=[boundaryRect[0]+structureOrigin[0].item(),boundaryRect[1]+structureOrigin[1].item(),
|
|
||||||
boundaryRect[2]+structureOrigin[0].item(),boundaryRect[3]+structureOrigin[1].item()]
|
|
||||||
|
|
||||||
if self.labelInRectangle(coordinates,boundaryRect):
|
|
||||||
boundaries.append(boundaryRect)
|
|
||||||
|
|
||||||
return boundaries
|
|
||||||
|
|
||||||
|
|
||||||
def getAllShapesInStructureList(self,layer):
|
|
||||||
"""
|
|
||||||
Return all pin shapes on a given layer.
|
|
||||||
"""
|
"""
|
||||||
boundaries = []
|
boundaries = []
|
||||||
for TreeUnit in self.xyTree:
|
for TreeUnit in self.xyTree:
|
||||||
|
|
@ -812,7 +756,8 @@ class VlsiLayout:
|
||||||
|
|
||||||
def getShapesInStructure(self,layer,structure):
|
def getShapesInStructure(self,layer,structure):
|
||||||
"""
|
"""
|
||||||
Go through all the shapes in a structure and return the list of shapes.
|
Go through all the shapes in a structure and return the list of shapes in
|
||||||
|
the form [llx, lly, urx, ury]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
(structureName,structureOrigin,structureuVector,structurevVector)=structure
|
(structureName,structureOrigin,structureuVector,structurevVector)=structure
|
||||||
|
|
@ -820,6 +765,7 @@ class VlsiLayout:
|
||||||
boundaries = []
|
boundaries = []
|
||||||
for boundary in self.structures[str(structureName)].boundaries:
|
for boundary in self.structures[str(structureName)].boundaries:
|
||||||
# FIXME: Right now, this only supports rectangular shapes!
|
# FIXME: Right now, this only supports rectangular shapes!
|
||||||
|
#debug.check(len(boundary.coordinates)==5,"Non-rectangular shape.")
|
||||||
if len(boundary.coordinates)!=5:
|
if len(boundary.coordinates)!=5:
|
||||||
continue
|
continue
|
||||||
if layer==boundary.drawingLayer:
|
if layer==boundary.drawingLayer:
|
||||||
|
|
@ -874,8 +820,8 @@ class VlsiLayout:
|
||||||
"""
|
"""
|
||||||
Checks if a coordinate is within a given rectangle. Rectangle is [leftx, bottomy, rightx, topy].
|
Checks if a coordinate is within a given rectangle. Rectangle is [leftx, bottomy, rightx, topy].
|
||||||
"""
|
"""
|
||||||
coordinate_In_Rectangle_x_range=(coordinate[0]>=int(rectangle[0]))&(coordinate[0]<=int(rectangle[2]))
|
coordinate_In_Rectangle_x_range=(coordinate[0]>=rectangle[0])&(coordinate[0]<=rectangle[2])
|
||||||
coordinate_In_Rectangle_y_range=(coordinate[1]>=int(rectangle[1]))&(coordinate[1]<=int(rectangle[3]))
|
coordinate_In_Rectangle_y_range=(coordinate[1]>=rectangle[1])&(coordinate[1]<=rectangle[3])
|
||||||
if coordinate_In_Rectangle_x_range & coordinate_In_Rectangle_y_range:
|
if coordinate_In_Rectangle_x_range & coordinate_In_Rectangle_y_range:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,14 @@ class control_logic(design.design):
|
||||||
Dynamically generated Control logic for the total SRAM circuit.
|
Dynamically generated Control logic for the total SRAM circuit.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, num_rows, port_type="rw"):
|
def __init__(self, num_rows, words_per_row, port_type="rw"):
|
||||||
""" Constructor """
|
""" Constructor """
|
||||||
name = "control_logic_" + port_type
|
name = "control_logic_" + port_type
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
debug.info(1, "Creating {}".format(name))
|
debug.info(1, "Creating {}".format(name))
|
||||||
|
|
||||||
self.num_rows = num_rows
|
self.num_rows = num_rows
|
||||||
|
self.words_per_row = words_per_row
|
||||||
self.port_type = port_type
|
self.port_type = port_type
|
||||||
|
|
||||||
if self.port_type == "rw":
|
if self.port_type == "rw":
|
||||||
|
|
@ -92,14 +93,25 @@ class control_logic(design.design):
|
||||||
from importlib import reload
|
from importlib import reload
|
||||||
c = reload(__import__(OPTS.replica_bitline))
|
c = reload(__import__(OPTS.replica_bitline))
|
||||||
replica_bitline = getattr(c, OPTS.replica_bitline)
|
replica_bitline = getattr(c, OPTS.replica_bitline)
|
||||||
# FIXME: These should be tuned according to the size!
|
|
||||||
delay_stages = 4 # Must be non-inverting
|
delay_stages, delay_fanout = self.get_delay_chain_size()
|
||||||
delay_fanout = 3 # This can be anything >=2
|
|
||||||
bitcell_loads = int(math.ceil(self.num_rows / 2.0))
|
bitcell_loads = int(math.ceil(self.num_rows / 2.0))
|
||||||
self.replica_bitline = replica_bitline(delay_stages, delay_fanout, bitcell_loads, name="replica_bitline_"+self.port_type)
|
self.replica_bitline = replica_bitline(delay_stages, delay_fanout, bitcell_loads, name="replica_bitline_"+self.port_type)
|
||||||
self.add_mod(self.replica_bitline)
|
self.add_mod(self.replica_bitline)
|
||||||
|
|
||||||
|
def get_delay_chain_size(self):
|
||||||
|
"""Determine the size of the delay chain used for the Sense Amp Enable """
|
||||||
|
# FIXME: These should be tuned according to the additional size parameters
|
||||||
|
delay_fanout = 3 # This can be anything >=2
|
||||||
|
# Delay stages Must be non-inverting
|
||||||
|
if self.words_per_row >= 8:
|
||||||
|
delay_stages = 8
|
||||||
|
elif self.words_per_row == 4:
|
||||||
|
delay_stages = 6
|
||||||
|
else:
|
||||||
|
delay_stages = 4
|
||||||
|
return (delay_stages, delay_fanout)
|
||||||
|
|
||||||
def setup_signal_busses(self):
|
def setup_signal_busses(self):
|
||||||
""" Setup bus names, determine the size of the busses etc """
|
""" Setup bus names, determine the size of the busses etc """
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ class dff(design.design):
|
||||||
|
|
||||||
pin_names = ["D", "Q", "clk", "vdd", "gnd"]
|
pin_names = ["D", "Q", "clk", "vdd", "gnd"]
|
||||||
(width,height) = utils.get_libcell_size("dff", GDS["unit"], layer["boundary"])
|
(width,height) = utils.get_libcell_size("dff", GDS["unit"], layer["boundary"])
|
||||||
pin_map = utils.get_libcell_pins(pin_names, "dff", GDS["unit"], layer["boundary"])
|
pin_map = utils.get_libcell_pins(pin_names, "dff", GDS["unit"])
|
||||||
|
|
||||||
def __init__(self, name="dff"):
|
def __init__(self, name="dff"):
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
|
|
|
||||||
|
|
@ -189,16 +189,66 @@ class replica_bitline(design.design):
|
||||||
|
|
||||||
if pin.layer != "metal1":
|
if pin.layer != "metal1":
|
||||||
continue
|
continue
|
||||||
self.add_path("metal1", [pin_right, pin_extension])
|
pin_width_ydir = pin.uy()-pin.by()
|
||||||
|
#Width is set to pin y width to avoid DRC issues with m1 gaps
|
||||||
|
self.add_path("metal1", [pin_right, pin_extension], pin_width_ydir)
|
||||||
self.add_power_pin("gnd", pin_extension)
|
self.add_power_pin("gnd", pin_extension)
|
||||||
|
|
||||||
# for multiport, need to short wordlines to each other so they all connect to gnd
|
# for multiport, need to short wordlines to each other so they all connect to gnd.
|
||||||
wl_last = self.wl_list[self.total_ports-1]+"_{}".format(row)
|
wl_last = self.wl_list[self.total_ports-1]+"_{}".format(row)
|
||||||
pin_last = self.rbl_inst.get_pin(wl_last)
|
pin_last = self.rbl_inst.get_pin(wl_last)
|
||||||
|
self.short_wordlines(pin, pin_last, "right", False, row, vector(self.m3_pitch,0))
|
||||||
|
|
||||||
|
def short_wordlines(self, wl_pin_a, wl_pin_b, pin_side, is_replica_cell, cell_row=0, offset_x_vec=None):
|
||||||
|
"""Connects the word lines together for a single bitcell. Also requires which side of the bitcell to short the pins."""
|
||||||
|
#Assumes input pins are wordlines. Also assumes the word lines are horizontal in metal1. Also assumes pins have same x coord.
|
||||||
|
#This is my (Hunter) first time editing layout in openram so this function is likely not optimal.
|
||||||
|
if self.total_ports > 1:
|
||||||
|
#1. Create vertical metal for all the bitlines to connect to
|
||||||
|
#m1 needs to be extended in the y directions, direction needs to be determined as every other cell is flipped
|
||||||
|
correct_y = vector(0, 0.5*drc("minwidth_metal1"))
|
||||||
|
#x spacing depends on the side being drawn. Unknown to me (Hunter) why the size of the space differs by the side.
|
||||||
|
#I assume this is related to how a wire is draw, but I have not investigated the issue.
|
||||||
|
if pin_side == "right":
|
||||||
|
correct_x = vector(0.5*drc("minwidth_metal1"), 0)
|
||||||
|
if offset_x_vec != None:
|
||||||
|
correct_x = offset_x_vec
|
||||||
|
else:
|
||||||
|
correct_x = vector(1.5*drc("minwidth_metal1"), 0)
|
||||||
|
|
||||||
|
if wl_pin_a.uy() > wl_pin_b.uy():
|
||||||
|
self.add_path("metal1", [wl_pin_a.rc()+correct_x+correct_y, wl_pin_b.rc()+correct_x-correct_y])
|
||||||
|
else:
|
||||||
|
self.add_path("metal1", [wl_pin_a.rc()+correct_x-correct_y, wl_pin_b.rc()+correct_x+correct_y])
|
||||||
|
elif pin_side == "left":
|
||||||
|
if offset_x_vec != None:
|
||||||
|
correct_x = offset_x_vec
|
||||||
|
else:
|
||||||
|
correct_x = vector(1.5*drc("minwidth_metal1"), 0)
|
||||||
|
|
||||||
|
if wl_pin_a.uy() > wl_pin_b.uy():
|
||||||
|
self.add_path("metal1", [wl_pin_a.lc()-correct_x+correct_y, wl_pin_b.lc()-correct_x-correct_y])
|
||||||
|
else:
|
||||||
|
self.add_path("metal1", [wl_pin_a.lc()-correct_x-correct_y, wl_pin_b.lc()-correct_x+correct_y])
|
||||||
|
else:
|
||||||
|
debug.error("Could not connect wordlines on specified input side={}".format(pin_side),1)
|
||||||
|
|
||||||
correct = vector(0.5*drc("minwidth_metal1"), 0)
|
#2. Connect word lines horizontally. Only replica cell needs. Bitline loads currently already do this.
|
||||||
self.add_path("metal1", [pin.rc()-correct, pin_last.rc()-correct])
|
for port in range(self.total_ports):
|
||||||
|
if is_replica_cell:
|
||||||
|
wl = self.wl_list[port]
|
||||||
|
pin = self.rbc_inst.get_pin(wl)
|
||||||
|
else:
|
||||||
|
wl = self.wl_list[port]+"_{}".format(cell_row)
|
||||||
|
pin = self.rbl_inst.get_pin(wl)
|
||||||
|
|
||||||
|
if pin_side == "left":
|
||||||
|
self.add_path("metal1", [pin.lc()-correct_x, pin.lc()])
|
||||||
|
elif pin_side == "right":
|
||||||
|
self.add_path("metal1", [pin.rc()+correct_x, pin.rc()])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def route_supplies(self):
|
def route_supplies(self):
|
||||||
""" Propagate all vdd/gnd pins up to this level for all modules """
|
""" Propagate all vdd/gnd pins up to this level for all modules """
|
||||||
|
|
||||||
|
|
@ -217,8 +267,13 @@ class replica_bitline(design.design):
|
||||||
|
|
||||||
# Replica bitcell needs to be routed up to M3
|
# Replica bitcell needs to be routed up to M3
|
||||||
pin=self.rbc_inst.get_pin("vdd")
|
pin=self.rbc_inst.get_pin("vdd")
|
||||||
# Don't rotate this via to vit in FreePDK45
|
# Don't rotate this via to vit in FreePDK45. In the custom cell, the pin cannot be placed
|
||||||
self.add_power_pin("vdd", pin.center(), rotate=0)
|
# directly on vdd or there will be a drc error with a wordline. Place the pin slightly farther
|
||||||
|
# away then route to it. A better solution would be to rotate the m1 in the via or move the pin
|
||||||
|
# a m1_pitch below the entire cell.
|
||||||
|
pin_extension = pin.center() - vector(0,self.m1_pitch)
|
||||||
|
self.add_power_pin("vdd", pin_extension, rotate=0)
|
||||||
|
self.add_path("metal1", [pin.center(), pin_extension])
|
||||||
|
|
||||||
for pin in self.rbc_inst.get_pins("gnd"):
|
for pin in self.rbc_inst.get_pins("gnd"):
|
||||||
self.add_power_pin("gnd", pin.center())
|
self.add_power_pin("gnd", pin.center())
|
||||||
|
|
@ -267,9 +322,10 @@ class replica_bitline(design.design):
|
||||||
wl_last = self.wl_list[self.total_ports-1]
|
wl_last = self.wl_list[self.total_ports-1]
|
||||||
pin = self.rbc_inst.get_pin(wl)
|
pin = self.rbc_inst.get_pin(wl)
|
||||||
pin_last = self.rbc_inst.get_pin(wl_last)
|
pin_last = self.rbc_inst.get_pin(wl_last)
|
||||||
|
x_offset = self.short_wordlines(pin, pin_last, "left", True)
|
||||||
|
|
||||||
correct = vector(0.5*drc("minwidth_metal1"), 0)
|
#correct = vector(0.5*drc("minwidth_metal1"), 0)
|
||||||
self.add_path("metal1", [pin.lc()+correct, pin_last.lc()+correct])
|
#self.add_path("metal1", [pin.lc()+correct, pin_last.lc()+correct])
|
||||||
|
|
||||||
# DRAIN ROUTE
|
# DRAIN ROUTE
|
||||||
# Route the drain to the vdd rail
|
# Route the drain to the vdd rail
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ class sense_amp(design.design):
|
||||||
|
|
||||||
pin_names = ["bl", "br", "dout", "en", "vdd", "gnd"]
|
pin_names = ["bl", "br", "dout", "en", "vdd", "gnd"]
|
||||||
(width,height) = utils.get_libcell_size("sense_amp", GDS["unit"], layer["boundary"])
|
(width,height) = utils.get_libcell_size("sense_amp", GDS["unit"], layer["boundary"])
|
||||||
pin_map = utils.get_libcell_pins(pin_names, "sense_amp", GDS["unit"], layer["boundary"])
|
pin_map = utils.get_libcell_pins(pin_names, "sense_amp", GDS["unit"])
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
|
|
@ -25,6 +25,7 @@ class sense_amp(design.design):
|
||||||
|
|
||||||
def input_load(self):
|
def input_load(self):
|
||||||
#Input load for the bitlines which are connected to the source/drain of a TX. Not the selects.
|
#Input load for the bitlines which are connected to the source/drain of a TX. Not the selects.
|
||||||
|
from tech import spice, parameter
|
||||||
bitline_pmos_size = 8 #FIXME: This should be set somewhere and referenced. Probably in tech file.
|
bitline_pmos_size = 8 #FIXME: This should be set somewhere and referenced. Probably in tech file.
|
||||||
return spice["min_tx_drain_c"]*(bitline_pmos_size/parameter["min_tx_size"])#ff
|
return spice["min_tx_drain_c"]*(bitline_pmos_size/parameter["min_tx_size"])#ff
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@ class single_level_column_mux_array(design.design):
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
def analytical_delay(self, vdd, slew, load=0.0):
|
def analytical_delay(self, vdd, slew, load=0.0):
|
||||||
from tech import spice
|
from tech import spice, parameter
|
||||||
r = spice["min_tx_r"]/(self.mux.ptx_width/parameter["min_tx_size"])
|
r = spice["min_tx_r"]/(self.mux.ptx_width/parameter["min_tx_size"])
|
||||||
#Drains of mux transistors make up capacitance.
|
#Drains of mux transistors make up capacitance.
|
||||||
c_para = spice["min_tx_drain_c"]*(self.mux.ptx_width/parameter["min_tx_size"])*self.words_per_row#ff
|
c_para = spice["min_tx_drain_c"]*(self.mux.ptx_width/parameter["min_tx_size"])*self.words_per_row#ff
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ class tri_gate(design.design):
|
||||||
|
|
||||||
pin_names = ["in", "en", "en_bar", "out", "gnd", "vdd"]
|
pin_names = ["in", "en", "en_bar", "out", "gnd", "vdd"]
|
||||||
(width,height) = utils.get_libcell_size("tri_gate", GDS["unit"], layer["boundary"])
|
(width,height) = utils.get_libcell_size("tri_gate", GDS["unit"], layer["boundary"])
|
||||||
pin_map = utils.get_libcell_pins(pin_names, "tri_gate", GDS["unit"], layer["boundary"])
|
pin_map = utils.get_libcell_pins(pin_names, "tri_gate", GDS["unit"])
|
||||||
|
|
||||||
unique_id = 1
|
unique_id = 1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ class write_driver(design.design):
|
||||||
|
|
||||||
pin_names = ["din", "bl", "br", "en", "gnd", "vdd"]
|
pin_names = ["din", "bl", "br", "en", "gnd", "vdd"]
|
||||||
(width,height) = utils.get_libcell_size("write_driver", GDS["unit"], layer["boundary"])
|
(width,height) = utils.get_libcell_size("write_driver", GDS["unit"], layer["boundary"])
|
||||||
pin_map = utils.get_libcell_pins(pin_names, "write_driver", GDS["unit"], layer["boundary"])
|
pin_map = utils.get_libcell_pins(pin_names, "write_driver", GDS["unit"])
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import sys
|
import sys
|
||||||
import gdsMill
|
import gdsMill
|
||||||
from tech import drc,GDS
|
from tech import drc,GDS
|
||||||
|
from tech import layer as techlayer
|
||||||
import math
|
import math
|
||||||
import debug
|
import debug
|
||||||
from router_tech import router_tech
|
from router_tech import router_tech
|
||||||
|
|
@ -39,7 +40,7 @@ class router(router_tech):
|
||||||
self.reader = gdsMill.Gds2reader(self.layout)
|
self.reader = gdsMill.Gds2reader(self.layout)
|
||||||
self.reader.loadFromFile(gds_filename)
|
self.reader.loadFromFile(gds_filename)
|
||||||
self.top_name = self.layout.rootStructureName
|
self.top_name = self.layout.rootStructureName
|
||||||
|
|
||||||
### The pin data structures
|
### The pin data structures
|
||||||
# A map of pin names to a set of pin_layout structures
|
# A map of pin names to a set of pin_layout structures
|
||||||
self.pins = {}
|
self.pins = {}
|
||||||
|
|
@ -66,7 +67,8 @@ class router(router_tech):
|
||||||
self.boundary = self.layout.measureBoundary(self.top_name)
|
self.boundary = self.layout.measureBoundary(self.top_name)
|
||||||
# These must be un-indexed to get rid of the matrix type
|
# These must be un-indexed to get rid of the matrix type
|
||||||
self.ll = vector(self.boundary[0][0], self.boundary[0][1])
|
self.ll = vector(self.boundary[0][0], self.boundary[0][1])
|
||||||
self.ur = vector(self.boundary[1][0], self.boundary[1][1])
|
# Pad the UR by a few tracks to add an extra rail possibly
|
||||||
|
self.ur = vector(self.boundary[1][0], self.boundary[1][1]) + self.track_widths.scale(5,5)
|
||||||
|
|
||||||
def clear_pins(self):
|
def clear_pins(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -94,12 +96,13 @@ class router(router_tech):
|
||||||
|
|
||||||
def retrieve_pins(self,pin_name):
|
def retrieve_pins(self,pin_name):
|
||||||
"""
|
"""
|
||||||
Retrieve the pin shapes from the layout.
|
Retrieve the pin shapes on metal 3 from the layout.
|
||||||
"""
|
"""
|
||||||
shape_list=self.layout.getAllPinShapesByLabel(str(pin_name))
|
debug.info(2,"Retrieving pins for {}.".format(pin_name))
|
||||||
|
shape_list=self.layout.getAllPinShapes(str(pin_name))
|
||||||
pin_set = set()
|
pin_set = set()
|
||||||
for shape in shape_list:
|
for shape in shape_list:
|
||||||
(name,layer,boundary)=shape
|
(layer,boundary)=shape
|
||||||
# GDSMill boundaries are in (left, bottom, right, top) order
|
# GDSMill boundaries are in (left, bottom, right, top) order
|
||||||
# so repack and snap to the grid
|
# so repack and snap to the grid
|
||||||
ll = vector(boundary[0],boundary[1]).snap_to_grid()
|
ll = vector(boundary[0],boundary[1]).snap_to_grid()
|
||||||
|
|
@ -114,7 +117,7 @@ class router(router_tech):
|
||||||
self.all_pins.update(pin_set)
|
self.all_pins.update(pin_set)
|
||||||
|
|
||||||
for pin in self.pins[pin_name]:
|
for pin in self.pins[pin_name]:
|
||||||
debug.info(2,"Retrieved pin {}".format(str(pin)))
|
debug.info(3,"Retrieved pin {}".format(str(pin)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -123,16 +126,17 @@ class router(router_tech):
|
||||||
Finds the pin shapes and converts to tracks.
|
Finds the pin shapes and converts to tracks.
|
||||||
Pin can either be a label or a location,layer pair: [[x,y],layer].
|
Pin can either be a label or a location,layer pair: [[x,y],layer].
|
||||||
"""
|
"""
|
||||||
|
debug.info(1,"Finding pins for {}.".format(pin_name))
|
||||||
self.retrieve_pins(pin_name)
|
self.retrieve_pins(pin_name)
|
||||||
self.analyze_pins(pin_name)
|
self.analyze_pins(pin_name)
|
||||||
|
|
||||||
|
|
||||||
def find_blockages(self):
|
def find_blockages(self):
|
||||||
"""
|
"""
|
||||||
Iterate through all the layers and write the obstacles to the routing grid.
|
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
|
This doesn't consider whether the obstacles will be pins or not. They get reset later
|
||||||
if they are not actually a blockage.
|
if they are not actually a blockage.
|
||||||
"""
|
"""
|
||||||
|
debug.info(1,"Finding blockages.")
|
||||||
for layer in [self.vert_layer_number,self.horiz_layer_number]:
|
for layer in [self.vert_layer_number,self.horiz_layer_number]:
|
||||||
self.retrieve_blockages(layer)
|
self.retrieve_blockages(layer)
|
||||||
|
|
||||||
|
|
@ -203,15 +207,15 @@ class router(router_tech):
|
||||||
if pg1.adjacent(pg2):
|
if pg1.adjacent(pg2):
|
||||||
combined = pin_group(pin_name, [], self)
|
combined = pin_group(pin_name, [], self)
|
||||||
combined.combine_groups(pg1, pg2)
|
combined.combine_groups(pg1, pg2)
|
||||||
debug.info(2,"Combining {0} {1} {2}:".format(pin_name, index1, index2))
|
debug.info(3,"Combining {0} {1} {2}:".format(pin_name, index1, index2))
|
||||||
debug.info(2, " {0}\n {1}".format(pg1.pins, pg2.pins))
|
debug.info(3, " {0}\n {1}".format(pg1.pins, pg2.pins))
|
||||||
debug.info(2," --> {0}\n {1}".format(combined.pins,combined.grids))
|
debug.info(3," --> {0}\n {1}".format(combined.pins,combined.grids))
|
||||||
remove_indices.update([index1,index2])
|
remove_indices.update([index1,index2])
|
||||||
pin_groups.append(combined)
|
pin_groups.append(combined)
|
||||||
break
|
break
|
||||||
|
|
||||||
# Remove them in decreasing order to not invalidate the indices
|
# Remove them in decreasing order to not invalidate the indices
|
||||||
debug.info(2,"Removing {}".format(sorted(remove_indices)))
|
debug.info(4,"Removing {}".format(sorted(remove_indices)))
|
||||||
for i in sorted(remove_indices, reverse=True):
|
for i in sorted(remove_indices, reverse=True):
|
||||||
del pin_groups[i]
|
del pin_groups[i]
|
||||||
|
|
||||||
|
|
@ -228,7 +232,7 @@ class router(router_tech):
|
||||||
Make multiple passes of the combine adjacent pins until we have no
|
Make multiple passes of the combine adjacent pins until we have no
|
||||||
more combinations or hit an iteration limit.
|
more combinations or hit an iteration limit.
|
||||||
"""
|
"""
|
||||||
|
debug.info(1,"Combining adjacent pins for {}.".format(pin_name))
|
||||||
# Start as None to signal the first iteration
|
# Start as None to signal the first iteration
|
||||||
num_removed_pairs = None
|
num_removed_pairs = None
|
||||||
|
|
||||||
|
|
@ -245,6 +249,7 @@ class router(router_tech):
|
||||||
This will try to separate all grid pins by the supplied number of separation
|
This will try to separate all grid pins by the supplied number of separation
|
||||||
tracks (default is to prevent adjacency).
|
tracks (default is to prevent adjacency).
|
||||||
"""
|
"""
|
||||||
|
debug.info(1,"Separating adjacent pins.")
|
||||||
# Commented out to debug with SCMOS
|
# Commented out to debug with SCMOS
|
||||||
#if separation==0:
|
#if separation==0:
|
||||||
# return
|
# return
|
||||||
|
|
@ -270,7 +275,7 @@ class router(router_tech):
|
||||||
grids_g1, grids_g2 = pg1.adjacent_grids(pg2, separation)
|
grids_g1, grids_g2 = pg1.adjacent_grids(pg2, separation)
|
||||||
# These should have the same length, so...
|
# These should have the same length, so...
|
||||||
if len(grids_g1)>0:
|
if len(grids_g1)>0:
|
||||||
debug.info(1,"Adjacent grids {0} {1} {2} {3}".format(index1,grids_g1,index2,grids_g2))
|
debug.info(3,"Adjacent grids {0} {1} {2} {3}".format(index1,grids_g1,index2,grids_g2))
|
||||||
self.remove_adjacent_grid(pg1, grids_g1, pg2, grids_g2)
|
self.remove_adjacent_grid(pg1, grids_g1, pg2, grids_g2)
|
||||||
|
|
||||||
def remove_adjacent_grid(self, pg1, grids1, pg2, grids2):
|
def remove_adjacent_grid(self, pg1, grids1, pg2, grids2):
|
||||||
|
|
@ -292,12 +297,12 @@ class router(router_tech):
|
||||||
# First, see if we can remove grids that are in the secondary grids
|
# First, see if we can remove grids that are in the secondary grids
|
||||||
# i.e. they aren't necessary to the pin grids
|
# i.e. they aren't necessary to the pin grids
|
||||||
if bigger_grids.issubset(bigger.secondary_grids):
|
if bigger_grids.issubset(bigger.secondary_grids):
|
||||||
debug.info(1,"Removing {} from bigger {}".format(str(bigger_grids), bigger))
|
debug.info(3,"Removing {} from bigger {}".format(str(bigger_grids), bigger))
|
||||||
bigger.grids.difference_update(bigger_grids)
|
bigger.grids.difference_update(bigger_grids)
|
||||||
self.blocked_grids.update(bigger_grids)
|
self.blocked_grids.update(bigger_grids)
|
||||||
return
|
return
|
||||||
elif smaller_grids.issubset(smaller.secondary_grids):
|
elif smaller_grids.issubset(smaller.secondary_grids):
|
||||||
debug.info(1,"Removing {} from smaller {}".format(str(smaller_grids), smaller))
|
debug.info(3,"Removing {} from smaller {}".format(str(smaller_grids), smaller))
|
||||||
smaller.grids.difference_update(smaller_grids)
|
smaller.grids.difference_update(smaller_grids)
|
||||||
self.blocked_grids.update(smaller_grids)
|
self.blocked_grids.update(smaller_grids)
|
||||||
return
|
return
|
||||||
|
|
@ -426,7 +431,7 @@ class router(router_tech):
|
||||||
|
|
||||||
def convert_blockages(self):
|
def convert_blockages(self):
|
||||||
""" Convert blockages to grid tracks. """
|
""" Convert blockages to grid tracks. """
|
||||||
|
debug.info(1,"Converting blockages.")
|
||||||
for blockage in self.blockages:
|
for blockage in self.blockages:
|
||||||
debug.info(3,"Converting blockage {}".format(str(blockage)))
|
debug.info(3,"Converting blockage {}".format(str(blockage)))
|
||||||
blockage_list = self.convert_blockage(blockage)
|
blockage_list = self.convert_blockage(blockage)
|
||||||
|
|
@ -438,7 +443,7 @@ class router(router_tech):
|
||||||
Recursive find boundaries as blockages to the routing grid.
|
Recursive find boundaries as blockages to the routing grid.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
shapes = self.layout.getAllShapesInStructureList(layer_num)
|
shapes = self.layout.getAllShapes(layer_num)
|
||||||
for boundary in shapes:
|
for boundary in shapes:
|
||||||
ll = vector(boundary[0],boundary[1])
|
ll = vector(boundary[0],boundary[1])
|
||||||
ur = vector(boundary[2],boundary[3])
|
ur = vector(boundary[2],boundary[3])
|
||||||
|
|
@ -621,6 +626,8 @@ class router(router_tech):
|
||||||
"""
|
"""
|
||||||
Analyze the shapes of a pin and combine them into groups which are connected.
|
Analyze the shapes of a pin and combine them into groups which are connected.
|
||||||
"""
|
"""
|
||||||
|
debug.info(2,"Analyzing pin groups for {}.".format(pin_name))
|
||||||
|
|
||||||
pin_set = self.pins[pin_name]
|
pin_set = self.pins[pin_name]
|
||||||
local_debug = False
|
local_debug = False
|
||||||
|
|
||||||
|
|
@ -684,6 +691,7 @@ class router(router_tech):
|
||||||
"""
|
"""
|
||||||
Convert the pin groups into pin tracks and blockage tracks.
|
Convert the pin groups into pin tracks and blockage tracks.
|
||||||
"""
|
"""
|
||||||
|
debug.info(1,"Converting pins for {}.".format(pin_name))
|
||||||
for pg in self.pin_groups[pin_name]:
|
for pg in self.pin_groups[pin_name]:
|
||||||
pg.convert_pin()
|
pg.convert_pin()
|
||||||
|
|
||||||
|
|
@ -733,7 +741,7 @@ class router(router_tech):
|
||||||
debug.check(index<self.num_pin_components(pin_name),"Pin component index too large.")
|
debug.check(index<self.num_pin_components(pin_name),"Pin component index too large.")
|
||||||
|
|
||||||
pin_in_tracks = self.pin_groups[pin_name][index].grids
|
pin_in_tracks = self.pin_groups[pin_name][index].grids
|
||||||
debug.info(1,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
|
debug.info(2,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||||
self.rg.add_source(pin_in_tracks)
|
self.rg.add_source(pin_in_tracks)
|
||||||
|
|
||||||
def add_path_target(self, paths):
|
def add_path_target(self, paths):
|
||||||
|
|
@ -752,7 +760,7 @@ class router(router_tech):
|
||||||
debug.check(index<self.num_pin_grids(pin_name),"Pin component index too large.")
|
debug.check(index<self.num_pin_grids(pin_name),"Pin component index too large.")
|
||||||
|
|
||||||
pin_in_tracks = self.pin_groups[pin_name][index].grids
|
pin_in_tracks = self.pin_groups[pin_name][index].grids
|
||||||
debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
|
debug.info(2,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
|
||||||
self.rg.add_target(pin_in_tracks)
|
self.rg.add_target(pin_in_tracks)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -760,7 +768,7 @@ class router(router_tech):
|
||||||
"""
|
"""
|
||||||
Block all of the pin components.
|
Block all of the pin components.
|
||||||
"""
|
"""
|
||||||
debug.info(2,"Setting blockages {0} {1}".format(pin_name,value))
|
debug.info(3,"Setting blockages {0} {1}".format(pin_name,value))
|
||||||
for pg in self.pin_groups[pin_name]:
|
for pg in self.pin_groups[pin_name]:
|
||||||
self.set_blockages(pg.grids, value)
|
self.set_blockages(pg.grids, value)
|
||||||
|
|
||||||
|
|
@ -796,7 +804,7 @@ class router(router_tech):
|
||||||
"""
|
"""
|
||||||
path=self.prepare_path(path)
|
path=self.prepare_path(path)
|
||||||
|
|
||||||
debug.info(1,"Adding route: {}".format(str(path)))
|
debug.info(2,"Adding route: {}".format(str(path)))
|
||||||
# If it is only a square, add an enclosure to the track
|
# If it is only a square, add an enclosure to the track
|
||||||
if len(path)==1:
|
if len(path)==1:
|
||||||
self.add_single_enclosure(path[0][0])
|
self.add_single_enclosure(path[0][0])
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from tech import drc,layer
|
from tech import drc,layer
|
||||||
from contact import contact
|
from contact import contact
|
||||||
from pin_group import pin_group
|
from pin_group import pin_group
|
||||||
|
from vector import vector
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
class router_tech:
|
class router_tech:
|
||||||
|
|
@ -35,9 +36,9 @@ class router_tech:
|
||||||
self.track_width = max(self.horiz_track_width,self.vert_track_width)
|
self.track_width = max(self.horiz_track_width,self.vert_track_width)
|
||||||
debug.info(1,"Track width: "+str(self.track_width))
|
debug.info(1,"Track width: "+str(self.track_width))
|
||||||
|
|
||||||
self.track_widths = [self.track_width] * 2
|
self.track_widths = vector([self.track_width] * 2)
|
||||||
self.track_factor = [1/self.track_width] * 2
|
self.track_factor = vector([1/self.track_width] * 2)
|
||||||
debug.info(1,"Track factor: {0}".format(self.track_factor))
|
debug.info(2,"Track factor: {0}".format(self.track_factor))
|
||||||
|
|
||||||
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
|
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
|
||||||
self.layer_widths = [self.track_width - self.horiz_layer_spacing, 1, self.track_width - self.vert_layer_spacing]
|
self.layer_widths = [self.track_width - self.horiz_layer_spacing, 1, self.track_width - self.vert_layer_spacing]
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,6 @@ class supply_router(router):
|
||||||
"""
|
"""
|
||||||
router.__init__(self, layers, design, gds_filename)
|
router.__init__(self, layers, design, gds_filename)
|
||||||
|
|
||||||
# We over-ride the regular router costs to allow
|
|
||||||
# more off-direction router in the supply grid
|
|
||||||
grid.VIA_COST = 1
|
|
||||||
grid.NONPREFERRED_COST = 1
|
|
||||||
grid.PREFERRED_COST = 1
|
|
||||||
|
|
||||||
# The list of supply rails (grid sets) that may be routed
|
# The list of supply rails (grid sets) that may be routed
|
||||||
self.supply_rails = {}
|
self.supply_rails = {}
|
||||||
self.supply_rail_wires = {}
|
self.supply_rail_wires = {}
|
||||||
|
|
@ -224,7 +218,7 @@ class supply_router(router):
|
||||||
ur = grid_utils.get_upper_right(rail)
|
ur = grid_utils.get_upper_right(rail)
|
||||||
z = ll.z
|
z = ll.z
|
||||||
pin = self.compute_wide_enclosure(ll, ur, z, name)
|
pin = self.compute_wide_enclosure(ll, ur, z, name)
|
||||||
debug.info(1,"Adding supply rail {0} {1}->{2} {3}".format(name,ll,ur,pin))
|
debug.info(2,"Adding supply rail {0} {1}->{2} {3}".format(name,ll,ur,pin))
|
||||||
self.cell.add_layout_pin(text=name,
|
self.cell.add_layout_pin(text=name,
|
||||||
layer=pin.layer,
|
layer=pin.layer,
|
||||||
offset=pin.ll(),
|
offset=pin.ll(),
|
||||||
|
|
@ -393,6 +387,7 @@ class supply_router(router):
|
||||||
Route the horizontal and vertical supply rails across the entire design.
|
Route the horizontal and vertical supply rails across the entire design.
|
||||||
Must be done with lower left at 0,0
|
Must be done with lower left at 0,0
|
||||||
"""
|
"""
|
||||||
|
debug.info(1,"Routing supply rail {0}.".format(name))
|
||||||
|
|
||||||
# Compute the grid locations of the supply rails
|
# Compute the grid locations of the supply rails
|
||||||
self.compute_supply_rails(name, supply_number)
|
self.compute_supply_rails(name, supply_number)
|
||||||
|
|
@ -426,14 +421,14 @@ class supply_router(router):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
remaining_components = sum(not x.is_routed() for x in self.pin_groups[pin_name])
|
remaining_components = sum(not x.is_routed() for x in self.pin_groups[pin_name])
|
||||||
debug.info(1,"Pin {0} has {1} remaining components to route.".format(pin_name,
|
debug.info(1,"Routing {0} with {1} pin components to route.".format(pin_name,
|
||||||
remaining_components))
|
remaining_components))
|
||||||
|
|
||||||
for index,pg in enumerate(self.pin_groups[pin_name]):
|
for index,pg in enumerate(self.pin_groups[pin_name]):
|
||||||
if pg.is_routed():
|
if pg.is_routed():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
debug.info(2,"Routing component {0} {1}".format(pin_name, index))
|
debug.info(3,"Routing component {0} {1}".format(pin_name, index))
|
||||||
|
|
||||||
# Clear everything in the routing grid.
|
# Clear everything in the routing grid.
|
||||||
self.rg.reinit()
|
self.rg.reinit()
|
||||||
|
|
@ -459,7 +454,7 @@ class supply_router(router):
|
||||||
"""
|
"""
|
||||||
Add the supply rails of given name as a routing target.
|
Add the supply rails of given name as a routing target.
|
||||||
"""
|
"""
|
||||||
debug.info(2,"Add supply rail target {}".format(pin_name))
|
debug.info(4,"Add supply rail target {}".format(pin_name))
|
||||||
# Add the wire itself as the target
|
# Add the wire itself as the target
|
||||||
self.rg.set_target(self.supply_rail_wire_tracks[pin_name])
|
self.rg.set_target(self.supply_rail_wire_tracks[pin_name])
|
||||||
# But unblock all the rail tracks including the space
|
# But unblock all the rail tracks including the space
|
||||||
|
|
@ -470,7 +465,7 @@ class supply_router(router):
|
||||||
"""
|
"""
|
||||||
Add the supply rails of given name as a routing target.
|
Add the supply rails of given name as a routing target.
|
||||||
"""
|
"""
|
||||||
debug.info(3,"Blocking supply rail")
|
debug.info(4,"Blocking supply rail")
|
||||||
for rail_name in self.supply_rail_tracks:
|
for rail_name in self.supply_rail_tracks:
|
||||||
self.rg.set_blocked(self.supply_rail_tracks[rail_name])
|
self.rg.set_blocked(self.supply_rail_tracks[rail_name])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -223,13 +223,13 @@ class sram_base(design):
|
||||||
from control_logic import control_logic
|
from control_logic import control_logic
|
||||||
# Create the control logic module for each port type
|
# Create the control logic module for each port type
|
||||||
if OPTS.num_rw_ports>0:
|
if OPTS.num_rw_ports>0:
|
||||||
self.control_logic = self.control_logic_rw = control_logic(num_rows=self.num_rows, port_type="rw")
|
self.control_logic = self.control_logic_rw = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, port_type="rw")
|
||||||
self.add_mod(self.control_logic_rw)
|
self.add_mod(self.control_logic_rw)
|
||||||
if OPTS.num_w_ports>0:
|
if OPTS.num_w_ports>0:
|
||||||
self.control_logic_w = control_logic(num_rows=self.num_rows, port_type="w")
|
self.control_logic_w = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, port_type="w")
|
||||||
self.add_mod(self.control_logic_w)
|
self.add_mod(self.control_logic_w)
|
||||||
if OPTS.num_r_ports>0:
|
if OPTS.num_r_ports>0:
|
||||||
self.control_logic_r = control_logic(num_rows=self.num_rows, port_type="r")
|
self.control_logic_r = control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, port_type="r")
|
||||||
self.add_mod(self.control_logic_r)
|
self.add_mod(self.control_logic_r)
|
||||||
|
|
||||||
# Create the address and control flops (but not the clk)
|
# Create the address and control flops (but not the clk)
|
||||||
|
|
|
||||||
|
|
@ -16,22 +16,25 @@ class library_lvs_test(openram_test):
|
||||||
import verify
|
import verify
|
||||||
|
|
||||||
(gds_dir, sp_dir, allnames) = setup_files()
|
(gds_dir, sp_dir, allnames) = setup_files()
|
||||||
|
drc_errors = 0
|
||||||
lvs_errors = 0
|
lvs_errors = 0
|
||||||
debug.info(1, "Performing LVS on: " + ", ".join(allnames))
|
debug.info(1, "Performing LVS on: " + ", ".join(allnames))
|
||||||
|
|
||||||
for f in allnames:
|
for f in allnames:
|
||||||
gds_name = "{0}/{1}.gds".format(gds_dir, f)
|
gds_name = "{0}/{1}.gds".format(gds_dir, f)
|
||||||
sp_name = "{0}/{1}.sp".format(sp_dir, f)
|
sp_name = "{0}/{1}.sp".format(sp_dir, f)
|
||||||
|
name = re.sub('\.gds$', '', f)
|
||||||
if not os.path.isfile(gds_name):
|
if not os.path.isfile(gds_name):
|
||||||
lvs_errors += 1
|
lvs_errors += 1
|
||||||
debug.error("Missing GDS file {}".format(gds_name))
|
debug.error("Missing GDS file {}".format(gds_name))
|
||||||
if not os.path.isfile(sp_name):
|
if not os.path.isfile(sp_name):
|
||||||
lvs_errors += 1
|
lvs_errors += 1
|
||||||
debug.error("Missing SPICE file {}".format(gds_name))
|
debug.error("Missing SPICE file {}".format(gds_name))
|
||||||
|
drc_errors += verify.run_drc(name, gds_name)
|
||||||
lvs_errors += verify.run_lvs(f, gds_name, sp_name)
|
lvs_errors += verify.run_lvs(f, gds_name, sp_name)
|
||||||
|
|
||||||
# fail if the error count is not zero
|
# fail if the error count is not zero
|
||||||
self.assertEqual(lvs_errors, 0)
|
self.assertEqual(drc_errors+lvs_errors, 0)
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
||||||
def setup_files():
|
def setup_files():
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,26 @@ class replica_bitline_test(openram_test):
|
||||||
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
||||||
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
#debug.error("Exiting...", 1)
|
||||||
|
|
||||||
|
stages=8
|
||||||
|
rows=100
|
||||||
|
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
||||||
|
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
#check replica bitline in handmade multi-port 1rw+1r cell
|
||||||
|
OPTS.bitcell = "bitcell_1rw_1r"
|
||||||
|
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
stages=4
|
||||||
|
fanout=4
|
||||||
|
rows=13
|
||||||
|
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
||||||
|
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
stages=8
|
stages=8
|
||||||
rows=100
|
rows=100
|
||||||
|
|
@ -31,7 +51,7 @@ class replica_bitline_test(openram_test):
|
||||||
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# check replica bitline in multi-port
|
# check replica bitline in pbitcell multi-port
|
||||||
OPTS.bitcell = "pbitcell"
|
OPTS.bitcell = "pbitcell"
|
||||||
OPTS.replica_bitcell = "replica_pbitcell"
|
OPTS.replica_bitcell = "replica_pbitcell"
|
||||||
OPTS.num_rw_ports = 1
|
OPTS.num_rw_ports = 1
|
||||||
|
|
@ -61,7 +81,7 @@ class replica_bitline_test(openram_test):
|
||||||
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
||||||
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
a = replica_bitline.replica_bitline(stages,fanout,rows)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
stages=8
|
stages=8
|
||||||
rows=100
|
rows=100
|
||||||
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows))
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ class control_logic_test(openram_test):
|
||||||
|
|
||||||
# check control logic for single port
|
# check control logic for single port
|
||||||
debug.info(1, "Testing sample for control_logic")
|
debug.info(1, "Testing sample for control_logic")
|
||||||
a = control_logic.control_logic(num_rows=128)
|
a = control_logic.control_logic(num_rows=128, words_per_row=1)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# check control logic for multi-port
|
# check control logic for multi-port
|
||||||
|
|
@ -31,7 +31,7 @@ class control_logic_test(openram_test):
|
||||||
OPTS.num_r_ports = 0
|
OPTS.num_r_ports = 0
|
||||||
|
|
||||||
debug.info(1, "Testing sample for control_logic for multiport")
|
debug.info(1, "Testing sample for control_logic for multiport")
|
||||||
a = control_logic.control_logic(num_rows=128)
|
a = control_logic.control_logic(num_rows=128, words_per_row=1)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
# Check port specific control logic
|
# Check port specific control logic
|
||||||
|
|
@ -40,15 +40,15 @@ class control_logic_test(openram_test):
|
||||||
OPTS.num_r_ports = 1
|
OPTS.num_r_ports = 1
|
||||||
|
|
||||||
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
||||||
a = control_logic.control_logic(num_rows=128, port_type="rw")
|
a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="rw")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
debug.info(1, "Testing sample for control_logic for multiport, only write control logic")
|
||||||
a = control_logic.control_logic(num_rows=128, port_type="w")
|
a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="w")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing sample for control_logic for multiport, only read control logic")
|
debug.info(1, "Testing sample for control_logic for multiport, only read control logic")
|
||||||
a = control_logic.control_logic(num_rows=128, port_type="r")
|
a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="r")
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
globals.end_openram()
|
globals.end_openram()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Run a regression test on a 1 bank SRAM
|
||||||
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from testutils import header,openram_test
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
import debug
|
||||||
|
|
||||||
|
#@unittest.skip("SKIPPING 20_psram_1bank_test, multiport layout not complete")
|
||||||
|
class psram_1bank_2mux_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
|
from sram import sram
|
||||||
|
from sram_config import sram_config
|
||||||
|
OPTS.bitcell = "pbitcell"
|
||||||
|
OPTS.replica_bitcell="replica_pbitcell"
|
||||||
|
|
||||||
|
# testing layout of sram using pbitcell with 1 RW port (a 6T-cell equivalent)
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
OPTS.num_r_ports = 0
|
||||||
|
|
||||||
|
c = sram_config(word_size=4,
|
||||||
|
num_words=32,
|
||||||
|
num_banks=1)
|
||||||
|
c.num_words=32
|
||||||
|
c.words_per_row=2
|
||||||
|
debug.info(1, "Single bank two way column mux with control logic")
|
||||||
|
a = sram(c, "sram")
|
||||||
|
self.local_check(a, final_verification=True)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# run the test from the command line
|
||||||
|
if __name__ == "__main__":
|
||||||
|
(OPTS, args) = globals.parse_args()
|
||||||
|
del sys.argv[1:]
|
||||||
|
header(__file__, OPTS.tech_name)
|
||||||
|
unittest.main()
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
Run a regression test on a 1 bank SRAM
|
|
||||||
"""
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
from testutils import header,openram_test
|
|
||||||
import sys,os
|
|
||||||
sys.path.append(os.path.join(sys.path[0],".."))
|
|
||||||
import globals
|
|
||||||
from globals import OPTS
|
|
||||||
import debug
|
|
||||||
|
|
||||||
@unittest.skip("SKIPPING 20_psram_1bank_test, multiport layout not complete")
|
|
||||||
class sram_1bank_test(openram_test):
|
|
||||||
|
|
||||||
def runTest(self):
|
|
||||||
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
|
||||||
from sram import sram
|
|
||||||
from sram_config import sram_config
|
|
||||||
OPTS.bitcell = "pbitcell"
|
|
||||||
OPTS.replica_bitcell="replica_pbitcell"
|
|
||||||
|
|
||||||
# testing layout of sram using pbitcell with 1 RW port (a 6T-cell equivalent)
|
|
||||||
OPTS.num_rw_ports = 1
|
|
||||||
OPTS.num_w_ports = 0
|
|
||||||
OPTS.num_r_ports = 0
|
|
||||||
|
|
||||||
c = sram_config(word_size=4,
|
|
||||||
num_words=16,
|
|
||||||
num_banks=1)
|
|
||||||
c.words_per_row=1
|
|
||||||
|
|
||||||
debug.info(1, "Single bank, no column mux with control logic")
|
|
||||||
a = sram(c, "sram1")
|
|
||||||
self.local_check(a, final_verification=True)
|
|
||||||
|
|
||||||
c.num_words=32
|
|
||||||
c.words_per_row=2
|
|
||||||
debug.info(1, "Single bank two way column mux with control logic")
|
|
||||||
a = sram(c, "sram2")
|
|
||||||
self.local_check(a, final_verification=True)
|
|
||||||
"""
|
|
||||||
c.num_words=64
|
|
||||||
c.words_per_row=4
|
|
||||||
debug.info(1, "Single bank, four way column mux with control logic")
|
|
||||||
a = sram(c, "sram3")
|
|
||||||
self.local_check(a, final_verification=True)
|
|
||||||
|
|
||||||
c.word_size=2
|
|
||||||
c.num_words=128
|
|
||||||
c.words_per_row=8
|
|
||||||
debug.info(1, "Single bank, eight way column mux with control logic")
|
|
||||||
a = sram(c, "sram4")
|
|
||||||
self.local_check(a, final_verification=True)
|
|
||||||
|
|
||||||
# testing sram using pbitcell in various port combinations
|
|
||||||
# layout for multiple ports does not work yet
|
|
||||||
"""
|
|
||||||
OPTS.netlist_only = True
|
|
||||||
|
|
||||||
c.num_words=16
|
|
||||||
c.words_per_row=1
|
|
||||||
|
|
||||||
OPTS.num_rw_ports = 2
|
|
||||||
OPTS.num_w_ports = 2
|
|
||||||
OPTS.num_r_ports = 2
|
|
||||||
|
|
||||||
debug.info(1, "Single bank, no column mux with control logic")
|
|
||||||
a = sram(c, "sram1")
|
|
||||||
self.local_check(a, final_verification=True)
|
|
||||||
"""
|
|
||||||
OPTS.num_rw_ports = 0
|
|
||||||
OPTS.num_w_ports = 2
|
|
||||||
OPTS.num_r_ports = 2
|
|
||||||
|
|
||||||
debug.info(1, "Single bank, no column mux with control logic")
|
|
||||||
a = sram(c, "sram1")
|
|
||||||
self.local_check(a, final_verification=True)
|
|
||||||
|
|
||||||
OPTS.num_rw_ports = 2
|
|
||||||
OPTS.num_w_ports = 0
|
|
||||||
OPTS.num_r_ports = 2
|
|
||||||
|
|
||||||
debug.info(1, "Single bank, no column mux with control logic")
|
|
||||||
a = sram(c, "sram1")
|
|
||||||
self.local_check(a, final_verification=True)
|
|
||||||
|
|
||||||
OPTS.num_rw_ports = 2
|
|
||||||
OPTS.num_w_ports = 2
|
|
||||||
OPTS.num_r_ports = 0
|
|
||||||
|
|
||||||
debug.info(1, "Single bank, no column mux with control logic")
|
|
||||||
a = sram(c, "sram1")
|
|
||||||
self.local_check(a, final_verification=True)
|
|
||||||
|
|
||||||
OPTS.num_rw_ports = 2
|
|
||||||
OPTS.num_w_ports = 0
|
|
||||||
OPTS.num_r_ports = 0
|
|
||||||
|
|
||||||
debug.info(1, "Single bank, no column mux with control logic")
|
|
||||||
a = sram(c, "sram1")
|
|
||||||
self.local_check(a, final_verification=True)
|
|
||||||
|
|
||||||
# testing with various column muxes
|
|
||||||
OPTS.num_rw_ports = c.num_rw_ports = 2
|
|
||||||
OPTS.num_w_ports = c.num_w_ports = 2
|
|
||||||
OPTS.num_r_ports = c.num_r_ports = 2
|
|
||||||
|
|
||||||
c.num_words=32
|
|
||||||
c.words_per_row=2
|
|
||||||
debug.info(1, "Single bank two way column mux with control logic")
|
|
||||||
a = sram(c, "sram2")
|
|
||||||
self.local_check(a, final_verification=True)
|
|
||||||
|
|
||||||
c.num_words=64
|
|
||||||
c.words_per_row=4
|
|
||||||
debug.info(1, "Single bank, four way column mux with control logic")
|
|
||||||
a = sram(c, "sram3")
|
|
||||||
self.local_check(a, final_verification=True)
|
|
||||||
|
|
||||||
c.word_size=2
|
|
||||||
c.num_words=128
|
|
||||||
c.words_per_row=8
|
|
||||||
debug.info(1, "Single bank, eight way column mux with control logic")
|
|
||||||
a = sram(c, "sram4")
|
|
||||||
self.local_check(a, final_verification=True)
|
|
||||||
"""
|
|
||||||
globals.end_openram()
|
|
||||||
|
|
||||||
# run the test from the command line
|
|
||||||
if __name__ == "__main__":
|
|
||||||
(OPTS, args) = globals.parse_args()
|
|
||||||
del sys.argv[1:]
|
|
||||||
header(__file__, OPTS.tech_name)
|
|
||||||
unittest.main()
|
|
||||||
|
|
@ -20,6 +20,9 @@ class psram_1bank_2mux_func_test(openram_test):
|
||||||
OPTS.netlist_only = True
|
OPTS.netlist_only = True
|
||||||
OPTS.bitcell = "pbitcell"
|
OPTS.bitcell = "pbitcell"
|
||||||
OPTS.replica_bitcell="replica_pbitcell"
|
OPTS.replica_bitcell="replica_pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
OPTS.num_w_ports = 1
|
||||||
|
|
||||||
# This is a hack to reload the characterizer __init__ with the spice version
|
# This is a hack to reload the characterizer __init__ with the spice version
|
||||||
from importlib import reload
|
from importlib import reload
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,9 @@ class psram_1bank_4mux_func_test(openram_test):
|
||||||
OPTS.netlist_only = True
|
OPTS.netlist_only = True
|
||||||
OPTS.bitcell = "pbitcell"
|
OPTS.bitcell = "pbitcell"
|
||||||
OPTS.replica_bitcell="replica_pbitcell"
|
OPTS.replica_bitcell="replica_pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
OPTS.num_w_ports = 1
|
||||||
|
|
||||||
# This is a hack to reload the characterizer __init__ with the spice version
|
# This is a hack to reload the characterizer __init__ with the spice version
|
||||||
from importlib import reload
|
from importlib import reload
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import globals
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
@unittest.skip("SKIPPING 22_psram_1bank_8mux_func_test")
|
#@unittest.skip("SKIPPING 22_psram_1bank_8mux_func_test")
|
||||||
class psram_1bank_8mux_func_test(openram_test):
|
class psram_1bank_8mux_func_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
|
|
@ -20,6 +20,9 @@ class psram_1bank_8mux_func_test(openram_test):
|
||||||
OPTS.netlist_only = True
|
OPTS.netlist_only = True
|
||||||
OPTS.bitcell = "pbitcell"
|
OPTS.bitcell = "pbitcell"
|
||||||
OPTS.replica_bitcell="replica_pbitcell"
|
OPTS.replica_bitcell="replica_pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
OPTS.num_w_ports = 1
|
||||||
|
|
||||||
# This is a hack to reload the characterizer __init__ with the spice version
|
# This is a hack to reload the characterizer __init__ with the spice version
|
||||||
from importlib import reload
|
from importlib import reload
|
||||||
|
|
@ -29,7 +32,7 @@ class psram_1bank_8mux_func_test(openram_test):
|
||||||
from sram import sram
|
from sram import sram
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
c = sram_config(word_size=4,
|
c = sram_config(word_size=4,
|
||||||
num_words=512,
|
num_words=256,
|
||||||
num_banks=1)
|
num_banks=1)
|
||||||
c.words_per_row=8
|
c.words_per_row=8
|
||||||
debug.info(1, "Functional test for psram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
|
debug.info(1, "Functional test for psram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,9 @@ class psram_1bank_nomux_func_test(openram_test):
|
||||||
OPTS.netlist_only = True
|
OPTS.netlist_only = True
|
||||||
OPTS.bitcell = "pbitcell"
|
OPTS.bitcell = "pbitcell"
|
||||||
OPTS.replica_bitcell="replica_pbitcell"
|
OPTS.replica_bitcell="replica_pbitcell"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
OPTS.num_w_ports = 1
|
||||||
|
|
||||||
# This is a hack to reload the characterizer __init__ with the spice version
|
# This is a hack to reload the characterizer __init__ with the spice version
|
||||||
from importlib import reload
|
from importlib import reload
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ class sram_1bank_8mux_func_test(openram_test):
|
||||||
from sram import sram
|
from sram import sram
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
c = sram_config(word_size=4,
|
c = sram_config(word_size=4,
|
||||||
num_words=512,
|
num_words=256,
|
||||||
num_banks=1)
|
num_banks=1)
|
||||||
c.words_per_row=8
|
c.words_per_row=8
|
||||||
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
|
debug.info(1, "Functional test for sram with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
|
||||||
|
|
@ -38,6 +38,7 @@ class sram_1bank_8mux_func_test(openram_test):
|
||||||
c.words_per_row,
|
c.words_per_row,
|
||||||
c.num_banks))
|
c.num_banks))
|
||||||
s = sram(c, name="sram")
|
s = sram(c, name="sram")
|
||||||
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
tempspice = OPTS.openram_temp + "temp.sp"
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
s.sp_write(tempspice)
|
s.sp_write(tempspice)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Run a functioal test on 1 bank SRAM
|
||||||
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from testutils import header,openram_test
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.path.join(sys.path[0],".."))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
import debug
|
||||||
|
|
||||||
|
#@unittest.skip("SKIPPING 22_sram_1rw_1r_1bank_nomux_func_test")
|
||||||
|
class psram_1bank_nomux_func_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
|
||||||
|
OPTS.analytical_delay = False
|
||||||
|
OPTS.netlist_only = True
|
||||||
|
OPTS.bitcell = "bitcell_1rw_1r"
|
||||||
|
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
|
||||||
|
OPTS.num_rw_ports = 1
|
||||||
|
OPTS.num_w_ports = 0
|
||||||
|
OPTS.num_r_ports = 1
|
||||||
|
|
||||||
|
# This is a hack to reload the characterizer __init__ with the spice version
|
||||||
|
from importlib import reload
|
||||||
|
import characterizer
|
||||||
|
reload(characterizer)
|
||||||
|
from characterizer import functional
|
||||||
|
from sram import sram
|
||||||
|
from sram_config import sram_config
|
||||||
|
c = sram_config(word_size=4,
|
||||||
|
num_words=32,
|
||||||
|
num_banks=1)
|
||||||
|
c.words_per_row=1
|
||||||
|
debug.info(1, "Functional test for sram 1rw,1r with {} bit words, {} words, {} words per row, {} banks".format(c.word_size,
|
||||||
|
c.num_words,
|
||||||
|
c.words_per_row,
|
||||||
|
c.num_banks))
|
||||||
|
s = sram(c, name="sram")
|
||||||
|
tempspice = OPTS.openram_temp + "temp.sp"
|
||||||
|
s.sp_write(tempspice)
|
||||||
|
|
||||||
|
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||||
|
|
||||||
|
f = functional(s.s, tempspice, corner)
|
||||||
|
f.num_cycles = 10
|
||||||
|
(fail, error) = f.run()
|
||||||
|
self.assertTrue(fail,error)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|
@ -100,7 +100,7 @@ def write_netgen_script(cell_name, sp_name):
|
||||||
os.system("chmod u+x {}".format(run_file))
|
os.system("chmod u+x {}".format(run_file))
|
||||||
|
|
||||||
|
|
||||||
def run_drc(cell_name, gds_name, extract=False, final_verification=False):
|
def run_drc(cell_name, gds_name, extract=True, final_verification=False):
|
||||||
"""Run DRC check on a cell which is implemented in gds_name."""
|
"""Run DRC check on a cell which is implemented in gds_name."""
|
||||||
|
|
||||||
global num_drc_runs
|
global num_drc_runs
|
||||||
|
|
@ -166,7 +166,6 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
|
||||||
global num_lvs_runs
|
global num_lvs_runs
|
||||||
num_lvs_runs += 1
|
num_lvs_runs += 1
|
||||||
|
|
||||||
run_drc(cell_name, gds_name, extract=True, final_verification=final_verification)
|
|
||||||
write_netgen_script(cell_name, sp_name)
|
write_netgen_script(cell_name, sp_name)
|
||||||
|
|
||||||
# run LVS
|
# run LVS
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,10 +1,15 @@
|
||||||
|
|
||||||
.SUBCKT cell_6t bl br wl vdd gnd
|
.SUBCKT cell_6t bl br wl vdd gnd
|
||||||
|
* Inverter 1
|
||||||
|
MM0 Qbar Q gnd gnd NMOS_VTG W=205.00n L=50n
|
||||||
|
MM4 Qbar Q vdd vdd PMOS_VTG W=90n L=50n
|
||||||
|
|
||||||
|
* Inverer 2
|
||||||
|
MM1 Q Qbar gnd gnd NMOS_VTG W=205.00n L=50n
|
||||||
|
MM5 Q Qbar vdd vdd PMOS_VTG W=90n L=50n
|
||||||
|
|
||||||
|
* Access transistors
|
||||||
MM3 bl wl Q gnd NMOS_VTG W=135.00n L=50n
|
MM3 bl wl Q gnd NMOS_VTG W=135.00n L=50n
|
||||||
MM2 br wl Qb gnd NMOS_VTG W=135.00n L=50n
|
MM2 br wl Qbar gnd NMOS_VTG W=135.00n L=50n
|
||||||
MM1 Q Qb gnd gnd NMOS_VTG W=205.00n L=50n
|
|
||||||
MM0 Qb Q gnd gnd NMOS_VTG W=205.00n L=50n
|
|
||||||
MM5 Q Qb vdd vdd PMOS_VTG W=90n L=50n
|
|
||||||
MM4 Qb Q vdd vdd PMOS_VTG W=90n L=50n
|
|
||||||
.ENDS cell_6t
|
.ENDS cell_6t
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
.SUBCKT replica_cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
|
||||||
|
MM9 RA_to_R_right wl1 br1 gnd NMOS_VTG W=180.0n L=50n m=1
|
||||||
|
MM8 RA_to_R_right Q gnd gnd NMOS_VTG W=180.0n L=50n m=1
|
||||||
|
MM7 RA_to_R_left vdd gnd gnd NMOS_VTG W=180.0n L=50n m=1
|
||||||
|
MM6 RA_to_R_left wl1 bl1 gnd NMOS_VTG W=180.0n L=50n m=1
|
||||||
|
MM5 Q wl0 bl0 gnd NMOS_VTG W=135.00n L=50n m=1
|
||||||
|
MM4 vdd wl0 br0 gnd NMOS_VTG W=135.00n L=50n m=1
|
||||||
|
MM1 Q vdd gnd gnd NMOS_VTG W=270.0n L=50n m=1
|
||||||
|
MM0 vdd Q gnd gnd NMOS_VTG W=270.0n L=50n m=1
|
||||||
|
MM3 Q vdd vdd vdd PMOS_VTG W=90n L=50n m=1
|
||||||
|
MM2 vdd Q vdd vdd PMOS_VTG W=90n L=50n m=1
|
||||||
|
.ENDS
|
||||||
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
|
|
||||||
.SUBCKT replica_cell_6t bl br wl vdd gnd
|
.SUBCKT replica_cell_6t bl br wl vdd gnd
|
||||||
MM3 bl wl gnd gnd NMOS_VTG W=135.00n L=50n
|
* Inverter 1
|
||||||
MM2 br wl net4 gnd NMOS_VTG W=135.00n L=50n
|
MM0 vdd Q gnd gnd NMOS_VTG W=205.00n L=50n
|
||||||
MM1 gnd net4 gnd gnd NMOS_VTG W=205.00n L=50n
|
MM4 vdd Q vdd vdd PMOS_VTG W=90n L=50n
|
||||||
MM0 net4 gnd gnd gnd NMOS_VTG W=205.00n L=50n
|
|
||||||
MM5 gnd net4 vdd vdd PMOS_VTG W=90n L=50n
|
* Inverer 2
|
||||||
MM4 net4 gnd vdd vdd PMOS_VTG W=90n L=50n
|
MM1 Q vdd gnd gnd NMOS_VTG W=205.00n L=50n
|
||||||
.ENDS replica_cell_6t
|
MM5 Q vdd vdd vdd PMOS_VTG W=90n L=50n
|
||||||
|
|
||||||
|
* Access transistors
|
||||||
|
MM3 bl wl Q gnd NMOS_VTG W=135.00n L=50n
|
||||||
|
MM2 br wl vdd gnd NMOS_VTG W=135.00n L=50n
|
||||||
|
.ENDS cell_6t
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,6 +1,6 @@
|
||||||
magic
|
magic
|
||||||
tech scmos
|
tech scmos
|
||||||
timestamp 1540504134
|
timestamp 1541193956
|
||||||
<< nwell >>
|
<< nwell >>
|
||||||
rect 0 50 54 79
|
rect 0 50 54 79
|
||||||
<< pwell >>
|
<< pwell >>
|
||||||
|
|
@ -139,10 +139,10 @@ rect 0 0 54 74
|
||||||
<< labels >>
|
<< labels >>
|
||||||
rlabel metal1 27 4 27 4 1 wl1
|
rlabel metal1 27 4 27 4 1 wl1
|
||||||
rlabel psubstratepcontact 27 11 27 11 1 gnd
|
rlabel psubstratepcontact 27 11 27 11 1 gnd
|
||||||
rlabel m2contact 27 74 27 74 5 vdd
|
|
||||||
rlabel metal1 19 67 19 67 1 wl0
|
rlabel metal1 19 67 19 67 1 wl0
|
||||||
rlabel metal2 4 7 4 7 2 bl0
|
rlabel metal2 4 7 4 7 2 bl0
|
||||||
rlabel metal2 11 7 11 7 1 bl1
|
rlabel metal2 11 7 11 7 1 bl1
|
||||||
rlabel metal2 43 7 43 7 1 br1
|
rlabel metal2 43 7 43 7 1 br1
|
||||||
rlabel metal2 50 7 50 7 8 br0
|
rlabel metal2 50 7 50 7 8 br0
|
||||||
|
rlabel metal1 19 74 19 74 5 vdd
|
||||||
<< end >>
|
<< end >>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
magic
|
||||||
|
tech scmos
|
||||||
|
timestamp 1541194096
|
||||||
|
<< nwell >>
|
||||||
|
rect 0 50 54 79
|
||||||
|
<< pwell >>
|
||||||
|
rect 0 0 54 50
|
||||||
|
<< ntransistor >>
|
||||||
|
rect 14 35 16 41
|
||||||
|
rect 22 29 24 41
|
||||||
|
rect 30 29 32 41
|
||||||
|
rect 38 35 40 41
|
||||||
|
rect 14 17 16 25
|
||||||
|
rect 22 17 24 25
|
||||||
|
rect 30 17 32 25
|
||||||
|
rect 38 17 40 25
|
||||||
|
<< ptransistor >>
|
||||||
|
rect 22 58 24 62
|
||||||
|
rect 30 58 32 62
|
||||||
|
<< ndiffusion >>
|
||||||
|
rect 9 39 14 41
|
||||||
|
rect 13 35 14 39
|
||||||
|
rect 16 35 17 41
|
||||||
|
rect 21 33 22 41
|
||||||
|
rect 17 29 22 33
|
||||||
|
rect 24 29 25 41
|
||||||
|
rect 29 29 30 41
|
||||||
|
rect 32 33 33 41
|
||||||
|
rect 37 35 38 41
|
||||||
|
rect 40 39 45 41
|
||||||
|
rect 40 35 41 39
|
||||||
|
rect 32 29 37 33
|
||||||
|
rect 9 23 14 25
|
||||||
|
rect 13 19 14 23
|
||||||
|
rect 9 17 14 19
|
||||||
|
rect 16 17 22 25
|
||||||
|
rect 24 17 25 25
|
||||||
|
rect 29 17 30 25
|
||||||
|
rect 32 17 38 25
|
||||||
|
rect 40 23 45 25
|
||||||
|
rect 40 19 41 23
|
||||||
|
rect 40 17 45 19
|
||||||
|
<< pdiffusion >>
|
||||||
|
rect 21 58 22 62
|
||||||
|
rect 24 58 25 62
|
||||||
|
rect 29 58 30 62
|
||||||
|
rect 32 58 33 62
|
||||||
|
<< ndcontact >>
|
||||||
|
rect 9 35 13 39
|
||||||
|
rect 17 33 21 41
|
||||||
|
rect 25 29 29 41
|
||||||
|
rect 33 33 37 41
|
||||||
|
rect 41 35 45 39
|
||||||
|
rect 9 19 13 23
|
||||||
|
rect 25 17 29 25
|
||||||
|
rect 41 19 45 23
|
||||||
|
<< pdcontact >>
|
||||||
|
rect 17 58 21 62
|
||||||
|
rect 25 58 29 62
|
||||||
|
rect 33 58 37 62
|
||||||
|
<< psubstratepcontact >>
|
||||||
|
rect 25 9 29 13
|
||||||
|
<< nsubstratencontact >>
|
||||||
|
rect 25 72 29 76
|
||||||
|
<< polysilicon >>
|
||||||
|
rect 22 62 24 64
|
||||||
|
rect 30 62 32 64
|
||||||
|
rect 22 48 24 58
|
||||||
|
rect 30 55 32 58
|
||||||
|
rect 31 51 32 55
|
||||||
|
rect 14 41 16 46
|
||||||
|
rect 22 44 23 48
|
||||||
|
rect 22 41 24 44
|
||||||
|
rect 30 41 32 51
|
||||||
|
rect 38 41 40 46
|
||||||
|
rect 14 33 16 35
|
||||||
|
rect 38 33 40 35
|
||||||
|
rect 14 25 16 26
|
||||||
|
rect 22 25 24 29
|
||||||
|
rect 30 25 32 29
|
||||||
|
rect 38 25 40 26
|
||||||
|
rect 14 15 16 17
|
||||||
|
rect 22 15 24 17
|
||||||
|
rect 30 15 32 17
|
||||||
|
rect 38 15 40 17
|
||||||
|
<< polycontact >>
|
||||||
|
rect 27 51 31 55
|
||||||
|
rect 10 42 14 46
|
||||||
|
rect 23 44 27 48
|
||||||
|
rect 40 42 44 46
|
||||||
|
rect 12 26 16 30
|
||||||
|
rect 38 26 42 30
|
||||||
|
<< metal1 >>
|
||||||
|
rect 0 72 25 76
|
||||||
|
rect 29 72 54 76
|
||||||
|
rect 0 65 54 69
|
||||||
|
rect 10 46 14 65
|
||||||
|
rect 29 58 33 62
|
||||||
|
rect 17 55 20 58
|
||||||
|
rect 17 51 27 55
|
||||||
|
rect 17 41 20 51
|
||||||
|
rect 34 48 37 58
|
||||||
|
rect 27 44 37 48
|
||||||
|
rect 34 41 37 44
|
||||||
|
rect 40 46 44 65
|
||||||
|
rect 6 35 9 39
|
||||||
|
rect 45 35 48 39
|
||||||
|
rect 25 25 29 29
|
||||||
|
rect 25 13 29 17
|
||||||
|
rect 0 9 25 13
|
||||||
|
rect 29 9 54 13
|
||||||
|
rect 0 2 16 6
|
||||||
|
rect 20 2 34 6
|
||||||
|
rect 38 2 54 6
|
||||||
|
<< m2contact >>
|
||||||
|
rect 25 72 29 76
|
||||||
|
rect 25 58 29 62
|
||||||
|
rect 2 35 6 39
|
||||||
|
rect 16 26 20 30
|
||||||
|
rect 48 35 52 39
|
||||||
|
rect 34 26 38 30
|
||||||
|
rect 9 19 13 23
|
||||||
|
rect 41 19 45 23
|
||||||
|
rect 16 2 20 6
|
||||||
|
rect 34 2 38 6
|
||||||
|
<< metal2 >>
|
||||||
|
rect 2 39 6 76
|
||||||
|
rect 2 0 6 35
|
||||||
|
rect 9 23 13 76
|
||||||
|
rect 25 62 29 72
|
||||||
|
rect 9 0 13 19
|
||||||
|
rect 16 6 20 26
|
||||||
|
rect 34 6 38 26
|
||||||
|
rect 41 23 45 76
|
||||||
|
rect 41 0 45 19
|
||||||
|
rect 48 39 52 76
|
||||||
|
rect 48 0 52 35
|
||||||
|
<< bb >>
|
||||||
|
rect 0 0 54 74
|
||||||
|
<< labels >>
|
||||||
|
rlabel metal1 27 4 27 4 1 wl1
|
||||||
|
rlabel psubstratepcontact 27 11 27 11 1 gnd
|
||||||
|
rlabel metal1 19 67 19 67 1 wl0
|
||||||
|
rlabel metal2 4 7 4 7 2 bl0
|
||||||
|
rlabel metal2 11 7 11 7 1 bl1
|
||||||
|
rlabel metal2 43 7 43 7 1 br1
|
||||||
|
rlabel metal2 50 7 50 7 8 br0
|
||||||
|
rlabel metal1 19 74 19 74 5 vdd
|
||||||
|
<< end >>
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
magic
|
magic
|
||||||
tech scmos
|
tech scmos
|
||||||
timestamp 1536091380
|
timestamp 1541443051
|
||||||
<< nwell >>
|
<< nwell >>
|
||||||
rect -8 29 42 51
|
rect -8 29 42 51
|
||||||
<< pwell >>
|
<< pwell >>
|
||||||
|
|
@ -76,15 +76,15 @@ rect 17 6 21 10
|
||||||
rect -2 44 15 48
|
rect -2 44 15 48
|
||||||
rect 19 44 32 48
|
rect 19 44 32 48
|
||||||
rect -2 40 2 44
|
rect -2 40 2 44
|
||||||
|
rect 22 40 26 44
|
||||||
rect 32 40 36 44
|
rect 32 40 36 44
|
||||||
rect 11 36 12 40
|
rect 11 36 12 40
|
||||||
rect 26 36 27 40
|
rect 26 36 27 40
|
||||||
rect -2 26 2 29
|
rect -2 26 2 29
|
||||||
rect 11 22 15 36
|
rect -2 16 2 22
|
||||||
|
rect 11 18 15 36
|
||||||
rect 23 24 27 36
|
rect 23 24 27 36
|
||||||
rect -2 18 15 22
|
|
||||||
rect 25 20 27 24
|
rect 25 20 27 24
|
||||||
rect -2 16 2 18
|
|
||||||
rect 14 14 15 18
|
rect 14 14 15 18
|
||||||
rect 23 18 27 20
|
rect 23 18 27 20
|
||||||
rect 32 26 36 29
|
rect 32 26 36 29
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,16 @@
|
||||||
.SUBCKT cell_6t bl br wl vdd gnd
|
.SUBCKT cell_6t bl br wl vdd gnd
|
||||||
* SPICE3 file created from cell_6t.ext - technology: scmos
|
* SPICE3 file created from cell_6t.ext - technology: scmos
|
||||||
|
|
||||||
M1000 a_36_40# a_28_32# vdd vdd p w=0.6u l=0.8u
|
* Inverter 1
|
||||||
M1001 vdd a_36_40# a_28_32# vdd p w=0.6u l=0.8u
|
M1000 Q Qbar vdd vdd p w=0.6u l=0.8u
|
||||||
M1002 a_36_40# a_28_32# gnd gnd n w=1.6u l=0.4u
|
M1002 Q Qbar gnd gnd n w=1.6u l=0.4u
|
||||||
M1003 gnd a_36_40# a_28_32# gnd n w=1.6u l=0.4u
|
|
||||||
M1004 a_36_40# wl bl gnd n w=0.8u l=0.4u
|
* Inverter 2
|
||||||
M1005 a_28_32# wl br gnd n w=0.8u l=0.4u
|
M1001 vdd Q Qbar vdd p w=0.6u l=0.8u
|
||||||
|
M1003 gnd Q Qbar gnd n w=1.6u l=0.4u
|
||||||
|
|
||||||
|
* Access transistors
|
||||||
|
M1004 Q wl bl gnd n w=0.8u l=0.4u
|
||||||
|
M1005 Qbar wl br gnd n w=0.8u l=0.4u
|
||||||
|
|
||||||
.ENDS
|
.ENDS
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
.SUBCKT replica_cell_1rw_1r bl0 br0 bl1 br1 wl0 wl1 vdd gnd
|
||||||
|
MM9 RA_to_R_right wl1 br1 gnd n w=1.6u l=0.4u
|
||||||
|
MM8 RA_to_R_right Q gnd gnd n w=1.6u l=0.4u
|
||||||
|
MM7 RA_to_R_left vdd gnd gnd n w=1.6u l=0.4u
|
||||||
|
MM6 RA_to_R_left wl1 bl1 gnd n w=1.6u l=0.4u
|
||||||
|
MM5 Q wl0 bl0 gnd n w=1.2u l=0.4u
|
||||||
|
MM4 vdd wl0 br0 gnd n w=1.2u l=0.4u
|
||||||
|
MM1 Q vdd gnd gnd n w=2.4u l=0.4u
|
||||||
|
MM0 vdd Q gnd gnd n w=2.4u l=0.4u
|
||||||
|
MM3 Q vdd vdd vdd p w=0.8u l=0.4u
|
||||||
|
MM2 vdd Q vdd vdd p w=0.8u l=0.4u
|
||||||
|
.ENDS
|
||||||
|
|
||||||
|
|
@ -1,14 +1,18 @@
|
||||||
|
|
||||||
*********************** "cell_6t" ******************************
|
*********************** "cell_6t" ******************************
|
||||||
.SUBCKT replica_cell_6t bl br wl vdd gnd
|
.SUBCKT replica_cell_6t bl br wl vdd gnd
|
||||||
* SPICE3 file created from replica_cell_6t.ext - technology: scmos
|
* SPICE3 file created from cell_6t.ext - technology: scmos
|
||||||
|
|
||||||
M1000 gnd a_28_32# vdd vdd p w=0.6u l=0.8u
|
* Inverter 1
|
||||||
M1001 vdd gnd a_28_32# vdd p w=0.6u l=0.8u
|
M1000 Q vdd vdd vdd p w=0.6u l=0.8u
|
||||||
** SOURCE/DRAIN TIED
|
M1002 Q vdd gnd gnd n w=1.6u l=0.4u
|
||||||
M1002 gnd a_28_32# gnd gnd n w=1.6u l=0.4u
|
|
||||||
M1003 gnd gnd a_28_32# gnd n w=1.6u l=0.4u
|
* Inverter 2
|
||||||
M1004 gnd wl bl gnd n w=0.8u l=0.4u
|
M1001 vdd Q vdd vdd p w=0.6u l=0.8u
|
||||||
M1005 a_28_32# wl br gnd n w=0.8u l=0.4u
|
M1003 gnd Q vdd gnd n w=1.6u l=0.4u
|
||||||
|
|
||||||
|
* Access transistors
|
||||||
|
M1004 Q wl bl gnd n w=0.8u l=0.4u
|
||||||
|
M1005 vdd wl br gnd n w=0.8u l=0.4u
|
||||||
|
|
||||||
.ENDS
|
.ENDS
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
tech
|
tech
|
||||||
format 29
|
format 31
|
||||||
scmos
|
scmos
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -301,11 +301,6 @@ style lambda=0.20(p)
|
||||||
scalefactor 20 10
|
scalefactor 20 10
|
||||||
options calma-permissive-labels
|
options calma-permissive-labels
|
||||||
|
|
||||||
# This is a custom section to add bounding boxes in OpenRAM
|
|
||||||
layer BB bb
|
|
||||||
labels bb
|
|
||||||
calma 63 0
|
|
||||||
|
|
||||||
layer CWN nwell,rnw,nwr,nwsd,nwsc
|
layer CWN nwell,rnw,nwr,nwsd,nwsc
|
||||||
bloat-or pdiff,apres,rpd,pdc/a,pfet * 120
|
bloat-or pdiff,apres,rpd,pdc/a,pfet * 120
|
||||||
bloat-or nsd,nsc/a * 60
|
bloat-or nsd,nsc/a * 60
|
||||||
|
|
@ -1769,11 +1764,6 @@ cifinput
|
||||||
style lambda=0.20(p)
|
style lambda=0.20(p)
|
||||||
scalefactor 20
|
scalefactor 20
|
||||||
|
|
||||||
# This is a custom section to add bounding boxes in OpenRAM
|
|
||||||
layer bb BB
|
|
||||||
labels BB
|
|
||||||
calma 63 0
|
|
||||||
|
|
||||||
layer nwell CWN
|
layer nwell CWN
|
||||||
and-not CWNR
|
and-not CWNR
|
||||||
and-not CTA
|
and-not CTA
|
||||||
|
|
@ -6701,7 +6691,7 @@ drc
|
||||||
edge4way nfet,pfet,fet space/active,ndiff,anres,rnd,ndc/a,pdiff,apres,rpd,pdc/a 3 ndiff,anres,rnd,ndc/a,pdiff,apres,rpd,pdc/a,nfet,pfet,fet 0 0 \
|
edge4way nfet,pfet,fet space/active,ndiff,anres,rnd,ndc/a,pdiff,apres,rpd,pdc/a 3 ndiff,anres,rnd,ndc/a,pdiff,apres,rpd,pdc/a,nfet,pfet,fet 0 0 \
|
||||||
"N-Diffusion,P-Diffusion overhang of Transistor < 3 (Mosis #3.4)" active
|
"N-Diffusion,P-Diffusion overhang of Transistor < 3 (Mosis #3.4)" active
|
||||||
|
|
||||||
edge4way poly,fp,rp,pc/a ~(poly,fp,pres,rp,pc/a,nfet,pfet,fet,prp)/active 1 space space 1 \
|
edge4way poly,fp,rp,pc/a ~(poly,fp,pres,rp,pc/a,nfet,pfet,fet,prp)/active 1 space/a space/a 1 \
|
||||||
"Poly spacing to Diffusion < 1 (Mosis #3.5)"
|
"Poly spacing to Diffusion < 1 (Mosis #3.5)"
|
||||||
|
|
||||||
edge4way nfet ~(nfet)/active 2 ~(pselect)/select ~(nfet)/active 2 \
|
edge4way nfet ~(nfet)/active 2 ~(pselect)/select ~(nfet)/active 2 \
|
||||||
|
|
@ -7212,13 +7202,15 @@ extract
|
||||||
planeorder via3 14
|
planeorder via3 14
|
||||||
planeorder fill 15
|
planeorder fill 15
|
||||||
|
|
||||||
|
substrate *psd,space/w,pwell well
|
||||||
|
|
||||||
resist (ndiff,anres,rnd,ndc,nsd,nwsd,nsc,nwsc)/active 3700
|
resist (ndiff,anres,rnd,ndc,nsd,nwsd,nsc,nwsc)/active 3700
|
||||||
resist (pdiff,apres,rpd,pdc,psd,psc)/active 2800
|
resist (pdiff,apres,rpd,pdc,psd,psc)/active 2800
|
||||||
resist (nwell)/well 1018000
|
resist (nwell)/well 1018000
|
||||||
resist (rnw,nwr)/active 1018000
|
resist (rnw,nwr)/active 1018000 0.5
|
||||||
resist (pwell)/well 1
|
resist (pwell)/well 1
|
||||||
resist (poly,fp,rp,pc,pc,nfet,pfet,fet)/active 6000
|
resist (poly,fp,rp,pc,pc,nfet,pfet,fet)/active 6000
|
||||||
resist (pres)/active 6000
|
resist (pres)/active 6000 0.5
|
||||||
resist (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c,m2c)/metal1 80
|
resist (m1,fm1,rm1,ndc,nsc,nwsc,pdc,psc,pc,m2c,m2c)/metal1 80
|
||||||
resist (m2,fm2,rm2,m2c,m3c,m3c)/metal2 70
|
resist (m2,fm2,rm2,m2c,m3c,m3c)/metal2 70
|
||||||
resist (m3,fm3,rm3,m3c,m4c,m4c)/metal3 80
|
resist (m3,fm3,rm3,m3c,m4c,m4c)/metal3 80
|
||||||
|
|
@ -7416,33 +7408,30 @@ extract
|
||||||
|
|
||||||
#metali
|
#metali
|
||||||
|
|
||||||
#fets
|
#devices
|
||||||
|
|
||||||
fet pfet pdiff,pdc 2 pfet Vdd! nwell 52 181
|
device mosfet pfet pfet pdiff,pdc nwell ERROR 52 181
|
||||||
fet pfet pdiff,pdc 1 pfet Vdd! nwell 52 181
|
device mosfet nfet nfet ndiff,ndc pwell,space/w ERROR 55 182
|
||||||
|
|
||||||
fet nfet ndiff,ndc 2 nfet Gnd! pwell 55 182
|
|
||||||
fet nfet ndiff,ndc 1 nfet Gnd! pwell 55 182
|
|
||||||
|
|
||||||
fetresis pfet linear 12182
|
fetresis pfet linear 12182
|
||||||
fetresis pfet saturation 12182
|
fetresis pfet saturation 12182
|
||||||
fetresis nfet linear 3961
|
fetresis nfet linear 3961
|
||||||
fetresis nfet saturation 3961
|
fetresis nfet saturation 3961
|
||||||
|
|
||||||
fet rnwell nsd,nsc 2 nwellResistor Gnd! nwell,pwell 0 0
|
device resistor nwellResistor rnwell *nsd
|
||||||
fet rpoly poly,pc 2 polyResistor Gnd! nwell,pwell 0 0
|
device resistor polyResistor rpoly *poly
|
||||||
fet nwr nwsd 2 nwellFig1bResistor Gnd! nwell,pwell 0 0
|
device resistor nwellFig1bResistor nwr nwsd
|
||||||
fet rndiff ndiff,ndc 2 ndiffResistor Gnd! nwell,pwell 0 0
|
device resistor ndiffResistor rndiff *ndiff
|
||||||
fet rpdiff pdiff,pdc 2 pdiffResistor Gnd! nwell,pwell 0 0
|
device resistor pdiffResistor rpdiff *pdiff
|
||||||
|
|
||||||
fet rmetal1 metal1 2 metal1Resistor Gnd! nwell,pwell 0 0
|
device resistor metal1Resistor rmetal1 *metal1
|
||||||
fet rmetal2 metal2 2 metal2Resistor Gnd! nwell,pwell 0 0
|
device resistor metal2Resistor rmetal2 *metal2
|
||||||
fet rmetal3 metal3 2 metal3Resistor Gnd! nwell,pwell 0 0
|
device resistor metal3Resistor rmetal3 *metal3
|
||||||
fet rmetal4 metal4 2 metal4Resistor Gnd! nwell,pwell 0 0
|
device resistor metal4Resistor rmetal4 *metal4
|
||||||
|
|
||||||
fet pres poly,pc 2 presResistor Gnd! nwell,pwell 0 0
|
device resistor presResistor pres *poly
|
||||||
fet anres ndiff,ndc 2 anresResistor Gnd! nwell,pwell 0 0
|
device resistor anresResistor anres *ndiff
|
||||||
fet apres pdiff,pdc 2 apresResistor Gnd! nwell,pwell 0 0
|
device resistor apresResistor apres *pdiff
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -240,7 +240,7 @@ spice["fet_models"] = { "TT" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"
|
||||||
|
|
||||||
|
|
||||||
#spice stimulus related variables
|
#spice stimulus related variables
|
||||||
spice["feasible_period"] = 5 # estimated feasible period in ns
|
spice["feasible_period"] = 5 # estimated feasible period in ns
|
||||||
spice["supply_voltages"] = [4.5, 5.0, 5.5] # Supply voltage corners in [Volts]
|
spice["supply_voltages"] = [4.5, 5.0, 5.5] # Supply voltage corners in [Volts]
|
||||||
spice["nom_supply_voltage"] = 5.0 # Nominal supply voltage in [Volts]
|
spice["nom_supply_voltage"] = 5.0 # Nominal supply voltage in [Volts]
|
||||||
spice["rise_time"] = 0.05 # rise time in [Nano-seconds]
|
spice["rise_time"] = 0.05 # rise time in [Nano-seconds]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue