-
Notifications
You must be signed in to change notification settings - Fork 2
/
def_parser.py
207 lines (192 loc) · 7.57 KB
/
def_parser.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
"""
DEF Parser
Author: Tri Minh Cao
Email: tricao@utdallas.edu
Date: August 2016
"""
import logging
from def_util import *
from util import *
class DefParser:
"""
DefParser will parse a DEF file and store related information of the design.
"""
def __init__(self, def_file):
self.file_path = def_file
# can make the stack to be an object if needed
self.stack = []
# store the statements info in a list
self.sections = []
self.property = None
self.components = None
self.pins = None
self.nets = None
self.tracks = []
self.gcellgrids = []
self.rows = []
self.diearea = None
self.version = None
self.dividerchar = None
self.busbitchars = None
self.design_name = None
self.units = None
self.scale = None
def parse(self):
"""
Main method to parse the DEF file
:return: void
"""
logging.debug ("Start parsing DEF file...")
# open the file and start reading
f = open(self.file_path, "r+")
# the program will run until the end of file f
for line in f:
# split the string by the plus '+' sign
parts = split_plus(line)
for each_part in parts:
# split each sub-string by space
info = split_space(each_part)
if len(info) > 0:
#print info
if info[0] == "PINS":
new_pins = Pins(int(info[1]))
self.stack.append(new_pins)
# print (new_pins.type)
elif info[0] == "VERSION":
self.version = info[1]
elif info[0] == "DIVIDERCHAR":
self.dividerchar = info[1]
elif info[0] == "BUSBITCHARS":
self.busbitchars = info[1]
elif info[0] == "DESIGN" and len(info) <= 3:
# differentiate with the DESIGN statement inside
# PROPERTYDEFINITIONS section.
self.design_name = info[1]
elif info[0] == "UNITS":
self.units = info[2]
self.scale = info[3]
elif info[0] == "PROPERTYDEFINITIONS":
new_property = Property()
self.stack.append(new_property)
elif info[0] == "DIEAREA":
info_split = split_parentheses(info)
pt1 = (int(info_split[1][0]), int(info_split[1][1]))
pt2 = (int(info_split[2][0]), int(info_split[2][1]))
self.diearea = [pt1, pt2]
elif info[0] == "COMPONENTS":
new_comps = Components(int(info[1]))
self.stack.append(new_comps)
elif info[0] == "NETS":
new_nets = Nets(int(info[1]))
self.stack.append(new_nets)
elif info[0] == "TRACKS":
new_tracks = Tracks(info[1])
new_tracks.pos = int(info[2])
new_tracks.do = int(info[4])
new_tracks.step = int(info[6])
new_tracks.layer = info[8]
self.tracks.append(new_tracks)
elif info[0] == "GCELLGRID":
new_gcellgrid = GCellGrid(info[1])
new_gcellgrid.pos = int(info[2])
new_gcellgrid.do = int(info[4])
new_gcellgrid.step = int(info[6])
self.gcellgrids.append(new_gcellgrid)
elif info[0] == "ROW":
new_row = Row(info[1])
new_row.site = info[2]
new_row.pos = (int(info[3]), int(info[4]))
new_row.orient = info[5]
new_row.do = int(info[7])
new_row.by = int(info[9])
new_row.step = (int(info[11]), int(info[12]))
self.rows.append(new_row)
elif info[0] == "END":
if len(self.stack) > 0:
self.sections.append(self.stack.pop())
# print ("finish")
else:
if len(self.stack) > 0:
latest_obj = self.stack[-1]
latest_obj.parse_next(info)
f.close()
# put the elements in sections list into separate variables
for sec in self.sections:
if sec.type == "PROPERTY_DEF":
self.property = sec
elif sec.type == "COMPONENTS_DEF":
self.components = sec
elif sec.type == "PINS_DEF":
self.pins = sec
elif sec.type == "NETS_DEF":
self.nets = sec
logging.debug ("Parsing DEF file done")
def to_def_format(self):
s = ""
s += "# Generated by tricao@utdallas.edu for testing only.\n\n"
s += "VERSION " + self.version + " ;" + "\n"
s += "DIVIDERCHAR " + self.dividerchar + " ;" + "\n"
s += "BUSBITCHARS " + self.busbitchars + " ;" + "\n"
s += "DESIGN " + self.design_name + " ;" + "\n"
s += "UNITS DISTANCE " + self.units + " " + self.scale + " ;" + "\n"
s += "\n"
props = self.sections[0]
s += props.to_def_format()
s += "\n"
s += "DIEAREA"
s += (" ( " + str(self.diearea[0][0]) + " " + str(self.diearea[0][1]) +
" )")
s += (" ( " + str(self.diearea[1][0]) + " " + str(self.diearea[1][1]) +
" )" + " ;")
s += "\n\n"
for each_row in self.rows:
s += each_row.to_def_format()
s += "\n"
s += "\n"
for each_tracks in self.tracks:
s += each_tracks.to_def_format()
s += "\n"
s += "\n"
for each_gcell in self.gcellgrids:
s += each_gcell.to_def_format()
s += "\n"
s += "\n"
comps = def_parser.sections[1]
s += comps.to_def_format()
s += "\n\n"
pins = def_parser.sections[2]
s += pins.to_def_format()
s += "\n\n"
nets = def_parser.sections[3]
s += nets.to_def_format()
return s
def write_def(self, new_def, back_end=True, front_end=True):
"""
Write a new def file based on the information in the DefParser object.
Note: this method writes all information
:param new_def: path of the new DEF file
:param back_end: write BEOL information or not.
:param front_end: write FEOL info or not.
:return: void
"""
f = open(new_def, mode="w+")
print("Writing DEF file...")
f.write(self.to_def_format())
print("Writing done.")
f.close()
# Main Class
if __name__ == '__main__':
# read_path = "./libraries/DEF/c880_tri.def"
read_path = "./libraries/DEF/c2670_dq.def"
def_parser = DefParser(read_path)
def_parser.parse()
# for each_pin in def_parser.pins.pins:
# print (each_pin)
print (def_parser.to_def_format())
# test macro and via (note: only via1)
# macro_dict = macro_and_via1(def_parser)
# for comp in macro_dict:
# print (comp)
# for pin in macro_dict[comp]:
# print (" " + pin + ": " + str(macro_dict[comp][pin]))
# print ()