Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
2b9f52212This file is pinned to the selected release. Download the original to open it in your design tool.
# MIT License
#
# Copyright (c) 2020 Tri Minh Cao
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""
DEF Parser
Author: Tri Minh Cao
Email: tricao@utdallas.edu
Date: August 2016
Changes by Tobias Senti
- SPECIALNETS support
- improved to_def_format()
- Write Format: Make similar to OpenROAD's DEF writer
"""
from .def_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.specialnets = 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
# add support for custom VIAS
self.vias = []
def parse(self):
"""
Main method to parse the DEF file
:return: void
"""
print("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] == "VIAS":
handleVias(self.vias, f)
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] == "SPECIALNETS":
new_specialnets = SpecialNets(int(info[1]))
self.stack.append(new_specialnets)
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 == "SPECIALNETS_DEF":
self.specialnets = sec
elif sec.type == "NETS_DEF":
self.nets = sec
print("Parsing DEF file done.\n")
def update_sec(self, sec, sec_type):
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 == "SPECIALNETS_DEF":
self.specialnets = sec
elif sec_type == "NETS_DEF":
self.nets = sec
for idx, old_sec in enumerate(self.sections):
if old_sec.type == sec_type:
self.sections[idx] = sec
return
def to_def_format(self):
s = ""
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 += "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"
for each_row in self.rows:
s += each_row.to_def_format()
s += "\n"
for each_tracks in self.tracks:
s += each_tracks.to_def_format()
s += "\n"
for each_gcell in self.gcellgrids:
s += each_gcell.to_def_format()
s += "\n"
for sec in self.sections:
s += sec.to_def_format()
s += "\n"
s += "END DESIGN\n"
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()
def handleVias(vias, f):
viasData = []
line = next(f)
while line.strip().lower() != "end vias":
vias.append(line)
line = next(f)
# Main Class
# if __name__ == '__main__':
# read_path = "./libraries/DEF/c880_tri.def"
"""read_path = "./libraries/DEF/c1908.def"
def_parser = DefParser(read_path)
def_parser.parse()
# for each_pin in def_parser.pins.pins:
# print (each_pin)
for net in def_parser.nets:
print (net)
"""
# 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 ()