It is useful to have a version number or time stamp embedded in your FPGA design. A version number or time stamp eliminates any confusion about which version of your design is currently programmed in the FPGA. For such a number to be useful, it must be updated automatically in the design compilation flow. Also, the number must be stored in the design hardware, such as in memory or a bank of registers.
This Tcl example describes different ways to generate a version number or time stamp, as well as different ways to store it in a design. Then, it shows a script framework you can use to create a Tcl script that generates and stores the version number automatically, every time you compile a design. Finally, it shows an example of a complete script.
Get a Number
The following list shows how you can generate a version number:
Store the Number
In addition to getting the number, you must write it in a design file. The following are examples of how to store the number:
Script Framework
You can combine methods for getting and saving a number to suit your design flow. From the examples above, choose a method to get a number and a method to store the number. Copy the appropriate procedures to a Tcl file and add commands to call the procedures. The following script framework shows how your script should be written. Finally, add an assignment (described below) to your Quartus II Settings File (.qsf ) to allow the script to run automatically.
# Insert procedure to get a number here # Insert procedure to store the number here # This line accommodates script automation, described later foreach { flow project revision } $quartus(args) { break } # Call procedure to get a number here # Do any number format conversion necessary # Call procedure to store the number here
Script Automation
Add the following line to your project's QSF to allow the script to run automatically before every compilation. Replace <script name > with the name of your Tcl file.
set_global_assignment -name PRE_FLOW_SCRIPT_FILE quartus_sh:<script name>
Refer to Automatic Script Execution for more information about the assignment and other ways to automatically run scripts.
Example
The following script example uses procedures from the following two examples:
- Get a number: read a version control software revision number
- Store the number: Verilog file with a bank of registers
# Gets SVN revision number for the specified file proc get_subversion_revision { file_name } { global done # The maximum number of seconds to wait for the svn info # command to complete set timeout_seconds 30 # The svn info command with filename that is run set cmd "svn info ${file_name}" # Attempt to get the version information. # If the command can't be run, return an error. # Otherwise set up a file event to process the command output. if { [catch {open "|$cmd"} input] } { return -code error $input } else { fileevent $input readable [list get_revision_info $input ] # Set up a timeout so that the process can't hang if the # repository is down. set timeout [after [ expr { $timeout_seconds * 1000 } ] [list set done -1] ] # Don't continue until the revision number is found, # or the operation times out. Cancel the timeout anyway. vwait done after cancel $timeout } } # Helper procedure for the above procedure 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 # Use a regular expression to match the line with the # revision number. if { [regexp {^Revision:\s+(\d+)\s*$} $line match revision_number] } { set done 1 } } } # Creates a register bank in a verilog file with the specified hex value 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 } } # This line accommodates script automation foreach { flow project revision } $quartus(args) { break } set file_name ${project}.qpf set done 0 set revision_number "" # Call procedure to get file revision number and handle any errors 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 { # Call procedure to store the number 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}" } } }
If you name the script update_version.tcl, you must add the following line to your QSF:
set_global_assignment -name PRE_FLOW_SCRIPT_FILE quartus_sh:update_version.tcl