mirror of
https://github.com/The-OpenROAD-Project/OpenLane.git
synced 2026-06-03 00:08:08 +08:00
+ Added linting rules for flake8, formatting with black + Added a GitHub Action to enforce lint/format rules
168 lines
5.5 KiB
Python
168 lines
5.5 KiB
Python
#!/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)
|