Orcad下使用TCL脚本自动生成导线、网络标号和off page

来源:互联网 发布:搜索与回溯算法 编辑:程序博客网 时间:2024/04/29 04:05

Orcad是一个很优秀的原理图工具,但是手工画批量导线和网络标号的时候(比如:RGB的信号线,DDR/FLASH的地址线),比较麻烦,修改也麻烦。所以这里介绍了使用TCL脚本自动生成导线、网络标号和off page的方法。

建议新建一个page(相当于草稿纸),再使用脚本,脚本生成的东西会自动剪切,这样更方便使用。(如果不需要剪切的功能,可以注释掉Cut命令)。

先介绍如何使用orcad.tcl,源代码在最后面。

1、新建一个load_tcl.tcl文件,内容如下:

proc ra {} {
    source "G:\\WorkDir\\ProTCL\\orcad.tcl"
}

proc ds {} {
    puts "D:\\Cadence\\SPB_16.6\\tools\\capture\\tclscripts\\capAutoLoad\\load_tcl.tcl"
    puts "G:\\WorkDir\\ProTCL\\orcad.tcl"
}

proc ed {} {
    exec "D:\\Sublime Text 2\\sublime_text.exe" "G:\\WorkDir\\ProTCL\\orcad.tcl" &
}
上面所有路径需要自己修改,路径分隔符可以用/或\\,不是\,不要有空格或者中文

其中,orcad.tcl是放在其它地方的TCL脚本。

增加ds命令,以防忘记load_tcl.tcl和orcad.tcl的路径。ed命令可以直接调用sublime来修改orcad.tcl,这样就不需要再找这个文件了。

然后把load_tcl.tcl放在D:\Cadence\SPB_16.6\tools\capture\tclscripts\capAutoLoad,这样,每次打开Orcad时,会自动装载这个load_tcl.tcl。

2、打开Orcad,在View->Toolbar->Command Window下,打开TCL控制台。

此外,page的单位要选择inch,后面的脚本是以0.1 inch为基准单位的。

捕捉栅格的单位必须是0.1 inch


3、自动生成阵列网络标号。

先输入ra让脚本运行一下。


再输入 ca ADDR 0 3,其中ADDR是你要的网络标号前缀(不能使用中括号,强制使用大写),后面0和3是对应的序号,这样就自动生成如下图所示的导线和网络标号了。自动计算导线长度,并自动选中并剪切生成的东西。如果要生成的标号太多,Orcad会卡一下,请耐心等待。


如果要降序,可以使用ca ADDR 3 0。

此外,可以在ca命令的结果后面添加任意多个字符串,如ca ADDR 3 0 _SDR。

4、自动生成任意网络标号。

先在orcad.tcl,写好需要生成的网络标号名(可以使用中括号,强制使用大写),其中X,NC和电源引脚都会跳过,不生成导线和网络标号的(不分大小写)。

如果标号名写成XX、ANC,还是会生成导线和网络标号的。自动计算导线长度,并自动选中并剪切生成的东西。


删掉最前面的#号如下图所示,#号代表注释(代码不起作用)。


完成后,如下图所示。注意:$custom_nets和set custom_nets这两个地方,custom_nets不要写错,不然没法运行脚本。


保存orcad.tcl,在控制台下输入ra,回车,就出现如下图所示。


根据前文所述,只要你添加set命令和cf命令,就能生成你自定义的网络标号名称

你也可以保存其它芯片的引脚名,以便重复使用。(在excel下copy引脚名过来,使用sublime下,ctrl+J可以合并多行)

使用时,如下图所示,保存之后,在orcad的控制台下输入ra,回车。这里,只允许运行一条cf命令,否则生成的网络标号会重叠在一起,没法使用。

如果你想屏蔽其它网络标号,可以修改这里的正则表达式。具体可以参考TCL TK官网的手册,这里用的是orcad 16.6,TCL版本是8.4,所以switch不能使用-nocase选项。


5、查找网络标号。

fn后面跟着你要找的标号名就可以了。


