verilog自动例化脚本(tcl 版本)
·
简介
我写了个基于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
大功告成
更多推荐



所有评论(0)