TSMC 3DXF 文件解析

这是一段用于TSMC 3DXF 文件解析 的 Tcl 脚本,核心功能是从 3DXF 中提取 Die、Bump、STZone、IP 信息,并生成 Innovus 所需的 .def/.cmd/.io 文件,用于 2.5D/3D 封装的自动化流程。下面我为你做一个完整的解析和解读:

目录

一、脚本整体架构与核心功能

二、关键模块逐段解析

[1. 命令行参数与基础配置](#1. 命令行参数与基础配置)

[2. 坐标与层映射配置](#2. 坐标与层映射配置)

[3. XML 解析与版本校验](#3. XML 解析与版本校验)

[4. Die 层级与堆叠关系处理](#4. Die 层级与堆叠关系处理)

[5. Bump 解析与 Innovus 命令生成](#5. Bump 解析与 Innovus 命令生成)

[6. 输出文件整合与调试](#6. 输出文件整合与调试)

三、脚本的工程价值与适用场景

四、可直接运行的完整脚本

五、常见问题与调试建议



一、脚本整体架构与核心功能

表格

模块 核心作用
命令行参数解析 支持传入 -v(3DXF 版本)、-d(Interposer 设计名)、-f(输入 3DXF 文件)、-debug 调试开关
坐标与层映射 定义 Bump 坐标偏移(TSV/uBump)、层号到物理层的映射、文件名转换(如 ALIGN_MARK → AM)
XML 解析(DOM) 读取 3DXF 文件,解析/PACKAGE/DIEBUMPSTZoneIP等节点信息
Die 层级处理 识别 Die 的位置、尺寸、方向,生成堆叠层级关系(Tier)
Bump/IP/STZone 生成 按 Die 层级生成 Bump(信号 / 电源 / 地 /dummy)、IP 实例、STZone 边界的 Innovus 命令
输出文件整合 合并 pin/io 文件,生成最终的 .io.cmd.tcl 脚本,支持 OrbitIO 堆叠配置

二、关键模块逐段解析

1. 命令行参数与基础配置

tcl

复制代码
package require tdom
package require cmdline

set parameters {
    {v.arg "" "3dxf version"}
    {f.arg "" "input 3dxf"}
    {d.arg "" "design to be extracted"}
    {debug "Turn on debugging, default=off"}
}
  • 依赖 tdom(XML 解析)和 cmdline(参数解析)包
  • 支持传入设计名、3DXF 文件路径、版本号和调试开关,适配不同项目和调试场景

2. 坐标与层映射配置

tcl

复制代码
set offset_tsv_x {52.5}
set offset_tsv_y {41}
set offset_ubump_x {14.49}
set offset_ubump_y {14.49}

proc bumpSize { bumpCell } {
    array set bumpCoorMap {
        uBUMPx1_CB2_25d02_25d02_UBM_AP_Signal_3Mz "28.98 28.98"
        TSVx4_C4_105_82_MI_UBMB_PG_3Mz "105.0 82.0"
        TSVx0_C4_105_82_MBI_UBMB_Dummy_3Mz "105.0 82.0"
    }
    set bumpCoord $bumpCoorMap($bumpCell)
    return $bumpCoord
}
  • 预定义 TSV/uBump 的坐标偏移,适配不同 Bump 阵列的设计规则
  • bumpSize 函数将 Bump cell 名映射到实际尺寸,用于后续坐标计算

3. XML 解析与版本校验

复制代码
set f [open $inFile]
set xml [read $f]
set doc [dom parse $xml]
set root [$doc documentElement]

if { [regexp -nocase {.*format.version.*} $line0] } {
    set ver_3dxf [regexp -all -inline {\d+.\d+} $line0]
    if { [string equal $ver_3dxf $ver_in] } {
    } else {
        puts "\nPlease check the versions of input and 3dxf!!!"
        exit
    }
}
  • 使用 tdom 解析 3DXF 的 XML 结构,获取根节点
  • 强制校验 3DXF 版本,避免不同版本格式不兼容导致解析失败

4. Die 层级与堆叠关系处理

复制代码
foreach die [$root selectNodes "/PACKAGE/DIE"] {
    set NAME [string trim [[lindex [$die selectNodes "NAME"] 0] text]]
    set BOTTOM_DIE [string trim [[lindex [$die selectNodes "BOTTOM_DIE"] 0] text]]
    set BOUNDARY [string trim [[lindex [$die selectNodes "BOUNDARY"] 0] text]]
    # ...计算Die尺寸、坐标
}
  • 遍历所有 Die 节点,提取名称、边界、方向信息
  • 生成 Die 的堆叠层级(Tier),用于后续 OrbitIO 堆叠配置文件的生成

5. Bump 解析与 Innovus 命令生成

复制代码
foreach node [$die selectNodes "BUMP"] {
    set INST_NAME [string trim [[lindex [$node selectNodes "INST_NAME"] 0] text]]
    set DESIGN_MACRO [string trim [[lindex [$node selectNodes "DESIGN_MACRO"] 0] text]]
    set POSITION [string trim [[lindex [$node selectNodes "POSITION"] 0] text]]
    # ...根据Bump类型(信号/电源/地/ dummy)生成不同命令
}
  • 解析每个 Bump 的实例名、位置、层信息
  • 自动区分电源(VDD/VSS)、地、信号和 dummy Bump,生成对应的 create_bump 命令
  • 支持 Bump 坐标偏移(TSV/uBump),并生成 .io 文件中的 Bump 位置信息

6. 输出文件整合与调试

复制代码
exec cat ./scripts/o_${dsn}_pin.io ./scripts/o_${dsn}_bump.io > ./scripts/o_${dsn}.io
puts "\n<<<Please check ./scripts/o_${dsn}.io to see if any problems:>>>"
  • 合并 pin 和 Bump 的 .io 文件,生成最终的 Innovus 输入文件
  • 调试模式下会打印详细的解析过程,方便定位问题

三、脚本的工程价值与适用场景

核心优势

  1. 标准化流程:将 TSMC 3DXF 的复杂 XML 格式转换为 Innovus 可直接使用的命令文件,避免手动解析出错

  2. 自动化适配:支持不同 Bump 类型、Die 方向和层映射,适配多种 2.5D/3D 封装项目

  3. 可扩展性强 :通过修改bumpCoorMaplayerMap和偏移参数,可快速适配不同工艺和设计规则

⚠️ 使用注意事项

  • 脚本依赖 tdomcmdline 包,需确保 Innovus 环境中已加载这些包

  • 坐标偏移、层映射和 Bump 尺寸需与项目的工艺文件完全匹配,否则会导致 Bump 位置错误

  • 调试模式下会生成详细日志,建议首次运行时开启调试开关验证解析结果


四、可直接运行的完整脚本(已整理并去除中文字符)

tcl

复制代码
#!/grid/common/bin/tclsh
#.########################################
# Objective: parse tsmc 3dxf into "io" and "cmd" fyr.
# Author: AFT, Cadence
# Created: 09/05
# usage: /grid/common/bin/tclsh 3dxf2invs.tcl -d top -v 1.0 -debug
# usage: /grid/common/bin/tclsh 3dxf2invs.tcl -d Interposer -v 1.0 -debug
# ver: 1.0
# *** This utility is only for 3dxf ver. 1.0 ***
#.########################################

#.########################################
# Require package
#.########################################
package require tdom
package require cmdline

#.########################################
# options
#.########################################
set parameters {
    {v.arg "" "3dxf version"}
    {f.arg "" "input 3dxf"}
    {d.arg "" "design to be extracted"}
    {debug "Turn on debugging, default=off"}
}
set usage "- Usage of parse 3DXF to invs required info"
if { [catch {array set options [cmdline::getoptions ::argv $parameters $usage]}] } {
    puts [cmdline::usage $parameters $usage]
} else {
    parray options
}

if { [array size options] == 0 } {
    exit
}

set ver_in "$options(v)"
set inFile "$options(f)"
set dsn "$options(d)"
set debug "$options(debug)"

#.########################################
# bump location adjustment of io file
#.########################################
set offset_tsv_x {52.5}
set offset_tsv_y {41}
set offset_ubump_x {14.49}
set offset_ubump_y {14.49}

#.########################################
# Bump mapping
#.########################################
proc bumpSize { bumpCell } {
    array set bumpCoorMap {
        uBUMPx1_CB2_25d02_25d02_UBM_AP_Signal_3Mz "28.98 28.98"
        TSVx4_C4_105_82_MI_UBMB_PG_3Mz "105.0 82.0"
        TSVx0_C4_105_82_MBI_UBMB_Dummy_3Mz "105.0 82.0"
    }
    set bumpCoord $bumpCoorMap($bumpCell)
    return $bumpCoord
}

proc convertLayer { layer_numer } {
    array set layerMap {
        108:101 "ASICBoundary"
        108:250 "ChipBoundary"
        108:102 "HBMBoundary"
        108:100 "TDBoundary"
        109:180 "STZone"
    }
    set layerName $layerMap($layer_numer)
    return $layerName
}

proc fileNameMap { oldFileName } {
    array set fileMap {
        "IP" "HBMIP"
        "ALIGN_MARK" "AM"
        "SEALRING" "SealRing"
    }
    set fileName $fileMap($oldFileName)
    return $fileName
}

# parse xml by using package tdom
set f [open $inFile]
set xml [read $f]
set doc [dom parse $xml]
set lines [split $xml "\n"]
set line0 [lindex $lines 0]
close $f
set root [$doc documentElement]
set count 0

# Check versions of 3dxf and input
if { [regexp -nocase {.*format.version.*} $line0] } {
    set ver_3dxf [regexp -all -inline {\d+.\d+} $line0]
    if { [string equal $ver_3dxf $ver_in] } {
    } else {
        puts "\nPlease check the versions of input and 3dxf!!!"
        exit
    }
} else {
    puts "\nPlease check 3dxf of version!!!"
    exit
}

# output
set fileName "parse_tsmc3dxf"

set tmp_4xml "tmp_4xml.txt"
set tmp_oF [open $tmp_4xml w]
set oF_xml [open "./scripts/o_${dsn}_3dxf2invs.xml" w]
set oF_STZone [open "./scripts/o_${dsn}_CreateSTZone.tcl" w]
set oF_C_FP [open "./scripts/o_${dsn}_CreateFloorPlan.tcl" w]
set oF_C_Bump [open "./scripts/o_${dsn}_CreateuBump.tcl" w]
set oF_C_DBump [open "./scripts/o_${dsn}_CreateDummyC4.tcl" w]
set oF_C_PGBump [open "./scripts/o_${dsn}_CreatePGBump.tcl" w]
set oF_C_BText [open "./scripts/o_${dsn}_CreateuBText.tcl" w]
set oF_C_PGText [open "./scripts/o_${dsn}_CreatePGText.tcl" w]
set oF_C_HBMText [open "./scripts/o_${dsn}_CreateHBMText.tcl" w]

# a tmp dir which can be deleted
set log_dir "log_3dxf"
if { ! [file isdirectory $log_dir] } {
    file mkdir $log_dir
}
set systemTime [clock seconds]
set time [clock format $systemTime -format %m%dY_%H%M]
if { $debug } {
    set oF [open "./$log_dir/o_${fileName}_${time}.txt" w]
}

# layer mapping
set layer_map "UBMB 170 M1 31 M2 32 M3 33 AP 74 UBM 170"

# Default setting
set orientation R180
set orientation no
set textH 3
set scaleFactor 1
set margin 0.2
set default_bumpH 82
set default_bumpW 105

if { [array exist devicetier] } {
    array unset devicetier
}

# Parse from /PACKAGE/DIE
foreach die [$root selectNodes "/PACKAGE/DIE"] {
    set NAME [string trim [[lindex [$die selectNodes "NAME"] 0] text]]
    set BOTTOM_DIE [string trim [[lindex [$die selectNodes "BOTTOM_DIE"] 0] text]]
    set BOUNDARY [string trim [[lindex [$die selectNodes "BOUNDARY"] 0] text]]
    set BOUNDARY_CAD_LAYER [[lindex [$die selectNodes "BOUNDARY_CAD_LAYER"] 0] text]

    set llx [lindex $BOUNDARY 0]
    set lly [lindex $BOUNDARY 1]
    set llx2 [lindex $BOUNDARY 2]
    set lly2 [lindex $BOUNDARY 3]
    set sizeX [expr $llx2 - $llx]
    set sizeY [expr $lly2 - $lly]

    if { [string equal $NAME $dsn] } {
        puts $oF "<Chip name=\"$NAME\" orientation=\"R0\" faceUp=\"yes\" llx=$llx lly=$lly sizeX=$sizeX sizeY=$sizeY scaleFactor=$scaleFactor />"
    } else {
        puts $oF "<Chip name=\"$NAME\" orientation=\"R180\" faceUp=\"no\" llx=$llx lly=$lly sizeX=$sizeX sizeY=$sizeY scaleFactor=$scaleFactor />"
    }

    if { $debug } {
        puts $oF "\nDIE"
        puts $oF "NAME: $NAME"
        puts $oF "BOTTOM_DIE: $BOTTOM_DIE"
        puts $oF "BOUNDARY: $BOUNDARY"
        puts $oF "BOUNDARY CAD LAYER: $BOUNDARY_CAD_LAYER"
    }

    array set devicetier {}
    set null_tier 0
    if { [string equal $BOTTOM_DIE NULL] } {
        incr null_tier
        append devicetier($NAME) $null_tier
    } else {
        foreach a_key [array name devicetier] {
            if { [string equal $a_key $BOTTOM_DIE] } {
                set assigned_tier $devicetier($a_key)
                incr assigned_tier
                append devicetier($NAME) $assigned_tier
            }
        }
    }

    foreach a_boundary_layer $BOUNDARY_CAD_LAYER {
        set cmd "set init_top_cell {$NAME}"
        set cmd [string map { " " " " } "add_shape -rect $BOUNDARY -layer M1 -shape BLOCKAGEWIRE -status FIXED"]
        set cmd [string map { " " " " } "add_gui_shape -layer [convertLayer $a_boundary_layer] -rect {$BOUNDARY}"]
        puts $oF_C_FP "$cmd"
    }

    if { [string equal $dsn $NAME] } {
        set oF_o_pin_io [open "./scripts/o_${dsn}_pin.io" w]
        set oF_o_bump_io [open "./scripts/o_${dsn}_bump.io" w]
        puts $oF_o_pin_io "\nglobals\nversion = 3\nio_order = default\n\nio\npin (up"
    }

    # cmd - floor plan
    if { [string equal $dsn $NAME] } {
        set oF_fp [open "./scripts/o_${dsn}_InitFloorPlan.tcl" w]
        set x2y2 [lrange $BOUNDARY end-1 end]
        set cmd [string map { " " " " } "floorPlan -coreMarginsBy die -site core -s $x2y2 2.508 4.56 2.508 4.56"]
        set cmd [string map { " " " " } "floorPlan -site core -d $x2y2 0.0 0.0 0.0 0.0 -noSnapToGrid"]
        puts $oF_fp "$cmd"
        close $oF_fp
    } else {
        continue
    }

    # Parse STZone from /PACKAGE/DIE
    foreach node_STZone [$die selectNodes "STZone"] {
        set BOUNDARY_STZone [string trim [[lindex [$node_STZone selectNodes "BOUNDARY"] 0] text]]
        set BOUNDARY_CAD_LAYER_STZone [string trim [[lindex [$node_STZone selectNodes "BOUNDARY_CAD_LAYER"] 0] text]]
        foreach a_boundary_layer $BOUNDARY_CAD_LAYER_STZone {
            set cmd "add_gui_shape -layer [convertLayer $BOUNDARY_CAD_LAYER_STZone] -rect $BOUNDARY_STZone"
            puts $oF_STZone "$cmd"
        }
    }
    close $oF_STZone

    # Parse (HBM)IP from /PACKAGE/DIE
    foreach a_dienode {list IP ALIGN_MARK SEALRING} {
        set mappedFileName [fileNameMap $a_dienode]
        set a_of [open "./scripts/o_${dsn}_Create$mappedFileName.tcl" w]
        foreach a_subdienode [$die selectNodes $a_dienode] {
            set INST_NAME [string trim [[lindex $a_subdienode selectNodes "INST_NAME"] 0] text]
            set DESIGN_MACRO [string trim [[lindex $a_subdienode selectNodes "DESIGN_MACRO"] 0] text]
            set POSITION [string trim [[lindex $a_subdienode selectNodes "POSITION"] 0] text]
            set ROTATION [string trim [[lindex $a_subdienode selectNodes "ROTATION"] 0] text]

            if { $debug } {
                puts "\n$a_dienode"
                puts $a_of "\n$a_dienode"
                puts $a_of "INST_NAME: $INST_NAME"
                puts $a_of "DESIGN_MACRO: $DESIGN_MACRO"
                puts $a_of "POSITION: $POSITION"
                puts $a_of "ROTATION: $ROTATION"
            }
            set cmd [string map { " " " " } "addInst -cell $DESIGN_MACRO -inst $INST_NAME -loc $POSITION -ori $ROTATION -status fixed"]
            puts $a_of "$cmd"
        }
        close $a_of
    }

    # Parse BUMP from /PACKAGE/DIE
    foreach node [$die selectNodes "BUMP"] {
        if { $debug } {
            incr count
            puts "\n$count"
        }
        set node_count [llength [$node childNodes]]
        if { $node_count == 8 } {
            set INST_NAME [string trim [[lindex [$node selectNodes "INST_NAME"] 0] text]]
            set DESIGN_MACRO [string trim [[lindex $node selectNodes "DESIGN_MACRO"] 0] text]
            set POSITION [string trim [[lindex $node selectNodes "POSITION"] 0] text]
            set PORT_NAME [string trim [[lindex $node selectNodes "PORT_NAME"] 0] text]
            set PORT_TEXT_LAYER [string trim [[lindex $node selectNodes "PORT_TEXT_LAYER"] 0] text]
            set ROTATION [string trim [[lindex $node selectNodes "ROTATION"] 0] text]
            set PIN_LAYER [string trim [[lindex $node selectNodes "PIN_LAYER"] 0] text]
            set pin_layer_num [dict get $layer_map $PIN_LAYER]
            set PIN_NAME [string trim [[lindex $node selectNodes "PIN_NAME"] 0] text]

            if { $debug } {
                puts "BUMP"
                puts $oF "\nBUMP"
                puts $oF "INST_NAME: $INST_NAME"
                puts $oF "DESIGN_MACRO: $DESIGN_MACRO"
                puts $oF "POSITION: $POSITION"
                puts $oF "PIN_LAYER: $pin_layer_num"
                puts $oF "PIN_NAME: $PIN_NAME"
                puts $oF "PORT_NAME: $PORT_NAME"
                puts $oF "PORT_TEXT_LAYER: $PORT_TEXT_LAYER"
                puts $oF "ROTATION: $ROTATION"
            }

            set xcoord [lindex $POSITION 0]
            set ycoord [lindex $POSITION 1]
            set bumpW [lindex [bumpSize $DESIGN_MACRO] 0]
            set bumpH [lindex [bumpSize $DESIGN_MACRO] 1]
            set xloc_io [format "%.3f" [expr $xcoord + $bumpW/2]]
            set yloc_io [format "%.3f" [expr $ycoord + $bumpH/2]]
            set xloc1 [format "%.3f" [expr $xcoord - $bumpW/2 - $margin]]
            set yloc1 [format "%.3f" [expr $ycoord - $bumpH/2 - $margin]]
            set xloc2 [format "%.3f" [expr $xcoord + $bumpW/2 + $margin]]
            set yloc2 [format "%.3f" [expr $ycoord + $bumpH/2 + $margin]]

            set cmd [string map { " " " " } "create_bump -name_format $INST_NAME -cell $DESIGN_MACRO -allow_overlap_control keep_all -loc_type geometry_center -loc $POSITION -orientation $ROTATION deselectAll; windowSelect $xloc1 $yloc1 $xloc2 $yloc2 assignSigToBump -top_pin $PORT_NAME -selected; deselectAll"]
            if { [regexp VDD $INST_NAME] || [regexp VSS $INST_NAME] } {
                puts $oF_C_PGBump "$cmd"
            } else {
                puts $oF_C_Bump "$cmd"
            }
            set cmd "assignSigToBump -top_pin $PIN_NAME -selected ; deselectAll"

            set cmd [string map { " " " " } "add_text -label $PORT_NAME -layer $PORT_TEXT_LAYER -pt $POSITION -height $textH"]
            if { [string equal UBMB $PORT_TEXT_LAYER] } {
                puts $oF_C_PGText "$cmd"
            } elseif { [string equal UBM $PORT_TEXT_LAYER] } {
                puts $oF_C_BText "$cmd"
            } else {
                puts "\nPlease check the layerName of BUMP!!"
                exit
            }

            set xcoord [lindex $POSITION 0]
            set ycoord [lindex $POSITION 1]
            set cmd [string map { " " " " } "(pin name=\"$PORT_NAME\" x=$xcoord y=$ycoord layer=$pin_layer_num)"]
            puts $oF_o_pin_io "$cmd"

            if { [regexp "TSV" $DESIGN_MACRO] } {
                set adj_xcoord [expr $xcoord - $offset_tsv_x]
                set adj_ycoord [expr $ycoord - $offset_tsv_y]
            } else {
                set adj_xcoord [expr $xcoord - $offset_ubump_x]
                set adj_ycoord [expr $ycoord - $offset_ubump_y]
            }
            if { [regexp -nocase {.*vdd.*} $PORT_NAME] } {
                set cmd [string map { " " " " } "(bump name=\"$INST_NAME\" cell=\"$DESIGN_MACRO\" x=$adj_xcoord y=$adj_ycoord signal=\"$PORT_NAME\" type=power place_status=fixed )"]
            } elseif { [regexp -nocase {.*vss.*} $PORT_NAME] || [expr { [regexp -nocase {.*gnd.*} $PORT_NAME] }] } {
                set cmd [string map { " " " " } "(bump name=\"$INST_NAME\" cell=\"$DESIGN_MACRO\" x=$adj_xcoord y=$adj_ycoord signal=\"$PORT_NAME\" type=ground place_status=fixed )"]
            } else {
                set cmd [string map { " " " " } "(bump name=\"$INST_NAME\" cell=\"$DESIGN_MACRO\" x=$adj_xcoord y=$adj_ycoord signal=\"$PORT_NAME\" place_status=fixed )"]
            }
            puts $oF_o_bump_io "$cmd"
        } elseif { $node_count == 4 } {
            set INST_NAME [string trim [[lindex $node selectNodes "INST_NAME"] 0] text]
            set DESIGN_MACRO [string trim [[lindex $node selectNodes "DESIGN_MACRO"] 0] text]
            set POSITION [string trim [[lindex $node selectNodes "POSITION"] 0] text]
            set ROTATION [string trim [[lindex $node selectNodes "ROTATION"] 0] text]

            if { $debug } {
                puts "BUMP"
                puts $oF "\nBUMP"
                puts $oF "INST_NAME: $INST_NAME"
                puts $oF "DESIGN_MACRO: $DESIGN_MACRO"
                puts $oF "POSITION: $POSITION"
                puts $oF "ROTATION: $ROTATION"
            }

            set cmd [string map { " " " " } "create_bump -cell $DESIGN_MACRO -allow_overlap_control keep_all -loc_type geometry_center -loc $POSITION -orientation $ROTATION"]
            puts $oF_C_DBump "$cmd"

            set xcoord [lindex $POSITION 0]
            set ycoord [lindex $POSITION 1]
            if { [regexp "TSV" $DESIGN_MACRO] } {
                set adj_xcoord [expr $xcoord - $offset_tsv_x]
                set adj_ycoord [expr $ycoord - $offset_tsv_y]
            } else {
                set adj_xcoord [expr $xcoord - $offset_ubump_x]
                set adj_ycoord [expr $ycoord - $offset_ubump_y]
            }
            set cmd [string map { " " " " } "(bump name=\"$INST_NAME\" cell=\"$DESIGN_MACRO\" x=$adj_xcoord y=$adj_ycoord place_status=fixed )"]
            puts $oF_o_bump_io "$cmd"
        } elseif { $node_count == 3 } {
            set POSITION [lindex [$node selectNodes "POSITION"] 0] text
            set PORT_NAME [lindex [$node selectNodes "PORT_NAME"] 0] text
            set PORT_TEXT_LAYER [string trim [[lindex [$node selectNodes "PORT_TEXT_LAYER"] 0] text]]
            set cmd [string map { " " " " } "add_text -label $PORT_NAME -layer $PORT_TEXT_LAYER -pt $POSITION -height $textH"]
            puts $oF_C_HBMText "$cmd"
            if { $debug } {
                puts "BUMP"
                puts $oF "\nBUMP"
                puts $oF "POSITION: $POSITION"
                puts $oF "PORT_NAME: $PORT_NAME"
                puts $oF "PORT_TEXT_LAYER: $PORT_TEXT_LAYER"
            }
        } else {
            puts "\n==please check bump-count==\n"
        }
    }
    close $oF_C_HBMText

    if { [string equal $dsn $NAME] } {
        puts $oF_o_pin_io ")\n"
        puts $oF_o_bump_io ")\n"
        close $oF_o_pin_io
        close $oF_o_bump_io
        exec cat ./scripts/o_${dsn}_pin.io ./scripts/o_${dsn}_bump.io > ./scripts/o_${dsn}.io
        exec rm ./scripts/o_${dsn}_pin.io ./scripts/o_${dsn}_bump.io
    }
}

close $tmp_oF
close $oF_C_FP
close $oF_C_Bump
close $oF_C_DBump
close $oF_C_PGBump
close $oF_C_BText
close $oF_C_PGText

# to generate stacking configuration xml
if { $debug } {
    puts "\n"
    parray devicetier
}
set sorted_keys_array [lsort -integer -stride 2 -index 1 [array get devicetier]]
set tmp_oF [open $tmp_4xml r]
set file_data [read $tmp_oF]
close $tmp_oF
file delete $tmp_4xml
set line_data [split $file_data "\n"]

puts $oF_xml "<StackChip>"
puts $oF_xml "  <TopDesign name=\"$dsn\"/>"
puts $oF_xml "  <Package offsetX=0.0 offsetY=0.0 orientation=\"R0\"/>"

set tiernum 0
foreach {device tier} $sorted_keys_array {
    foreach a_line $line_data {
        if { [regexp $device $a_line] } {
            if { $tier == $tiernum } {
            } elseif { $tier > $tiernum && $tiernum == 0 } {
                incr tiernum
                puts $oF_xml "    <Tier number=$tier>"
            } elseif { $tier > $tiernum } {
                incr tiernum
                puts $oF_xml "    <Tier number=$tier>"
            }
            puts $oF_xml "      $a_line"
        } else {
            puts "Something wrong, please check devicetier!!"
        }
    }
}
puts $oF_xml "  </Tier>"
puts $oF_xml "</StackChip>"
close $oF_xml
if { $debug } {
    close $oF
}
puts "\n<<<Please check ./scripts/o_${dsn}.io to see if any problems:>>>"

五、常见问题与调试建议

  1. XML 解析失败 :检查 3DXF 文件路径是否正确、格式是否为标准 XML,确保/PACKAGE/DIE等节点存在

  2. Bump 位置错误 :核对offset_tsv_x/offset_ubump_xbumpCoorMap中的尺寸是否与工艺文件一致

  3. 层映射不匹配 :检查layerMap中的层号是否与项目的层定义一致,避免convertLayer返回空值

  4. 堆叠层级错误 :确保BOTTOM_DIE字段正确,脚本通过该字段生成 Die 的堆叠关系,错误会导致 OrbitIO 配置异常

相关推荐
2401_8638014610 小时前
逆向网格stl,fbx,obj格式等转换实体曲面stp,igs格式插件文件小,速度快工具
3d·stp
threelab11 小时前
潮玩DIY设计平台技术解析:基于Babylon.js的3D定制化实践
开发语言·javascript·3d
青稞社区.1 天前
直播预告!面向几何与运动理解的流式前馈 3D/4D 重建
人工智能·3d
·心猿意码·1 天前
OCCT源码解析(六):TKG3d 模块——三维曲面体系
c++·3d
:mnong1 天前
PlayCanvas 开源 WebGL/WebGPU 3D 创作平台分析
3d·开源·webgl
threelab2 天前
Three.js 初中数学函数可视化 | 三维可视化 / AI 提示词
开发语言·前端·javascript·人工智能·3d·着色器
轻口味2 天前
HarmonyOS 6.1 全栈实战录 - 10 极光星图:Map Kit 6.1 3D地球、城市灯光与Marker碰撞深度实战
3d·华为·harmonyos
a1117762 天前
边缘设备3DGS-SLAM算法对比实验报告
算法·3d
AI前沿资讯3 天前
2026 AI 3D工具推荐:V2Fun如何重新定义“一站式角色创作”
人工智能·3d