6、查找引脚名。

用法跟查找标号名一样。此外,这里还提供了相似的命令,比如:把FindPins替换为FindText就能用了,用法都一样的。


7、替换标号名。

rn后面跟着旧的网络名和新的网络名,然后以旧换新,这里也提供了相似的命令,跟第6点一样的,换个命令名就能用了。

注意:这里的替换,是把所有page里的匹配内容都换掉的,使用前请考虑清楚。


8、互换标号名。

用法跟替换一样,效果如下图所示。


注意:这里的互换,是把所有page里的匹配内容都换掉的,使用前请考虑清楚。

查找、替换、互换命令,都可以使用正则表达式。

9、取出网络标号名。

先选中网络标号,再Ctrl+C拷贝,即可Ctrl+V粘贴到sublime编辑一下,再用cf生成新的网络标号。

10、取出引脚名。

先选中引脚,再使用gs命令,即可以控制台获得引脚名。这样可以拷贝到sublime编辑一下,再用cf生成新的网络标号。

使用时请注意:取出的引脚名,并不以原理图的位置排列,而是按照Orcad数据库的存储位置排列。


11、取出引脚名,同时生成导线和网络标号。

先选中引脚,再使用gf命令,即可以控制台获得引脚名,同时会自动生成导线和网络标号。

gf命令相当于gs + cf。

使用时请注意:取出的引脚名,并不以原理图的位置排列,而是按照Orcad数据库的存储位置排列。


12、自动生成off page。

先设置好库的路径,如下图所示。


使用ia命令,即可生成输入/向左的off page,用法跟ca命令相似。

使用oa命令,即可生成输出/向右的off page,用法跟ca命令相似。

使用idf命令,即可生成输入/向左的off page,用法跟cf命令相似。

使用odf命令,即可生成输出/向右的off page,用法跟cf命令相似。

其中生成的输出/向右的off page都会自动排版。


13、为了方便使用,所有的命令名称都比较短,不记得就用dh看看(唯一需要记住的命令)。


更多的Orcad命令,可以参考官方手册。


Orcad命令分为三个部分:基本命令,数据库命令和CaptureCIS命令。

基本命令是非常简单易用的,数据库命令稍为复杂(是个面向对象的数据库,不是关系型的),CaptureCIS命令则只能在CIS下运行。

要掌握Orcad命令,关键在于掌握数据库,这样的话,你就能随心所欲地操控Orcad了。包括制作自己的菜单,批量修改元件封装,甚至调用爬虫库自动查找并下载芯片手册,在他人的机子上一键完成自定义的配置、色彩,一键导出各种自定义的报告、BOM表等。

此外,如果你的PCB要让别人画,但是又不得不给出原理图,有部分关键的参数不想让别人知道的话,你是可以利用脚本把芯片名、引脚名、参数、网络标号、Symbol全部加密,而封装和网表不变。

有兴趣的读者可以尝试做这些功能,做好的脚本也能使用orcad加密,这样,可以让别人使用但看不到里面的源码。

14、orcad.tcl源代码。保存路径,一定要跟load_tcl.tcl当中source命令下的路径对应上

########## this a tcl script for orcad ##########
package require capDesignUtil 1.0

# find net name
proc fn { netname } {
    FindNets $netname 1
}

# find pin name
# similar commands : FindText , FindParts , FindPins , FindNets , FindOffPageConnectors , FindHierarchicalPorts , FindBookMarks , FindDRCMarks
proc fp { pinname } {
    FindPins $pinname 1
}

# replace net name of all pages
# similar commands : replaceText , replaceAlias , replaceOffPageText , replaceGlobalText , replacePortText
proc rn { old_netname new_netname } {
    ::capDesignUtil::replaceAlias $old_netname $new_netname
}

# exchange net name of all pages
proc en { first_netname second_netname } {
    ::capDesignUtil::replaceAlias $first_netname __Temp_Net_Name_
    ::capDesignUtil::replaceAlias $second_netname $first_netname
    ::capDesignUtil::replaceAlias __Temp_Net_Name_ $second_netname
    ZoomSelection
}

