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:
- Generate a time stamp
- Read a version control software revision number. This example uses SVN.
- Increment a number stored in an HDL file
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