简介

我写了个基于tcl的Verilog自动例化脚本,我自己做了个简单测试,OK的,在这里分享出来,兄弟们如果遇到什么BUG,欢迎留言评论区,或者联系QQ:3203326964,代码如下:

#!/usr/bin/env tclsh

####----------------------------------------
##  This is 3rd version , called "cc.tcl"
##  aa.tcl # 25/08/31 initial version
##  bb.tcl # 25/10/13 change index of del comment
##  cc.tcl # 25/10/21 release
##
####----------------------------------------

#output tcl version
puts "Tcl version : $tcl_version ;"

#check add_param num = 1
if {$argc != 1} {
    puts "linux cmd: tclsh $argv0 <verilog file>"
    exit 1
}

set filename [lindex $argv 0]
#puts "Input verilog file\t:\t$filename"

set inst_filename $filename\_inst.txt
#puts "Output inst file\t:\t$inst_filename"

if {[file exists $inst_filename]} {
    file delete $inst_filename
}

#check the verilog exit
if {![file exists $filename]} {
    puts "Error: the $filename no exists"
    exit 1
}



# get file extension
set ext [file extension $filename]

#check the ext is .v or .sv ?
if {$ext ni {.v .sv}} {
    puts "Error : input file error !"
    puts "Such as : tclsh $argv0 <verilog file>"
    exit 1
}

#get content of verilog file 
set filpd [open $filename r]
set filecon [read $filpd]
close $filpd
#puts $filecon

#set str "[puts "Input verilog file\t:\t$filename"][puts "Output inst file\t:\t$inst_filename"]"
#puts $str
#set new [string map {\t "    "} $str]
#puts $new
#get 4 * a
#puts [string repeat "a" $tabsize]
#puts [string length $filename]

#the 25 could limit space

####----------------------------------------
##  proc ALL
####----------------------------------------
proc div_ceil_4 {n} {
    return [expr {($n+3) / 4}]
}
proc indent_text {text spaces} {
    set indent [string repeat " " $spaces]
    set lines [split $text "\n"]
    set result {}
    foreach line $lines {
        lappend result "${indent}${line}"
    }
    return [join $result "\n"]
}
proc print_config {key value} {
    puts [format "%-20s: %s" $key $value]
}

print_config "Input verilog file" $filename
print_config "Output inst file" $inst_filename
print_config "Module name" "top_module"

####----------------------------------------
##  change $filecon to list
####----------------------------------------
set file_list [split $filecon "\n"]
#puts $file_list

####----------------------------------------
##  Because the last line is "\n",the llength add + 1
####----------------------------------------
set file_line_count [llength $file_list]
#puts $file_line_count

#set file_del1 [regsub -all {/\*.*?\*/} $filecon ""]
#puts $file_del1
#set file_del2 [regsub -all {//.*} $file_del1 ""]
#puts $file_del2

set test {}
foreach line [split $filecon "\n"] {
    set cle [regsub  {//.*} $line ""]
    lappend test $cle
}

set file_del1 [join $test "\n"]

set file_del2 [regsub -all {/\*.*?\*/} $file_del1 ""]


#puts $file_del2
####----------------------------------------
##  ok del all comment
####----------------------------------------

####----------------------------------------
##  del all empty line
####----------------------------------------

##  del empty line
set file_deline1 [join [lsearch -all -inline -not -exact [split $file_del2 "\n"] ""] "\n"]
#puts $file_deline1

##  del no valid code line , eg : only tab
set lines {}
foreach line [split $file_deline1 "\n"] {
    if {[string trim $line] ne ""} {lappend lines $line}
}
set file_deline2 [join $lines "\n"]
#puts $file_deline2

####----------------------------------------
##  delay no use code
####----------------------------------------

set save 0
set object_tmp {}
foreach line [split $file_deline2 "\n"] {
    if {$save == 0 && [string match "module*" [string trim $line]]} {
        set save 1
    }
    if {$save == 1} {
        lappend object_tmp $line
    }
    if {$save == 1 && [regexp {\);$} [string trim $line]]} {
        #lappend new_b $line  ;# 先加上这一行
        break
    }
}

#set object [join $object_tmp "\n"] 
set object [string map {"\n" ""} [join $object_tmp "\n"]]
#puts $object

set modu_line [lindex [split $object ")"] 0]
#puts $modu_line

set para_en  0

set module_pos [string first "module" $modu_line]
#puts "module is $module_pos"
set para_pos [string first "#" $modu_line]
#puts "para is $para_pos"
if {$module_pos == -1} {
    #puts "no any key word \"module\""
    #puts "Error : please check"
    exit 1
} 
if {$para_pos > $module_pos} {
    #puts "para func enable"
    set para_en 1
    #puts $para_en
} else {
    #puts "para func no use"
    set para_en 0
}

set modu_line_1 [string map {"\n" ""} $modu_line]
#puts $modu_line_1

set kuoh [regexp -all -inline {\([^)]*\)} $object]

