blob: 0f4986be7c238ece0d5915bb29bd9c56d9b1d2b9 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2020 Efabless Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import odb
parser = argparse.ArgumentParser(
description="Produces a DEF file where a design is shown in the context of its instantiation in a top-level design"
)
parser.add_argument("--macro-def", "-md", required=True, help="DEF view of the design")
parser.add_argument(
"--macro-lef",
"-ml",
required=True,
help="LEF file needed to have a proper view of the macro DEF",
)
parser.add_argument(
"--top-def",
"-td",
required=True,
help="DEF view of the top-level design where the macro is instantiated",
)
parser.add_argument(
"--top-lef",
"-tl",
required=True,
help="LEF file needed to have a proper view of the top-level DEF",
)
parser.add_argument(
"--output",
"-o",
required=True,
default="output.def",
help="Output Contextualized DEF",
)
parser.add_argument(
"--keep-inner-connections",
"-keep",
action="store_true",
default=False,
help="If set, the internal cells will remain conneted in the otput DEF",
)
args = parser.parse_args()
macro_def_file_name = args.macro_def
macro_lef_file_name = args.macro_lef
top_def_file_name = args.top_def
top_lef_file_name = args.top_lef
keep_flag = args.keep_inner_connections
output_def_file_name = args.output
# in the tcl side
# top_lef_new_file_name = os.path.join(os.path.dirname(macro_lef_file_name), os.path.basename(macro_lef_file_name) + ".top.lef")
# top_def_new_file_name = os.path.join(os.path.dirname(macro_def_file_name), os.path.basename(macro_def_file_name) + ".top.def")
# copy(os.path.normpath(top_lef_file_name), top_lef_new_file_name)
# copy(os.path.normpath(top_def_file_name), top_def_new_file_name)
# top_lef_file_name = top_lef_new_file_name
# top_def_file_name = top_def_new_file_name
db_macro = odb.dbDatabase.create()
db_top = odb.dbDatabase.create()
odb.read_lef(
db_macro, top_lef_file_name
) # must read first to have consistent views with the top-level
odb.read_lef(
db_macro, macro_lef_file_name
) # rest of the macros that don't appear in the top-level are covered here
odb.read_def(db_macro, macro_def_file_name)
odb.read_lef(db_top, top_lef_file_name)
odb.read_def(db_top, top_def_file_name)
chip_macro = db_macro.getChip()
block_macro = chip_macro.getBlock()
macro_design_name = block_macro.getName()
chip_top = db_top.getChip()
block_top = chip_top.getBlock()
top_design_name = block_top.getName()
print("Block design name:", macro_design_name)
print("Top-level design name:", top_design_name)
nets_top = block_top.getNets()
to_connect = {}
MACRO_TOP_PLACEMENT_X = 0
MACRO_TOP_PLACEMENT_Y = 0
MACRO_TOP_PLACEMENT_ORIENT = 0
assert macro_design_name in [
inst.getMaster().getName() for inst in block_top.getInsts()
], "%s not found in %s" % (macro_design_name, top_design_name)
for net in nets_top:
iterms = net.getITerms() # asssumption: no pins (bterms) on top level
block_net_name = None
for iterm in iterms:
macro_name = iterm.getMTerm().getMaster().getName()
if macro_name == macro_design_name:
block_net_name = iterm.getMTerm().getName()
macro_top_inst = iterm.getInst()
MACRO_TOP_PLACEMENT_X, MACRO_TOP_PLACEMENT_Y = macro_top_inst.getLocation()
MACRO_TOP_PLACEMENT_ORIENT = macro_top_inst.getOrient()
print("Block net name: ", block_net_name)
break
if block_net_name is not None:
to_connect[block_net_name] = []
for iterm in iterms:
macro_name = iterm.getMTerm().getMaster().getName()
if macro_name != macro_design_name:
to_connect[block_net_name].append(iterm)
block_net_name = None
# print(macro_name, inst_name, end= ' ')
# print(iterm.getMTerm().getName())
# print(to_connect)
nets_macro = block_macro.getNets()
created_macros = {}
for net in nets_macro:
iterms = net.getITerms() # asssumption: no pins (bterms) on top level
if not keep_flag:
for iterm in iterms:
iterm.disconnect()
if net.getName() in to_connect:
for node_iterm in to_connect[net.getName()]:
node_master = node_iterm.getMTerm().getMaster()
node_inst = node_iterm.getInst()
node_inst_name = node_iterm.getInst().getName()
if node_inst_name not in created_macros:
created_macros[node_inst_name] = 1
print("Creating: ", node_master.getName(), node_inst_name)
new_inst = odb.dbInst_create(block_macro, node_master, node_inst_name)
new_inst.setOrient(node_inst.getOrient())
new_inst.setLocation(
node_inst.getLocation()[0] - MACRO_TOP_PLACEMENT_X,
node_inst.getLocation()[1] - MACRO_TOP_PLACEMENT_Y,
)
new_inst.setPlacementStatus("FIRM")
else:
new_inst = block_macro.findInst(node_inst_name)
new_inst.findITerm(node_iterm.getMTerm().getName()).connect(net)
odb.write_def(block_macro, output_def_file_name)