Dear All,
i have managed to make a working solution for the version control using CVS. This info is for those who are interested in a similar thing. The source as well as ideas are compiled of many sources, including hints from this thread.
So, short howto:
1) when using CVS to store your project, store the POF (programmer object file) as well. We use POF file as an identification of the revision of the project. CVS does not have (imho) a revision number for module. POF file is a good choice because every time you make an update to source file, quartus generates unique POF for this vhdl-file-set. One can use SOF as well, but imho putting both SOF and POF into CVS does not bring any added value.
2) setup CVS connection to your CVS server by using automatic SSH authentication (public/private keys)
3) put this script into either project directory or somewhere where you store VHDL files. The system visibility is not necessary because you'll call it from quartus by relative calls anyways. Script is here:
get_revision.tcl:
======================================================
# !/usr/bin/tclsh
# note: in order to be sure that code is fine, file_name should be a sram object file
# or program object file. These must be of course imported to CVS!
# Comments? Bug reports? email: david.belohrad@cern.ch
package require cmdline
proc get_cvs_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 "cvs log ${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 { } {
return -code error $input
} else {
fileevent $input readable
# Set up a timeout so that the process can't hang if the
# repository is down.
set timeout
]
# Don't continue until the revision number is found,
# or the operation times out. Cancel the timeout anyway.
vwait done
after cancel $timeout
}
}
proc get_revision_info { inp } {
global done magic_number
if { } {
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. The revision number up to fourh number is
# supported
if { } {
set record
# for loop to get integer:
set magic_number 0
set recordno 3
foreach pt $record {
set mtemp ]
# cannot be higher revision number because we would run out of ULONG type:
if {$mtemp > 255} {
set mtemp 255
}
set con
set magic_number
set recordno
}
}
}
}
proc create_entity { filename } {
global magic_number
# this script generates an entity with given revision number
set fi
puts $fi "library ieee;"
puts $fi "use ieee.std_logic_1164.all;"
puts $fi "use ieee.numeric_std.all;"
puts $fi "entity fw_revision is"
puts $fi "port ("
puts $fi "\trevision : out std_logic_vector(31 downto 0));"
puts $fi "end entity fw_revision;\n"
puts $fi "architecture v1 of fw_revision is"
puts $fi "begin -- architecture v1"
puts $fi "\trevision <= STD_LOGIC_VECTOR(TO_UNSIGNED($magic_number,revision'length));"
puts $fi "end architecture v1;"
close $fi
}
# note: if this file is run via quartus_sh, we get additional parameters
# on the command line. this is flowtype, project name and revision.
# as project name is corresponding to the .pof file generated, we can
# use this information to create our revision file:
set file_name
append file_name ".pof"
set project_name
set revision_name
post_message "get_revision.tcl: Getting revision for $file_name..."
# this filename is used to open the project, if not opened. The project
# needs to be opened because we need to know about project working directory.
if {} {
if {} {
project_open $project_name -revision
} else {
project_open $project_name -revision $revision_name
}
} else {
post_message -type error "Project $project_name does not exist"
exit
}
post_message "get_revision.tcl: project opened, project name: $project_name, revision: $revision_name"
set done 0
set magic_number 0
if { } {
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 { } {
post_message -type critical_warning
"Couldn't find revision number in output of cvs info $file_name."
} else {
post_message "Revision for $file_name is $magic_number (0x)"
# create new entity in sources/fwrevision directory
set prjfile
append prjfile "sources/fwrevision"
# we have full path, let's check whether it exists:
file mkdir $prjfile
# call procedure to make an entity:
append prjfile "/fw_revision.vhd"
puts "Creating $prjfile ..."
create_entity $prjfile
post_message "get_revision.tcl: done."
}
}
# close project:
if {
project_close
}
4) what the script does: the script must be called from quartus environment, the calling
parameters must be the same as of PRE_FLOW_SCRIPT_FILE, thus <flowtype> <projectname> <revisionname>. The script opens the project, creates a filename of the POF file corresponding to the project name, then calls CVS LOG command to find out the revisions of the POF file. By using regular expressions it extracts the 'HEAD' revision number. As CVS revision number is not a single number like in SVN, but it has at least one major and one minor release version (e.g. 1.32) we need to parse it somehow to get in VHDL decent information about version. The script supports the revision number up to 2 subbranches, thus maximum allowed revision number would be something like 1.32.2.3. Additional subbranches are lost. The revision number is converted to the unsigned long number of type 0xMMIIBBSS, where M=major number, I=minor number, B = branch, S = subbranch. If B and/or S are not used, zero is filled. Such LONG revision number is put into the entity called fw_revision. The entity exports single 32bit STD_LOGIC_VECTOR containing the value above. The entity is by default created in <projectdirectory>/sources/fwrevision/fw_revision.vhd. Note, that neither fwrevision directory nor fw_revision.vhd file must be imported into CVS. When you check out plain VHDL code, the directory and file inside must not exist.
5) the entity generated looks like:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity fw_revision is
port (
revision : out std_logic_vector(31 downto 0));
end entity fw_revision;
architecture v1 of fw_revision is
begin -- architecture v1
revision <= STD_LOGIC_VECTOR(TO_UNSIGNED(16973824,revision'length));
end architecture v1;
where the number 12973824 (0x01030000) corresponds to CVS revision 1.3 of POF file.
6) in order to make it automatically called from within quartus you have to put following sentence
into your QSF file:
# automatic script run to get every time a revision:
set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:../cfga_vhdl/get_revision.tcl"
where ../cfga_vhdl is a relative path of the get_revision.tcl script with respect to the project directory
-------------
Hope this helps to someone else as well.
d.