首先,在pt里进行signoff timing分析,查看时序报告。下面的脚本以hold timing为例。
# 查看hold时序违例情况
pt_shell> report_constrainits -all_violators -min_delay
# 查看库里buffer、delay cell的名字
pt_shell> get_lib_cells */buf*
pt_shell> get_lib_cells */dl*
# 修hold
pt_shell> fix_eco_timing -type hold -buffer_list {dl01 dl02 buf01 buff02}
# 再报hold timing,看是否修干净
pt_shell> report_constrainits -all_violators -min_delay
# 写出pt修改的cell和连线信息
write_changes -format text -output pt_eco.txt
下面是一个自动生成的pt_eco.txt的格式:
Change list, formatted as text:
1. insert_buffer in <top>: added one 'dl01' 'A' to 'Y' on pin 'xxx_reg/Q' named 'net_PTECO_HOLD_NET1' 'U_PTECO_HOLD_BUF1'
2. insert_buffer in u_submodule1: added one 'buf01' 'A' to 'Y' on pin 'xxx_reg_2_/D' named 'net_PTECO_HOLD_NET2' 'U_PTECO_HOLD_BUF2'
3. size_cell in u_submodule2: 'U296' sized to 'buf01'
4. size_cell in <top>: 'U001' sized to 'nand02'
可见,有两种指令,insert_buffer和size_cell。在哪个pin前(或者后)插入某cell,并且指定了新的inst名字和新net名字。或者是修改哪个cell的驱动能力。
然后,利用ai编写脚本,转成innovus eco格式,下面是一个例子。可根据你的pt_eco.txt的实际情况,请ai再修改一下脚本。
import re
def convert_pt_to_innovus(input_path, output_path):
# 匹配 insert_buffer
insert_pattern = re.compile(r"insert_buffer\s+in\s+(<top>|[a-zA-Z0-9_]+):\s+added\s+one\s+'([^']+)'\s+'A'\s+to\s+'Y'\s+on\s+pin\s+'([^']+)'\s+named\s+'([^']+)'\s+'([^']+)'")
# 匹配 size_cell
size_pattern = re.compile(r"size_cell\s+in\s+(<top>|[a-zA-Z0-9_]+):\s+'([^']+)'\s+sized\s+to\s+'([^']+)'")
innovus_cmds = []
try:
with open(input_path, 'r', encoding='utf-8') as f:
for line_num, line in enumerate(f, 1):
line = line.strip()
if not line:
continue
# 1. 处理 insert_buffer
insert_match = insert_pattern.search(line)
if insert_match:
hier_inst = insert_match.group(1)
buf_type = insert_match.group(2)
pin_path = insert_match.group(3)
net_name = insert_match.group(4)
buf_inst_name = insert_match.group(5)
# 处理层次化拼接 (只对 term 进行拼接)
if hier_inst == '<top>':
full_pin_path = pin_path
else:
full_pin_path = f"{hier_inst}/{pin_path}"
# 修正:-name 只传基础名 (base name),不带层次前缀
cmd = f"ecoAddRepeater -term {full_pin_path} -cell {buf_type} -name {buf_inst_name}"
innovus_cmds.append(cmd)
continue
# 2. 处理 size_cell
size_match = size_pattern.search(line)
if size_match:
hier_inst = size_match.group(1)
inst_name = size_match.group(2)
new_cell_type = size_match.group(3)
# 处理层次化拼接
if hier_inst == '<top>':
full_inst_name = inst_name
else:
full_inst_name = f"{hier_inst}/{inst_name}"
# -inst 支持全层级路径
cmd = f"ecoChangeCell -inst {full_inst_name} -cell {new_cell_type}"
innovus_cmds.append(cmd)
# 写入输出文件
with open(output_path, 'w', encoding='utf-8') as f:
for cmd in innovus_cmds:
f.write(cmd + "\n")
print(f"转换成功!共转换了 {len(innovus_cmds)} 条命令。")
print(f"结果已保存至: {output_path}")
except FileNotFoundError:
print(f"错误: 找不到输入文件 '{input_path}',请检查文件路径。")
if __name__ == "__main__":
input_file = "pt_eco.txt"
output_file = "innovus_eco.tcl"
convert_pt_to_innovus(input_file, output_file)
最后,在innovus里source这个innovus_eco.tcl。重新导出数据,用pt检查时序是否修改好了。
innovus> setEcoMode -batchMode true -LEQCheck false -updateTiming false -refinePlace false
innovus> source -echo -verbose innvous_eco.tcl
innovus> setEcoMode -reset
innovus> setEcoMode -batchMode false
innovus> refinePlace
innovus> ecoRoute