# customize array wires placing method
proc ca { netname start_num end_num args } {
    set netname [string toupper $netname]
    set args [string toupper $args]

    set head_strlen [string length $netname]
    set tail_strlen [string length $args]
    set start_num_strlen [string length $start_num]
    set end_num_strlen [string length $end_num]
    
    if {$start_num_strlen > $end_num_strlen} {
        set max_strlen [expr $head_strlen + $tail_strlen + $start_num_strlen]
    } else {
        set max_strlen [expr $head_strlen + $tail_strlen + $end_num_strlen]
    }

    # $wlen_end - $wlen_start = wire length
    set wlen_start 0.5
    set wlen_end [expr round( 10 * ($max_strlen * 0.07 + $wlen_start + 0.4)) * 0.1]

    set index [expr abs($start_num-$end_num)+1]
    for {set i 1} {$i <= $index} {incr i} {
        set y1 [expr $i / 10.0 + 0.3]
        PlaceWire $wlen_start $y1 $wlen_end $y1
        if {$start_num >= $end_num} {
            set new_netname $netname[expr $start_num - $i + 1]$args
        } else {
            set new_netname $netname[expr $start_num + $i - 1]$args
        }
        puts $new_netname
        PlaceNetAlias [expr $wlen_start + 0.2 ] $y1 $new_netname
    }
    SelectBlock [expr $wlen_end + 0.1] 0.2 [expr $wlen_start - 0.1] \
                [expr $index / 10.0 + 0.4] 1
    Cut
}

# customize different wires placing method
proc cf { netnames args } {
    set netnames [string toupper $netnames]
    set args [string toupper $args]

    lappend netnames $args
    set max_strlen 0
    for {set i 1} {$i <= [llength $netnames]} {incr i} {
        set one_net [lindex $netnames [expr $i-1]]
        set current_strlen [string length $one_net]
        if {$current_strlen > $max_strlen} {
            set max_strlen $current_strlen
        }
    }

    # $wlen_end - $wlen_start = wire length
    set wlen_start 0.5
    set wlen_end [expr round( 10 * ($max_strlen * 0.07 + $wlen_start + 0.4)) * 0.1]

    for {set i 1} {$i <= [llength $netnames]} {incr i} {
        set y1 [expr $i / 10.0 + 0.3]
        set one_net [lindex $netnames [expr $i-1]]
        if { $one_net != ""  && $one_net != {} } {
            switch -regexp -- $one_net {
                ^NC[0-9]|^nc[0-9]|^NC$|^nc$     {continue}
                ^X$|^x$                         {continue}
                VCC+|vcc+                        {continue}
                VDD+|vdd+                        {continue}
                VSS+|vss+                        {continue}
                GND+|gnd+                        {continue}
                default     {PlaceWire $wlen_start $y1 $wlen_end $y1
                            puts $one_net
                            PlaceNetAlias [expr $wlen_start + 0.2 ] $y1 $one_net$args}
            }
        }
    }
    SelectBlock [expr $wlen_end + 0.1] 0.2 [expr $wlen_start - 0.1] \
                [expr [llength $netnames] / 10.0 + 0.4] 1
    Cut
}