if {[llength $kuoh] >= 1} {
    set para_cont_tmp [string range [lindex $kuoh 0] 1 end-1]
    #puts "1 part : $para_cont_tmp"
}
if {[llength $kuoh] >= 2} {
    set io_cont_tmp [string range [lindex $kuoh 1] 1 end-1]
    #puts "2 part : $io_cont_tmp"
}

if {$para_en == 1 } {
    set para_cont $para_cont_tmp
    set io_cont $io_cont_tmp
} else {
    set para_cont 0
    set io_cont $para_cont_tmp
}

#puts "para cont : $para_cont"
#puts "io   cont : $io_cont"

####----------------------------------------
##  proc para cont
####----------------------------------------
set para_all_tmp {}
if {$para_en == 1} {
    foreach line [split $para_cont ","] {
        #puts "the cont : $line"
        set para_id [regexp {parameter\s+([^=]+)=} $line -> cont_temp]
        set cont [string trim $cont_temp]
        # There is space in $cont_temp , must del the space
        #puts "para : 00 $cont_temp 11" 
        #puts "para : 00 $cont 11"
        lappend para_all_tmp ".$cont\($cont\),"
    }
}

#puts "[ join $para_all_tmp "\n"]"

set para_all [ join $para_all_tmp "\n"]

set para_all_1 [split $para_all "\n"]

set para_all_last_line [lindex $para_all_1 end]

set para_all_last_line_1 [regsub {,$} $para_all_last_line ""]

set para_all_last [join [lreplace $para_all_1 end end $para_all_last_line_1] "\n"]
#puts $para_all_last

####----------------------------------------
##  proc io cont
####----------------------------------------
set io_all_tmp {}
foreach line [split $io_cont ","] {
    #puts "the cont : $line"
    if {[regexp {(input)} $line -> keyword]} {
        set io 0
        set io_dir "input"
        set key_pos [string first $keyword $line]
        set line_cont [string range $line $key_pos end]
        #puts "Now line : input $line_cont"
    } elseif {[regexp {(output)} $line -> keyword]} {
        set io 1
        set io_dir "output"
        set key_pos [string first $keyword $line]
        set line_cont [string range $line $key_pos end]
        #puts "Now line : output $line_cont"
    } elseif {[regexp {(inout)} $line -> keyword]} {
        set io 2
        set io_dir "inout"
        set key_pos [string first $keyword $line]
        set line_cont [string range $line $key_pos end]
        #puts "Now line : inout $line_cont"
    } else {
        set io 3
        #puts "jump"
    }
    if {[regexp {\[(\S+):(\S+)\]} $line_cont -> left right]} {
        set left_val $left
        set right_val $right
        #puts $left_val
        #puts $right_val
        if {[string is integer -strict $left_val] && [string is integer -strict $right_val] } {
            set io_width [expr {abs($right_val-$left_val)+1}]
            #puts "io width : $io_width"
        } else {
            set io_width "$left_val+1"
            #puts "io width : $io_width "
        }
    } else {
        set io_width 1
        #puts "io width : $io_width"
    }

    if {$io < 3} {
        set io_name [lindex $line_cont end]
        #puts "FINAL :$io_dir $io_name $io_width"
        lappend io_all_tmp ".$io_name\($io_name\),"
    }
    #puts $line_cont
    #set cleaned [regsub -all {\s*(input|output|wire|reg|\[\d+:\d+\])\s*} $line " "]
    #puts $cleaned
}

