芯片TO前会进行一些IP merge等工作,所以后期再通过查看当时export的log文件来检查所使用的layer 层次信息并不能准确反应GDS/OAS中的数据内容。
另一方面TO前工艺厂也会要求提供design中使用的device 和需要的mask layer,这也要基于真实的GDS/OAS中的层次数据来填写。防止人为失误导致必要层次缺失和额外禁用层次。提交给fab前一定需要做的一项检查。例如,以前遇到项目不使用DNW 层,在项目TO前检查出某IP中DNW 没有处理干净。导致IP需要重新处理验证临时工作量增加。
对于design 中使用了哪些类型的device,我们一般都可以从lvs的report 中提取出来抽取到的device。前提lvs pass。但对于所用到的layer信息,比较难从验证数据中取到。(之前写过用calibre 的 query和Yield server也是可以的,只是数据使用svdb和dfmdb)
下面写了个集成在CC上的工具。其原理是后台调用drv command来抽取layer number 信息,然后基于给定的参考信息,分析是否有使用到禁用层。并输出一份层次使用情况的报告。
如下在custom compiler 的console中source 下面脚本,生产如下对话框。选择oas 或gds格式数据,选择对于的layer map文件。下面提供了一个输入list框,用户可以把禁用的层次,或特殊必要layer number 输入。便于后面对比检查。
这里脚本添加了notify-send指令,在检查到禁用layers时会及时在linux桌面上弹出提示。
定制的check 脚本报告格式等都可以灵活改动。
脚本如下:
proc genLayerMap {file} {
global layerRelative
array set layerRelative [list]
set f [open $file r]
while {[gets $f data] >= 0} {
set value "[lindex $data 0] [lindex $data 1]"
set key "[lindex $data 2] [lindex $data 3]"
if {[info exists layerRelative($key)]} {
lappend layerRelative($key) $value
} else {
set layerRelative($key) $value
}
}
close $f
}
proc createMainRule {dataInput layerMapFile forbidLayer} {
global layerRelative
if {[file exist ".ccScanOas.tcl"]} {
file delete -force ".ccScanOas.tcl"
}
set f [open .ccScanOas.tcl w]
puts $f "
if {\[file exist layerCheck.rep\]} {
file delete -force layerCheck.rep
}
set usedLayer \"\"
set forbidLayer \"\"
if {\[file exist $layerMapFile\]} {
array set layerRelative \[list\]
set ff \[open $layerMapFile r\]
while {\[gets \$ff data\] >= 0} {
set value \"\[lindex \$data 0\] \[lindex \$data 1\]\"
set key \"\[lindex \$data 2\] \[lindex \$data 3\]\"
if {\[info exists layerRelative(\$key)\]} {
lappend layerRelative(\$key) \$value
} else {
set layerRelative(\$key) \$value
}
}
close \$ff
}
set layout \[layout create $dataInput -dt_expand -preservePaths -preserveTextAttributes -preserveProperties\]
set allLayers \[\$layout layers\]
foreach lay \$allLayers {
if {\[string match \"*\.*\" \$lay\]} {
set key \[split \$lay \".\"\]
} else {
set key \"\$lay 0\"
}
foreach probLay {$forbidLayer} {
set probKey \"\[lindex \$probLay 0\] \[lindex \$probLay 1\]\"
if {\$probKey == \$key} {
if {\[info exists layerRelative(\$key)\]} {
append forbidLayer \"\n \$layerRelative(\$key) <==> \$key\"
} else {
append forbidLayer \"\n \$key\"
}
}
}
if {\[info exists layerRelative(\$key)\]} {
append usedLayer \"\n \$layerRelative(\$key) <==> \$key \"
} else {
append forbidLayer \"\n \$key\"
}
}
set ffo \[open layerCheck.rep w\]
puts \$ffo \"\n ###### design used layers #####\"
puts \$ffo \$usedLayer
puts \$ffo \"\n ###### design forbid layers #####\"
puts \$ffo \$forbidLayer
close \$ffo
if {\$forbidLayer != \"\"} {
exec notify-send \"Warn:\$forbidLayer\"
exec gvim layerCheck.rep
} else {
exec notify-send \"Pass\"
}
"
close $f
《部分代码不展示》
}
proc execRuleCheck {widget} {
set dataInput [db::getAttr value -of [gi::findChild dataInput -in $widget]]
set layerMapFile [db::getAttr value -of [gi::findChild layerMapFile -in $widget]]
set forbidLayer [db::getAttr value -of [gi::findChild forbidLayer -in $widget]]
createMainRule $dataInput $layerMapFile $forbidLayer
}
proc mainForm {} {
set alive [gi::getDialogs ccDRV]
if {[db::getCount $alive] != 0} {
gi::closeWindows $alive
}
set ccDRV [gi::createDialog ccDRV -title "mask number check" \
-showHelp false -execProc "execRuleCheck"]
set dataInput [gi::createFileInput dataInput -parent $ccDRV -label "GDS/OASIS File:" \
-fileMasks {"oas (*.oas)" "gds (*.gds)" "GDS (*.GDS)" "OAS (*.OAS)" "(*)"}]
set layerMapFile [gi::createFileInput layerMapFile -parent $ccDRV -label "layerMap File:" \
-fileMasks {"layerMap (*.layerMap)" "map (*.map)" "(*)"}]
set forbidLayer [gi::createDynamicList forbidLayer -parent $ccDRV -label "forbid Layers:" ]
}
mainForm