# in off page array
proc ia { netname start_num end_num args} {
    set netname [string toupper $netname]
    set args [string toupper $args]

    set lib_path D:\\Cadence\\SPB_16.6\\tools\\capture\\library\\CAPSYM.OLB
    set head_strlen [string length $netname]
    set tail_strlen [string length $args]
    set start_num_strlen [string length $start_num]
    set end_num_strlen [string length $end_num]
    
    if {$start_num_strlen > $end_num_strlen} {
        set max_strlen [expr $head_strlen + $tail_strlen + $start_num_strlen]
    } else {
        set max_strlen [expr $head_strlen + $tail_strlen + $end_num_strlen]
    }

    # $wlen_end - $wlen_start = off page length
    set wlen_start 0.5
    set wlen_end [expr round( 10 * ($max_strlen * 0.07 + $wlen_start + 0.4)) * 0.1]

    set index [expr abs($start_num-$end_num)+1]

    for {set i 1} {$i <= $index} {incr i} {
        set y1 [expr $i / 10.0 + 0.3]
        if {$start_num >= $end_num} {
            set new_netname $netname[expr $start_num - $i + 1]$args
        } else {
            set new_netname $netname[expr $start_num + $i - 1]$args
        }
        puts $new_netname
        PlaceOffPage [expr $wlen_start + 0.2 ] $y1 $lib_path OFFPAGELEFT-L $new_netname
    }
    SelectBlock [expr $wlen_end-0.1] 0.4 [expr $wlen_start+0.1] \
                [expr $index / 10.0 + 0.5] 1
    Cut
}

# customize different wires placing method
proc idf { netnames args } {
    set netnames [string toupper $netnames]
    set args [string toupper $args]

    set lib_path D:\\Cadence\\SPB_16.6\\tools\\capture\\library\\CAPSYM.OLB
    lappend netnames $args
    set max_strlen 0
    for {set i 1} {$i <= [llength $netnames]} {incr i} {
        set one_net [lindex $netnames [expr $i-1]]
        set current_strlen [string length $one_net]
        if {$current_strlen > $max_strlen} {
            set max_strlen $current_strlen
        }
    }

    # $wlen_end - $wlen_start = wire length
    set wlen_start 0.5
    set wlen_end [expr round( 10 * ($max_strlen * 0.07 + $wlen_start + 0.4)) * 0.1]

    for {set i 1} {$i <= [llength $netnames]} {incr i} {
        set y1 [expr $i / 10.0 + 0.3]
        set one_net [lindex $netnames [expr $i-1]]
        if { $one_net != ""  && $one_net != {} } {
            switch -regexp -- $one_net {
                ^NC[0-9]|^nc[0-9]|^NC$|^nc$     {continue}
                ^X$|^x$                         {continue}
                VCC+|vcc+                        {continue}
                VDD+|vdd+                        {continue}
                VSS+|vss+                        {continue}
                GND+|gnd+                        {continue}
                default     {puts $one_net
                            PlaceOffPage [expr $wlen_start + 0.2 ] $y1 $lib_path OFFPAGELEFT-L $one_net}
            }
        }
    }
    SelectBlock [expr $wlen_end + 0.1] 0.4 [expr $wlen_start - 0.1] \
                [expr [llength $netnames] / 10.0 + 0.5] 1
    Cut
}

# customize method of placing array out/right off page
proc oa { netname start_num end_num args } {
    set netname [string toupper $netname]
    set args [string toupper $args]

    set lib_path D:\\Cadence\\SPB_16.6\\tools\\capture\\library\\CAPSYM.OLB
    set head_strlen [string length $netname]
    set tail_strlen [string length $args]
    set start_num_strlen [string length $start_num]
    set end_num_strlen [string length $end_num]
    
    if {$start_num_strlen > $end_num_strlen} {
        set max_strlen [expr $head_strlen + $tail_strlen + $start_num_strlen]
    } else {
        set max_strlen [expr $head_strlen + $tail_strlen + $end_num_strlen]
    }

    # $wlen_end - $wlen_start = off page length
    set wlen_start 1.5
    set wlen_end [expr round( 10 * ($max_strlen * 0.07 + $wlen_start + 0.4)) * 0.1]

    set index [expr abs($start_num-$end_num)+1]
    set base_strlen [string length "OFFPAGELEFT-R"]

    for {set i 1} {$i <= $index} {incr i} {
        set y1 [expr $i / 10.0 + 0.3]
        if {$start_num >= $end_num} {
            set new_netname $netname[expr $start_num - $i + 1]$args
        } else {
            set new_netname $netname[expr $start_num + $i - 1]$args
        }
        puts $new_netname
        PlaceOffPage [expr $wlen_start + 0.2 ] $y1 $lib_path OFFPAGELEFT-R $new_netname
        # move string of out off page automatically
        set diff_strlen [expr abs($base_strlen - $max_strlen) / 10.0]
        if {$base_strlen > $max_strlen} {
            capMoveMouseAndClick [expr $wlen_start - 0.5] [expr $i / 10.0 + 0.4]
            Move [expr $wlen_start - 1.6 + $diff_strlen * 0.75 - $diff_strlen / 10.0] \
                 [expr $i / 10.0 - 0.1 * $i -0.01] 1
        } else {
            capMoveMouseAndClick [expr $wlen_start - 0.5] [expr $i / 10.0 + 0.4]
            Move [expr $wlen_start - 1.5 - $diff_strlen * 0.68 + $diff_strlen / 10.0] \
                 [expr $i / 10.0 - 0.1 * $i -0.01] 1
        }
    }
    SelectBlock [expr $wlen_end-0.1] 0.4 [expr $wlen_start+0.1] \
                [expr $index / 10.0 + 0.5] 1
    Cut
}

