mirror of https://github.com/VLSIDA/OpenRAM.git
256 lines
11 KiB
Python
256 lines
11 KiB
Python
import gdsMill
|
|
import tech
|
|
import globals
|
|
import math
|
|
import debug
|
|
from collections import defaultdict
|
|
|
|
class lef:
|
|
"""
|
|
SRAM LEF Class open GDS file, read pins information, obstruction
|
|
and write them to LEF file
|
|
"""
|
|
def __init__(self, gdsName, lefName, sr):
|
|
self.gdsName = gdsName
|
|
self.lef = open(lefName,"w")
|
|
self.sr = sr
|
|
self.myLayout = gdsMill.VlsiLayout(units=tech.GDS["unit"])
|
|
self.reader = gdsMill.Gds2reader(self.myLayout)
|
|
self.reader.loadFromFile(gdsName)
|
|
self.unit = float(self.myLayout.info['units'][0])
|
|
self.layer = ["metal1", "via1", "metal2", "via2", "metal3"]
|
|
|
|
self.create()
|
|
|
|
self.lef.close()
|
|
|
|
def create(self):
|
|
"""Write to LEF file"""
|
|
power_pin_name = self.powerPinName()
|
|
ground_pin_name = self.groundPinName()
|
|
input_pin_name = self.inputPinName()
|
|
inout_pin_name = self.inoutPinName()
|
|
|
|
self.writeLefHeader()
|
|
|
|
for pin in power_pin_name:
|
|
self.writePin(pin, 1)
|
|
|
|
for pin in ground_pin_name:
|
|
self.writePin(pin, 2)
|
|
|
|
for pin in inout_pin_name:
|
|
self.writePin(pin, 3)
|
|
|
|
for pin in input_pin_name:
|
|
self.writePin(pin,4)
|
|
|
|
self.lef.write(" OBS \n")
|
|
for lay in self.layer:
|
|
self.lef.write(" Layer {0} ; \n".format(lay))
|
|
self.writeObstruct(self.sr.name, lay, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0))
|
|
self.lef.write(" END \n")
|
|
|
|
self.writeLefFooter()
|
|
|
|
def coordinatesTranslate(self, coord, mirr, angle, xyShift):
|
|
"""Calculate coordinates after flip, rotate, and shift"""
|
|
coordinate = []
|
|
for item in coord:
|
|
x = (item[0]*math.cos(angle)-item[1]*mirr*math.sin(angle)+xyShift[0])
|
|
y = (item[0]*math.sin(angle)+item[1]*mirr*math.cos(angle)+xyShift[1])
|
|
coordinate += [(x, y)]
|
|
return coordinate
|
|
|
|
def writeObstruct(self, sr, lay, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0)):
|
|
"""Recursive write boundaries on each Structure in GDS file to LEF"""
|
|
for boundary in self.myLayout.structures[sr].boundaries:
|
|
coordTrans = self.coordinatesTranslate(boundary.coordinates, mirr, angle, xyShift)
|
|
rect = self.minMaxCoord(coordTrans)
|
|
lay_convert = tech.layer[lay]
|
|
if boundary.drawingLayer == lay_convert:
|
|
self.lef.write(" RECT ")
|
|
for item in rect:
|
|
self.lef.write(" {0} {1}".format(item[0]*self.unit, item[1]*self.unit))
|
|
self.lef.write(" ;\n")
|
|
|
|
for sref in self.myLayout.structures[sr].srefs:
|
|
sMirr = 1
|
|
if sref.transFlags[0] == True:
|
|
sMirr = -1
|
|
sAngle = math.radians(float(0))
|
|
if sref.rotateAngle:
|
|
sAngle = math.radians(float(sref.rotateAngle))
|
|
sAngle += angle
|
|
x = sref.coordinates[0]
|
|
y = sref.coordinates[1]
|
|
newX = (x)*math.cos(angle) - mirr*(y)*math.sin(angle) + xyShift[0]
|
|
newY = (x)*math.sin(angle) + mirr*(y)*math.cos(angle) + xyShift[1]
|
|
sxyShift = (newX, newY)
|
|
self.writeObstruct(sref.sName, lay,sMirr, sAngle, sxyShift)
|
|
|
|
def writePinCoord(self, sr, pinName, pinLayer, pinCoord, mirr = 1,
|
|
angle = math.radians(float(0)), xyShift = (0, 0)):
|
|
"""Write PIN information to LEF"""
|
|
for boundary in self.myLayout.structures[sr].boundaries:
|
|
if (pinLayer == boundary.drawingLayer):
|
|
coordTrans = self.coordinatesTranslate(boundary.coordinates, mirr, angle, xyShift)
|
|
rect = self.minMaxCoord(coordTrans)
|
|
if self.pointInsideRect(pinCoord, rect):
|
|
self.lef.write(" RECT ")
|
|
for item in rect:
|
|
self.lef.write(" {0} {1}".format(item[0]*self.unit, item[1]*self.unit))
|
|
self.lef.write(" ;\n")
|
|
|
|
for sref in self.myLayout.structures[sr].srefs:
|
|
sMirr = 1
|
|
if sref.transFlags[0] == True:
|
|
sMirr = -1
|
|
sAngle = math.radians(float(0))
|
|
if sref.rotateAngle:
|
|
sAngle = math.radians(float(sref.rotateAngle))
|
|
sAngle += angle
|
|
x = sref.coordinates[0]
|
|
y = sref.coordinates[1]
|
|
newX = (x*math.cos(angle) - mirr*y*math.sin(angle)) + xyShift[0]
|
|
newY = (x*math.sin(angle) + mirr*y*math.cos(angle)) + xyShift[1]
|
|
sxyShift = (newX, newY)
|
|
self.writePinCoord(sref.sName, pinName, pinLayer, pinCoord, sMirr, sAngle, sxyShift)
|
|
|
|
def pinLayerCoord(self, sr, pinName):
|
|
"""Get Pin Layer and Coordinates {layer:[coord1, coord2, ...]}"""
|
|
layCoord = defaultdict(list)
|
|
for text in self.myLayout.structures[self.sr.name].texts:
|
|
if text.textString.strip('\x00') == pinName:
|
|
k = text.drawingLayer
|
|
v = text.coordinates
|
|
d = {k: v}
|
|
layCoord.setdefault(k, []).append(v)
|
|
return layCoord
|
|
|
|
def minMaxCoord(self, coordTrans):
|
|
"""Find the lowest and highest conner of a Rectangle"""
|
|
coordinate = []
|
|
minx = min(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0])
|
|
maxx = max(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0])
|
|
miny = min(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1])
|
|
maxy = max(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1])
|
|
coordinate += [(minx, miny)]
|
|
coordinate += [(maxx, maxy)]
|
|
return coordinate
|
|
|
|
def pointInsideRect(self, p, rect):
|
|
"""Check if a point is inside a rectangle"""
|
|
inside = False
|
|
if ((p[0][0] >= rect[0][0])& (p[0][0] <= rect[1][0])
|
|
& (p[0][1] >= rect[0][1]) &(p[0][1] <= rect[1][1])):
|
|
inside = not inside
|
|
return inside
|
|
|
|
def writeLefHeader(self):
|
|
"""Heafer of LEF file"""
|
|
coord = self.lowestLeftCorner(self.sr.name, 1, 0.0, (0, 0), [], [], [], [])
|
|
self.lef.write("MACRO {0}\n".format(self.sr.name))
|
|
self.lef.write(" CLASS RING ;\n")
|
|
self.lef.write(" ORIGIN {0} {1} ;\n".format(-coord[0][0]*self.unit, coord[0][1]*self.unit))
|
|
self.lef.write(" FOREIGN sram {0} {1} ;\n"
|
|
.format(0.0, 0.0))
|
|
self.lef.write(" SIZE {0} BY {1} ;\n"
|
|
.format(self.sr.width, self.sr.height))
|
|
self.lef.write(" SYMMETRY X Y R90 ;\n")
|
|
|
|
def writeLefFooter(self):
|
|
self.lef.write("END {0} \n".format(self.sr.name))
|
|
self.lef.write("END LIBRARY \n")
|
|
|
|
def powerPinName(self):
|
|
return ["vdd"]
|
|
|
|
def groundPinName(self):
|
|
return ["gnd"]
|
|
|
|
def inputPinName(self):
|
|
input_pin_name = []
|
|
for i in range(self.sr.addr_size + int(math.log(self.sr.num_banks, 2))):
|
|
input_pin_name.append("ADDR[{0}]".format(i))
|
|
input_pin_name.append("CSb")
|
|
input_pin_name.append("OEb")
|
|
input_pin_name.append("WEb")
|
|
input_pin_name.append("clk")
|
|
return input_pin_name
|
|
|
|
def inoutPinName(self):
|
|
inout_pin_name = []
|
|
for i in range(self.sr.word_size):
|
|
inout_pin_name.append("DATA[{0}]".format(i))
|
|
|
|
return inout_pin_name
|
|
|
|
def writePin(self, pinName, typ):
|
|
self.lef.write(" PIN {0} \n".format(pinName))
|
|
if typ == 1:
|
|
self.lef.write(" DIRECTION INOUT ; \n")
|
|
self.lef.write(" USE POWER ; \n")
|
|
self.lef.write(" SHAPE ABUTMENT ; \n")
|
|
self.lef.write(" PORT \n")
|
|
elif typ == 2:
|
|
self.lef.write(" DIRECTION INOUT ; \n")
|
|
self.lef.write(" USE GROUND ; \n")
|
|
self.lef.write(" SHAPE ABUTMENT ; \n")
|
|
self.lef.write(" PORT \n")
|
|
elif typ == 3:
|
|
self.lef.write(" DIRECTION INOUT ; \n")
|
|
self.lef.write(" PORT \n")
|
|
elif typ == 4:
|
|
self.lef.write(" DIRECTION INPUT ; \n")
|
|
self.lef.write(" PORT \n")
|
|
else:
|
|
debug.error("Invalid pin type on pin {0}".format(pinName))
|
|
|
|
pin_layer_coord = self.pinLayerCoord(self.sr.name, pinName)
|
|
for pinLayer in pin_layer_coord:
|
|
lay = [key for key, value in tech.layer.iteritems() if value == pinLayer][0]
|
|
self.lef.write(" Layer {0} ; \n".format(lay))
|
|
for pinCoord in pin_layer_coord[pinLayer]:
|
|
self.writePinCoord(self.sr.name, pinName, pinLayer, pinCoord,
|
|
mirr = 1,angle = math.radians(float(0)), xyShift = (0, 0))
|
|
self.lef.write(" END \n")
|
|
self.lef.write(" END {0} \n".format(pinName))
|
|
|
|
def lowestLeftCorner(self, sr, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0), listMinX = [], listMinY = [], listMaxX = [], listMaxY =[]):
|
|
"""Recursive find a lowest left conner on each Structure in GDS file"""
|
|
for boundary in self.myLayout.structures[sr].boundaries:
|
|
coordTrans = self.coordinatesTranslate(boundary.coordinates, mirr, angle, xyShift)
|
|
minX = min(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0])
|
|
minY = min(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1])
|
|
maxX = max(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0])
|
|
maxY = max(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1])
|
|
listMinX.append(minX)
|
|
listMinY.append(minY)
|
|
listMaxX.append(maxX)
|
|
listMaxY.append(maxY)
|
|
|
|
for sref in self.myLayout.structures[sr].srefs:
|
|
sMirr = 1
|
|
if sref.transFlags[0] == True:
|
|
sMirr = -1
|
|
sAngle = math.radians(float(0))
|
|
if sref.rotateAngle:
|
|
sAngle = math.radians(float(sref.rotateAngle))
|
|
sAngle += angle
|
|
x = sref.coordinates[0]
|
|
y = sref.coordinates[1]
|
|
newX = (x*math.cos(angle) - mirr*y*math.sin(angle)) + xyShift[0]
|
|
newY = (x*math.sin(angle) + mirr*y*math.cos(angle)) + xyShift[1]
|
|
sxyShift = (newX, newY)
|
|
self.lowestLeftCorner(sref.sName, sMirr, sAngle, sxyShift, listMinX, listMinY, listMaxX, listMaxY)
|
|
coordinate = []
|
|
lowestX = min(listMinX)
|
|
lowestY = min(float(item) for item in listMinY)
|
|
highestX = max(float(item) for item in listMaxX)
|
|
highestY = max(float(item) for item in listMaxY)
|
|
coordinate.append((lowestX, lowestY))
|
|
coordinate.append((highestX, highestY))
|
|
return coordinate
|
|
|