#puts "[ join $io_all_tmp "\n"]"

set io_all [ join $io_all_tmp "\n"]

set io_all_1 [split $io_all "\n"]

set io_all_last_line [lindex $io_all_1 end]

set io_all_last_line_1 [regsub {,$} $io_all_last_line ""]

set io_all_last [join [lreplace $io_all_1 end end $io_all_last_line_1] "\n"]
#puts $io_all_last

####----------------------------------------
##  Get module_name
####----------------------------------------
set module_name {}
if {[regexp {module\s+(\w+)} $modu_line match name]} {
    set module_name $name
} else {
    set module_name ""
}
puts $module_name



####----------------------------------------
##  open a new txt
####----------------------------------------

if {$para_en==1} {
    set new_inst_first_line "$module_name #("
} else {
    set new_inst_first_line "$module_name $module_name\_U0("
}

#puts "$new_inst_first_line"

set first_line_len [string length $new_inst_first_line]
#puts "$first_line_len"
set tab_num [div_ceil_4 $first_line_len]


#puts [indent_text $io_all_last 8]

set para_all_last_space [indent_text $para_all_last [expr {$tab_num * 4}]]
set io_all_last_space   [indent_text $io_all_last [expr {$tab_num * 4}]]

#puts $para_all_last_space
#puts $io_all_last_space

set current_time [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S"]

puts $current_time

set header_line "//Inst PASS: $current_time\n"


set new_filpd [open $inst_filename w]

puts -nonewline $new_filpd $header_line

puts -nonewline $new_filpd "\n"

if {$para_en==1} {
    puts -nonewline $new_filpd "$module_name #(\n"
    puts -nonewline $new_filpd $para_all_last_space
    puts -nonewline $new_filpd "\n"
    puts -nonewline $new_filpd "[string repeat " " [expr {$tab_num * 4}]])$module_name\_U0(\n"
} else {
    puts -nonewline $new_filpd "$module_name $module_name\_U0(\n"
}

puts -nonewline $new_filpd $io_all_last_space

puts -nonewline $new_filpd "\n);"

puts -nonewline $new_filpd "\n"
puts -nonewline $new_filpd "\n"

close $new_filpd

####----------------------------------------
##  check
####----------------------------------------
set modu_key "module"

if {[string first $modu_key $file_del2] != -1} {
    puts "## module exists"
} else {
    puts "## Warning : module no exists"
    exit 1
}

exit 1
# wmware_EDA_ALL

代码运行方式

首先将该文件保存在任意文件夹下,命名为ai.tcl(此文件原则上可以随意命名,此处只作示范),然后在当前文件夹运行即可,运行方式如下图

关于在Windows中的使用

这个需要在Windows安装tcl环境,tcl环境安装就绪后,使用方式如之前所述,唯一需要注意的就是,需要在保存tcl文件的当前文件夹打开CMD,然后在CMD中使用该命令即可

关于linux和Windows中快捷方式的建立

linux中需要在.bashrc中添加以下命令,然后source .bashrc

注意:一定要确保tcl文件在该文件夹内

Windows中需要先新建一个ai.txt文件,输入文件内容如下

然后将ai.txt的后缀改为bat,最后该文件就成了ai.bat,最后将ai.bat的路径添加进环境变量即可

最终使用

linux中,直接在任意有Verilog文件的terminal输入ai xxxx.v

Windows中,直接在任意有Verilog文件的CMD输入ai xxxx.v

大功告成

更多推荐