Quartus® II Tcl 示例:自动版本号

在 FPGA 设计中嵌入版本号或时间戳是很有用的。版本号或时间戳可避免当前在 FPGA 中编程的设计版本混淆不清。版本号必须在设计编译流程中自动更新才能发挥作用。此外,版本号必须存储在设计硬件中,例如内存或寄存器库中。

此 Tcl 示例介绍了生成版本号或时间戳的不同方法,以及将其存储在设计中的不同方法。它还展示了一个可用于创建 Tcl 脚本的脚本框架,此脚本可在每次编译设计时自动生成并存储版本号。最后,它展示了一个完整脚本的示例。

获取版本号

以下列表展示了如何生成版本号:

存储版本号

除了获取版本号之外,还必须将其写入设计文件。以下是如何存储版本号的示例:

脚本框架

可以根据设计流程将获取和保存版本号的方法合并在一起。从上面的示例中,选择获取版本号的方法和存储版本号的方法。将相应的程序复制到 Tcl 文件,并添加调用程序的命令。以下脚本框架展示了如何编写脚本。最后,将如下所示的赋值添加到 Quartus II 设置文件 (.qsf) 中,使脚本自动运行。

# 在此处插入获取版本号的程序 # 在此处插入存储版本号的程序 # 此行容纳脚本自动化,如下所示 foreach { flow project revision } $quartus(args) { break } # 在此处调用获取版本号的程序 # 进行任何必要的版本号格式转换 # 在此处调用存储版本号的程序

脚本自动化

将以下行添加到项目的 QSF 中,使脚本在每次编译之前自动运行。用 Tcl 文件名替换 <script name>。

set_global_assignment -name PRE_FLOW_SCRIPT_FILE quartus_sh:<script name>

有关赋值和自动运行脚本的其它方法的详细信息,请参阅“脚本自动执行”

示例

以下脚本示例使用以下两个示例中的程序:

# 获取指定文件的 SVN 修订号 proc get_subversion_revision { file_name } { global done # 等待完成 svn info 命令的 # 最大秒数 set timeout_seconds 30 # 包含已运行文件的文件名的 svn info 命令 set cmd "svn info ${file_name}" # 尝试获取版本信息。 # 如果无法运行此命令,则返回错误。 # 否则,设置一个处理命令输出的文件事件。 if { [catch {open "|$cmd"} input] } { return -code error $input } else { fileevent $input readable [list get_revision_info $input ] # 设置超时,使存储库停止运行时此程序 # 无法挂起。 set timeout [after [ expr { $timeout_seconds * 1000 } ] [list set done -1] ] # 找到修订号或操作超时时 # 再继续。无论哪种情况,取消超时。 vwait done after cancel $timeout } } # 以上程序的帮助器程序 proc get_revision_info { inp } { global done revision_number if { [eof $inp] } { catch {close $inp} set done 1 } elseif { $done } { gets $inp line } else { gets $inp line # 使用正则表达式匹配修订号 # 所在的行。 if { [regexp {^Revision:\s+(\d+)\s*$} $line match revision_number] } { set done 1 } } } # 在包含指定十六进制值的 Verilog 文件中创建一个寄存器库 proc generate_verilog { hex_value } { set num_digits [string length $hex_value] set bit_width [expr { 4 * $num_digits } ] set high_index [expr { $bit_width - 1 } ] set reset_value [string repeat "0" $num_digits] if { [catch { set fh [open "version_reg.v" w ] puts $fh "module version_reg (clock, reset, data_out);" puts $fh " input clock;" puts $fh " input reset;" puts $fh " output \[$high_index:0\] data_out;" puts $fh " reg \[$high_index:0\] data_out;" puts $fh " always @ (posedge clock or negedge reset) begin" puts $fh " if (!reset)" puts $fh " data_out <= ${bit_width}'h${reset_value};" puts $fh " else" puts $fh " data_out <= ${bit_width}'h${hex_value};" puts $fh " end" puts $fh "endmodule" close $fh } res ] } { return -code error $res } else { return 1 } } # 此行容纳脚本自动化 foreach { flow project revision } $quartus(args) { break } set file_name ${project}.qpf set done 0 set revision_number "" # 调用获取文件修订号的程序,并处理任何错误 if { [catch { get_subversion_revision $file_name } msg] } { post_message -type critical_warning "Couldn't run command to get revision number. $msg" } else { if { -1 == $done } { post_message -type critical_warning "Timeout getting revision number." } elseif {[string equal "" $revision_number] } { post_message -type critical_warning "Couldn't find revision number in output of svn info $file_name." } else { # 调用存储版本号的程序 if { [catch { generate_verilog $revision_number } res] } { post_message -type critical_warning \ "Couldn't generate Verilog file. $res" } else { post_message "Successfully updated version number to\ version 0x${revision_number}" } } }

如果将脚本命名为 update_version.tcl,必须将以下行添加到 QSF 中:

set_global_assignment -name PRE_FLOW_SCRIPT_FILE quartus_sh:update_version.tcl