-
Notifications
You must be signed in to change notification settings - Fork 218
/
Copy pathlef.py
222 lines (195 loc) · 9.33 KB
/
lef.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2024 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import os
import shutil
from openram import debug
from openram.base import vector
from openram.base import pin_layout
from openram.tech import layer_names
from openram import OPTS
class lef:
"""
SRAM LEF Class open GDS file, read pins information, obstruction
and write them to LEF file.
This is inherited by the sram_1bank class.
"""
def __init__(self, layers):
# LEF db units per micron
self.lef_units = 2000
# These are the layers of the obstructions
self.lef_layers = layers
# Round to ensure float values are divisible by 0.0025 (the manufacturing grid)
self.round_grid = 4
def magic_lef_write(self, lef_name):
""" Use a magic script to perform LEF creation. """
debug.info(3, "Writing abstracted LEF to {0}".format(lef_name))
# Copy .magicrc file into the output directory
magic_file = OPTS.openram_tech + "tech/.magicrc"
if os.path.exists(magic_file):
shutil.copy(magic_file, OPTS.openram_temp)
else:
debug.warning("Could not locate .magicrc file: {}".format(magic_file))
gds_name = OPTS.openram_temp + "{}.gds".format(self.name)
self.gds_write(gds_name)
run_file = OPTS.openram_temp + "run_lef.sh"
f = open(run_file, "w")
f.write("#!/bin/sh\n")
f.write('export OPENRAM_TECH="{}"\n'.format(os.environ['OPENRAM_TECH']))
f.write('echo "$(date): Starting GDS to MAG using Magic {}"\n'.format(OPTS.drc_exe[1]))
f.write('\n')
f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1]))
f.write("drc off\n")
f.write("gds polygon subcell true\n")
f.write("gds warning default\n")
f.write("gds flatten true\n")
f.write("gds ordering true\n")
f.write("gds readonly true\n")
f.write("gds read {}\n".format(gds_name))
f.write('puts "Finished reading gds {}"\n'.format(gds_name))
f.write("load {}\n".format(self.name))
f.write('puts "Finished loading cell {}"\n'.format(self.name))
f.write("cellname delete \\(UNNAMED\\)\n")
f.write("lef write {} -hide\n".format(lef_name))
f.write('puts "Finished writing LEF cell {}"\n'.format(self.name))
f.close()
os.system("chmod u+x {}".format(run_file))
from openram.verify.run_script import run_script
(outfile, errfile, resultsfile) = run_script(self.name, "lef")
def lef_write(self, lef_name):
""" Write the entire lef of the object to the file. """
# Can possibly use magic lef write to create the LEF
# if OPTS.drc_exe and OPTS.drc_exe[0] == "magic":
# self.magic_lef_write(lef_name)
# return
# To maintain the indent level easily
self.indent = ""
if OPTS.detailed_lef:
debug.info(3, "Writing detailed LEF to {0}".format(lef_name))
else:
debug.info(3, "Writing abstract LEF to {0}".format(lef_name))
self.compute_abstract_blockages()
self.lef = open(lef_name, "w")
self.lef_write_header()
for pin_name in self.pins:
self.lef_write_pin(pin_name)
self.lef_write_obstructions(OPTS.detailed_lef)
self.lef_write_footer()
self.lef.close()
def compute_abstract_blockages(self):
# Start with blockages on all layers the size of the block
# minus the pin escape margin (hard coded to 4 x m3 pitch)
# These are a pin_layout to use their geometric functions
perimeter_margin = self.m3_pitch
self.blockages = {}
for layer_name in self.lef_layers:
self.blockages[layer_name]=[]
for layer_name in self.lef_layers:
ll = vector(perimeter_margin, perimeter_margin)
ur = vector(self.width - perimeter_margin, self.height - perimeter_margin)
self.blockages[layer_name].append(pin_layout("",
[ll, ur],
layer_name))
# For each pin, remove the blockage and add the pin
for pin_name in self.pins:
pins = self.get_pins(pin_name)
for pin in pins:
inflated_pin = pin.inflated_pin(multiple=2)
continue_fragmenting = True
while continue_fragmenting:
continue_fragmenting = False
old_blockages = list(self.blockages[pin.layer])
for blockage in old_blockages:
if blockage.overlaps(inflated_pin):
intersection_pin = blockage.intersection(inflated_pin)
# If it is zero area, don't split the blockage
if not intersection_pin or intersection_pin.area() == 0:
continue
# Remove the old blockage and add the new ones
self.blockages[pin.layer].remove(blockage)
new_blockages = blockage.cut(intersection_pin)
self.blockages[pin.layer].extend(new_blockages)
# We split something so make another pass
continue_fragmenting = True
def lef_write_header(self):
""" Header of LEF file """
self.lef.write("VERSION 5.4 ;\n")
self.lef.write("NAMESCASESENSITIVE ON ;\n")
self.lef.write("BUSBITCHARS \"[]\" ;\n")
self.lef.write("DIVIDERCHAR \"/\" ;\n")
self.lef.write("UNITS\n")
self.lef.write(" DATABASE MICRONS {0} ;\n".format(self.lef_units))
self.lef.write("END UNITS\n")
self.lef.write("{0}MACRO {1}\n".format(self.indent, self.name))
self.indent += " "
self.lef.write("{0}CLASS BLOCK ;\n".format(self.indent))
self.lef.write("{0}SIZE {1} BY {2} ;\n" .format(self.indent,
round(self.width, self.round_grid),
round(self.height, self.round_grid)))
self.lef.write("{0}SYMMETRY X Y R90 ;\n".format(self.indent))
def lef_write_footer(self):
self.indent = self.indent[:-3]
self.lef.write("{0}END {1}\n".format(self.indent, self.name))
self.lef.write("END LIBRARY\n")
def lef_write_pin(self, name):
pin_dir = self.get_pin_dir(name)
pin_type = self.get_pin_type(name)
self.lef.write("{0}PIN {1}\n".format(self.indent, name))
self.indent += " "
self.lef.write("{0}DIRECTION {1} ;\n".format(self.indent, pin_dir))
if pin_type in ["POWER", "GROUND"]:
self.lef.write("{0}USE {1} ; \n".format(self.indent, pin_type))
self.lef.write("{0}SHAPE ABUTMENT ; \n".format(self.indent))
self.lef.write("{0}PORT\n".format(self.indent))
self.indent += " "
# We could sort these together to minimize different layer sections, but meh.
pin_list = self.get_pins(name)
for pin in pin_list:
self.lef.write("{0}LAYER {1} ;\n".format(self.indent, layer_names[pin.layer]))
self.lef_write_shape(pin.rect)
# End the PORT
self.indent = self.indent[:-3]
self.lef.write("{0}END\n".format(self.indent))
# End the PIN
self.indent = self.indent[:-3]
self.lef.write("{0}END {1}\n".format(self.indent, name))
def lef_write_obstructions(self, detailed=False):
""" Write all the obstructions on each layer """
self.lef.write("{0}OBS\n".format(self.indent))
for layer in self.lef_layers:
self.lef.write("{0}LAYER {1} ;\n".format(self.indent, layer_names[layer]))
self.indent += " "
if detailed:
blockages = self.get_blockages(layer, True)
for b in blockages:
self.lef_write_shape(b)
else:
blockages = self.blockages[layer]
for b in blockages:
self.lef_write_shape(b.rect)
self.indent = self.indent[:-3]
self.lef.write("{0}END\n".format(self.indent))
def lef_write_shape(self, obj):
if len(obj) == 2:
""" Write a LEF rectangle """
self.lef.write("{0}RECT ".format(self.indent))
for item in obj:
# print(obj)
self.lef.write(" {0} {1}".format(round(item[0],
self.round_grid),
round(item[1],
self.round_grid)))
self.lef.write(" ;\n")
else:
""" Write a LEF polygon """
self.lef.write("{0}POLYGON ".format(self.indent))
for item in obj:
self.lef.write(" {0} {1}".format(round(item[0],
self.round_grid),
round(item[1],
self.round_grid)))
self.lef.write(" ;\n")