# customize method of placing different out/right off page
proc odf { netnames args } {
    set netnames [string toupper $netnames]
    set args [string toupper $args]

    set lib_path D:\\Cadence\\SPB_16.6\\tools\\capture\\library\\CAPSYM.OLB
    lappend netnames $args
    set max_strlen 0
    for {set i 1} {$i <= [llength $netnames]} {incr i} {
        set one_net [lindex $netnames [expr $i-1]]
        set current_strlen [string length $one_net]
        if {$current_strlen > $max_strlen} {
            set max_strlen $current_strlen
        }
    }

    # $wlen_end - $wlen_start = wire length
    set wlen_start 1.5
    set wlen_end [expr round( 10 * ($max_strlen * 0.07 + $wlen_start + 0.4)) * 0.1]
    set base_strlen [string length "OFFPAGELEFT-R"]

    for {set i 1} {$i <= [llength $netnames]} {incr i} {
        set y1 [expr $i / 10.0 + 0.3]
        set one_net [lindex $netnames [expr $i-1]]
        if { $one_net != ""  && $one_net != {} } {
            switch -regexp -- $one_net {
                ^NC[0-9]|^nc[0-9]|^NC$|^nc$     {continue}
                ^X$|^x$                         {continue}
                VCC+|vcc+                        {continue}
                VDD+|vdd+                        {continue}
                VSS+|vss+                        {continue}
                GND+|gnd+                        {continue}
                default     {puts $one_net
                            PlaceOffPage [expr $wlen_start + 0.2 ] $y1 $lib_path OFFPAGELEFT-R $one_net}
            }
            # move string of out off page automatically
            set diff_strlen [expr abs($base_strlen - $max_strlen) / 10.0]
            if {$base_strlen > $max_strlen} {
                capMoveMouseAndClick [expr $wlen_start - 0.5] [expr $i / 10.0 + 0.4]
                Move [expr $wlen_start - 1.6 + $diff_strlen * 0.75 - $diff_strlen / 10.0] \
                     [expr $i / 10.0 - 0.1 * $i -0.01] 1
            } else {
                capMoveMouseAndClick [expr $wlen_start - 0.5] [expr $i / 10.0 + 0.4]
                Move [expr $wlen_start - 1.5 - $diff_strlen * 0.68 + $diff_strlen / 10.0] \
                     [expr $i / 10.0 - 0.1 * $i -0.01] 1
            }
        }
    }
    SelectBlock [expr $wlen_end + 0.1] 0.4 [expr $wlen_start - 0.1] \
                [expr [llength $netnames] / 10.0 + 0.5] 1
    Cut
}

proc gs {} {
    set lStatus [DboState]
    set lSelObjs [GetSelectedObjects]
    set lPinnames {}
    foreach lObj $lSelObjs {
        set lPropNameCStr [DboTclHelper_sMakeCString "Name"]
        $lObj GetPinName $lPropNameCStr
        lappend lPinnames [DboTclHelper_sGetConstCharPtr $lPropNameCStr]

        # get pin position
        # puts [$lObj GetPinPosition $lStatus]

        # get pin number
        # $lObj GetPinNumber $lPropNameCStr
        # puts [DboTclHelper_sGetConstCharPtr $lPropNameCStr]
    }
    puts "\n\n"
    puts $lPinnames
    puts "\n\n"
}

proc gf {} {
    set lStatus [DboState]
    set lSelObjs [GetSelectedObjects]
    set lPinnames {}
    foreach lObj $lSelObjs {
        set lPropNameCStr [DboTclHelper_sMakeCString "Name"]
        $lObj GetPinName $lPropNameCStr
        lappend lPinnames [DboTclHelper_sGetConstCharPtr $lPropNameCStr]
    }
    puts "\n\n"
    puts $lPinnames
    puts "\n\n"
    cf $lPinnames
}

# display help information
proc dh {} {
    puts "ra  : run all commands of this tcl script"
    puts "gs  : get pin names of selected pins"
    puts "gf  : gs + cf"
    puts "ca  : customize method of placing array alias and wires"
    puts "ia  : customize method of placing array in/left off page"
    puts "oa  : customize method of placing array out/right off page"
    puts "cf  : customize method of placing different alias and wires"
    puts "idf : customize method of placing different in/left off page"
    puts "odf : customize method of placing different out/right off page"
    puts "fn  : find net name"
    puts "fp  : find pin name"
    puts "rn  : replace net name of all pages"
    puts "en  : exchange net name of all pages"
    puts "ed  : edit this tcl script using sublime text"
    puts "ds  : display script directory"
    puts "dh  : display commands information"
}

set THS5615_nets {
    D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 NC NC NC NC CLK DVDD
    DGND MODE AVDD COMP2 IOUT1 IOUT2 AGND COMP1 BIASJ EXTIO EXTLO SLEEP
}

set GL827L_nets {
    GPIO1 PMOSO DVDD X1 X2 GND AVDD DP DM RREF DVDD VP5
    EXTRSTZ SD_WP GPIO0 GPIO3 MS_INS D2 D3 D4 SD_CMD D5 SD_CLK D6 D7 D0 D1 SD_CDZ
}

set CS4344_nets {
    SDIN SCLK LRCK MCLK VQ AOUTR VA GND AOUTL FILT
}

set SST39VF6401_TSOP48_nets {
    A15 A14 A13 A12 A11 A10 A9 A8 A19 A20 WEN RSTN A21
    WPN NC A18 A17 A7 A6 A5 A4 A3 A2 A1 A0 CEN VSS OEN
    DQ0 DQ8 DQ1 DQ9 DQ2 DQ10 DQ3 DQ11 VDD DQ4 DQ12 DQ5
    DQ13 DQ6 DQ14 DQ7 DQ15 VSS NC A16
}

set RGB888_nets {
    CLK HS VS DE
    R0 R1 R2 R3 R4 R5 R6 R7
    G0 G1 G2 G3 G4 G5 G6 G7
    B0 B1 B2 B3 B4 B5 B6 B7
}

set LM2853_nets {
    AVIN EN SGND SS NC PVIN PVIN SW SW PGND PGND NC NC SNS EP
}

set MT47H256M8_nets {
    VDD VDD VDD VDD VDDL VDDQ VDDQ VDDQ VDDQ VDDQ X VREF X
    DQSN DQS RDQS X DQ0 DQ1 DQ2 DQ3 DQ4 DQ5 DQ6 DQ7  
}

################ all available net names ###################
# CS4344_nets custom_nets
# GL827L_nets
# LM2853_nets
# MT47H256M8_nets
# RGB888_nets
# THS5615_nets
# SST39VF6401_TSOP48_nets
############################################################

set custom_nets {
    VREF X DQSN DQS RDQS X DQ0 DQ1 DQ2 DQ3 DQ4 DQ5 DQ6 DQ7
}

# cf $custom_nets
# idf $custom_nets
# odf $custom_nets

1 0