10

Can I uses in VHDL something similar to the C-Sourcecode-Macros __DATE__ and __TIME__ to make the compile time available in the FPGA as a kind of version time stamp?

As a >>>new-comer<<< to VHDL I want to modify the following existing code, which puts a hard coded date into a FPGA register. I always have to remember adjusting the values before compiling. It would be easier if this is done automatically. Can I also include hours/minutes/seconds?

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;

ENTITY Datum2 IS
   PORT
   (
        Day         :OUT std_logic_vector(4 downto 0);
        Month       :OUT std_logic_vector(3 downto 0);
        Year        :OUT std_logic_vector(4 downto 0)
   );
END Datum2 ;

ARCHITECTURE rtl OF Datum2 IS

BEGIN
--  "08.08.0013"
    Day   <= conv_std_logic_vector(8, 5);
    Month <= conv_std_logic_vector(8, 4);
    Year  <= conv_std_logic_vector(13, 5);
END ARCHITECTURE rtl;
Helmholtz42
  • 185
  • 5
  • 10

3 Answers3

17

Current date and time is not directly available in VHDL, but solution is suggested below.

EDITED 2013-08-10: Added description for Altera Quartus II Tcl automatic generation.

One way to make date and time available is through an automatically generated VHDL package like the below:

library ieee;
use ieee.std_logic_1164.all;

package datetime is
  -- Date information
  constant YEAR_INT  : integer                       := 2013;
  constant YEAR_HEX  : std_logic_vector(15 downto 0) := X"2013";
  constant MONTH_INT : integer                       := 08;
  constant MONTH_HEX : std_logic_vector(7 downto 0)  := X"08";
  constant DAY_INT   : integer                       := 09;
  constant DAY_HEX   : std_logic_vector(7 downto 0)  := X"09";
  constant DATE_HEX  : std_logic_vector(31 downto 0) := YEAR_HEX & MONTH_HEX & DAY_HEX;
  -- Time information
  constant HOUR_INT   : integer                       := 13;
  constant HOUR_HEX   : std_logic_vector(7 downto 0)  := X"13";
  constant MINUTE_INT : integer                       := 06;
  constant MINUTE_HEX : std_logic_vector(7 downto 0)  := X"06";
  constant SECOND_INT : integer                       := 29;
  constant SECOND_HEX : std_logic_vector(7 downto 0)  := X"29";
  constant TIME_HEX   : std_logic_vector(31 downto 0) := X"00" & HOUR_HEX & MINUTE_HEX & SECOND_HEX;
  -- Miscellaneous information
  constant EPOCH_INT  : integer := 1376046389;  -- Seconds since 1970-01-01_00:00:00
end package;

This VHDL package can be created with a Tcl script like this:

# Make datetime.vhd package from Tcl script

# Current date, time, and seconds since epoch
# Array index                                            0  1  2  3  4  5  6
set datetime_arr [clock format [clock seconds] -format {%Y %m %d %H %M %S %s}]

# Write VHDL package
set filename datetime.vhd
set file [open $filename w]
puts $file "library ieee;"
puts $file "use ieee.std_logic_1164.all;"
puts $file ""
puts $file "package datetime is"
puts $file "  -- Date information"
puts $file "  constant YEAR_INT  : integer                       := [lindex $datetime_arr 0];"
puts $file "  constant YEAR_HEX  : std_logic_vector(15 downto 0) := X\"[lindex $datetime_arr 0]\";"
puts $file "  constant MONTH_INT : integer                       := [lindex $datetime_arr 1];"
puts $file "  constant MONTH_HEX : std_logic_vector(7 downto 0)  := X\"[lindex $datetime_arr 1]\";"
puts $file "  constant DAY_INT   : integer                       := [lindex $datetime_arr 2];"
puts $file "  constant DAY_HEX   : std_logic_vector(7 downto 0)  := X\"[lindex $datetime_arr 2]\";"
puts $file "  constant DATE_HEX  : std_logic_vector(31 downto 0) := YEAR_HEX & MONTH_HEX & DAY_HEX;"
puts $file "  -- Time information"
puts $file "  constant HOUR_INT   : integer                       := [lindex $datetime_arr 3];"
puts $file "  constant HOUR_HEX   : std_logic_vector(7 downto 0)  := X\"[lindex $datetime_arr 3]\";"
puts $file "  constant MINUTE_INT : integer                       := [lindex $datetime_arr 4];"
puts $file "  constant MINUTE_HEX : std_logic_vector(7 downto 0)  := X\"[lindex $datetime_arr 4]\";"
puts $file "  constant SECOND_INT : integer                       := [lindex $datetime_arr 5];"
puts $file "  constant SECOND_HEX : std_logic_vector(7 downto 0)  := X\"[lindex $datetime_arr 5]\";"
puts $file "  constant TIME_HEX   : std_logic_vector(31 downto 0) := X\"00\" & HOUR_HEX & MINUTE_HEX & SECOND_HEX;"
puts $file "  -- Miscellaneous information"
puts $file "  constant EPOCH_INT  : integer := [lindex $datetime_arr 6];  -- Seconds since 1970-01-01_00:00:00"
puts $file "end package;"
close $file

In Altera Quartus II it is possible to make the flow run this script before synthesis, whereby the datetime package can be created. This is done in the .qsf file with the line below, where the script is named "make_datetime.tcl":

set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:make_datetime.tcl"

Further description of this Quartus II feature can be found in Quartus II Tcl Example: Automatic Script Execution.

The Datum2 module can then use the package like this:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity Datum2 is
  port(
    Day   : out std_logic_vector(4 downto 0);
    Month : out std_logic_vector(3 downto 0);
    Year  : out std_logic_vector(4 downto 0));
end Datum2;


library work;
use work.datetime;

architecture rtl of Datum2 is
begin
  Day   <= conv_std_logic_vector(datetime.day_int, 5);
  Month <= conv_std_logic_vector(datetime.month_int, 4);
  Year  <= conv_std_logic_vector(datetime.year_int mod 100, 5);
end architecture rtl;

After synthesis in Quartus II the RTL viewer shows the module outputs as below:

enter image description here

Previously described alternative solutions are to create the VHDL package with a Bash script like this:

# Make datetime.vhd package from shell script

# Current date, time, and seconds since epoch
# Array index           0  1  2  3  4  5  6
datetime_arr=($(date +"%Y %m %d %H %M %S %s"))

# Write VHDL package
filename="datetime.vhd"
echo "library ieee;" > $filename
echo "use ieee.std_logic_1164.all;" >> $filename
echo "" >> $filename
echo "package datetime is" >> $filename
echo "  -- Date information" >> $filename
echo "  constant YEAR_INT  : integer                       := ${datetime_arr[0]};" >> $filename
echo "  constant YEAR_HEX  : std_logic_vector(15 downto 0) := X\"${datetime_arr[0]}\";" >> $filename
echo "  constant MONTH_INT : integer                       := ${datetime_arr[1]};" >> $filename
echo "  constant MONTH_HEX : std_logic_vector(7 downto 0)  := X\"${datetime_arr[1]}\";" >> $filename
echo "  constant DAY_INT   : integer                       := ${datetime_arr[2]};" >> $filename
echo "  constant DAY_HEX   : std_logic_vector(7 downto 0)  := X\"${datetime_arr[2]}\";" >> $filename
echo "  constant DATE_HEX  : std_logic_vector(31 downto 0) := YEAR_HEX & MONTH_HEX & DAY_HEX;" >> $filename
echo "  -- Time information" >> $filename
echo "  constant HOUR_INT   : integer                       := ${datetime_arr[3]};" >> $filename
echo "  constant HOUR_HEX   : std_logic_vector(7 downto 0)  := X\"${datetime_arr[3]}\";" >> $filename
echo "  constant MINUTE_INT : integer                       := ${datetime_arr[4]};" >> $filename
echo "  constant MINUTE_HEX : std_logic_vector(7 downto 0)  := X\"${datetime_arr[4]}\";" >> $filename
echo "  constant SECOND_INT : integer                       := ${datetime_arr[5]};" >> $filename
echo "  constant SECOND_HEX : std_logic_vector(7 downto 0)  := X\"${datetime_arr[5]}\";" >> $filename
echo "  constant TIME_HEX   : std_logic_vector(31 downto 0) := X\"00\" & HOUR_HEX & MINUTE_HEX & SECOND_HEX;" >> $filename
echo "  -- Miscellaneous information" >> $filename
echo "  constant EPOCH_INT  : integer := ${datetime_arr[6]};  -- Seconds since 1970-01-01_00:00:00" >> $filename
echo "end package;" >> $filename

For platform independence then a Python 3.x script like this may be used:

# Make datetime.vhd package from Python 3.x script

# Get date and time
import datetime
import time
now = datetime.datetime.now()
now_epoch_sec = int(time.time())

# Write VHDL package
file = open('datetime.vhd', 'wt')
file.write('library ieee;\n')
file.write('use ieee.std_logic_1164.all;\n')
file.write('\n')
file.write('package datetime is\n')
file.write('  -- Date information\n')
file.write('  constant YEAR_INT  : integer                       := {};\n'.format(now.strftime('%Y')))
file.write('  constant YEAR_HEX  : std_logic_vector(15 downto 0) := X\"{}\";\n'.format(now.strftime('%Y')))
file.write('  constant MONTH_INT : integer                       := {};\n'.format(now.strftime('%m')))
file.write('  constant MONTH_HEX : std_logic_vector(7 downto 0)  := X\"{}\";\n'.format(now.strftime('%m')))
file.write('  constant DAY_INT   : integer                       := {};\n'.format(now.strftime('%d')))
file.write('  constant DAY_HEX   : std_logic_vector(7 downto 0)  := X\"{}\";\n'.format(now.strftime('%d')))
file.write('  constant DATE_HEX  : std_logic_vector(31 downto 0) := YEAR_HEX & MONTH_HEX & DAY_HEX;\n')
file.write('  -- Time information\n')
file.write('  constant HOUR_INT   : integer                       := {};\n'.format(now.strftime('%H')))
file.write('  constant HOUR_HEX   : std_logic_vector(7 downto 0)  := X\"{}\";\n'.format(now.strftime('%H')))
file.write('  constant MINUTE_INT : integer                       := {};\n'.format(now.strftime('%M')))
file.write('  constant MINUTE_HEX : std_logic_vector(7 downto 0)  := X\"{}\";\n'.format(now.strftime('%M')))
file.write('  constant SECOND_INT : integer                       := {};\n'.format(now.strftime('%S')))
file.write('  constant SECOND_HEX : std_logic_vector(7 downto 0)  := X\"{}\";\n'.format(now.strftime('%S')))
file.write('  constant TIME_HEX   : std_logic_vector(31 downto 0) := X\"00\" & HOUR_HEX & MINUTE_HEX & SECOND_HEX;\n')
file.write('  -- Miscellaneous information\n')
file.write('  constant EPOCH_INT  : integer := {};  -- Seconds since 1970-01-01_00:00:00\n'.format(now_epoch_sec))
file.write('end package;\n')
file.close()

For presentation of date and time in 32-bit register values, a module can be like this:

library ieee;
use ieee.std_logic_1164.all;
entity tb is
end entity;

library work;
use work.datetime;
architecture sim of tb is
  signal date_hex : std_logic_vector(31 downto 0);
  signal time_hex : std_logic_vector(31 downto 0);
begin
  date_hex <= datetime.DATE_HEX;
  time_hex <= datetime.TIME_HEX;
  process is begin wait; end process;
end architecture;

Waveform shown below.

enter image description here

The Bash or Python script approach requires integration in the build flow for automatic package generation.

EDITED 2016-08-08 with update by Damien: Description of non-Tcl script call from Altera Quartus.

To integrate a bash script (under Linux), create a Tcl wrapper script which calls the bash script as part of the process. In this example, there is a "scripts" directory which has a "call_bash.tcl" script and a "make_datetime.sh" which does the actual work:

# Useful if the script is in a subdirectory
proc getScriptDirectory {} {
    set dispScriptFile [file normalize [info script]]
    set scriptFolder [file dirname $dispScriptFile]
    return $scriptFolder
}

set scriptDir [getScriptDirectory]

# Call the bash script which does the real work
exec $scriptDir/make_datetime_vhdl.sh

# Add a message the Altera workflow
post_message -type info "Created datetime.vhd"

Integrating into Altera's build flow can then be achieved by adding the following to the the qsf file:

set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:scripts/call_bash.tcl"
gyuunyuu
  • 526
  • 5
  • 17
Morten Zilmer
  • 15,586
  • 3
  • 30
  • 49
  • 1
    I do something similar, and put the subversion revision and date into a version register as part of automated build scripts. There are many ways to do this, but it generally boils down to having a non-VHDL process update a VHDL file that is used in the design with the specific meta-data you want included. – Charles Steinkuehler Aug 09 '13 at 12:23
  • And what's missing is the way of automating the process in the particular tool environment, from the tags: fpga altera, and nios. A proper response would appear to require someone using that environment. Also note the question centered on three bitfields Day std_logic_vector(4 downto 0), Month std_logic_vector(3 downto 0) and Year std_logic_vector(4 down to 0). Also some tool environments ( See http://www.doulos.com/knowhow/fpga/Setting_Generics_Parameters_for_Synthesis/) have the capability of setting parameters directly. –  Aug 10 '13 at 02:02
  • @David Koontz: Good point; I have updated the answer with an Altera Quartus II specific suggestion, which is integrated into the Quartus II flow for automatic run. – Morten Zilmer Aug 10 '13 at 11:49
  • Now that was thorough, informative and specifically helpful. As I understand it, it's also possible to call external programs (as in bash or python scripts) from a tcl script. –  Aug 10 '13 at 20:50
  • @David Koontz: Yes, but probably best to keep it in Tcl domain only, since this is available with Quartus II, independently on platform (Bash) and external programs (Python). – Morten Zilmer Aug 10 '13 at 21:06
  • @MortenZdk Currently the 1076 WG has a proposal for adding DATE and TIME information. Your participation in the form of comments or reformulation of this proposal or others would be appreciated. See: http://www.eda.org/twiki/bin/view.cgi/P1076/DateTime. I can arrange access to edit the TWIKI if you like. You can reach me through: http://www.eda.org/twiki/bin/view.cgi/P1076/WebHome – Jim Lewis Nov 13 '13 at 20:21
  • The only thing missing from the answer is how to integrate the bash/python script into the quartus build architecture. Other than that, the answer is very useful indeed. – Damien Aug 08 '16 at 05:43
  • @Damien: For integration into Quartus, I will suggest the Tcl script approach, also described above, since Quartus provides immediate hooks for Tcl integration, as described in the section "In Altera Quartus II it is possible..." above. – Morten Zilmer Aug 08 '16 at 07:05
  • @MortenZilmer: I've provided an example on how to integrate a bash script. It means I can leverage existing tools we have without having to re-write in tcl. Thanks! – Damien Aug 08 '16 at 08:40
  • @Damien: Thanks; I have accepted the edit and update with some note about change. Best regards. – Morten Zilmer Aug 08 '16 at 09:38
2

I use a 64-bit std_logic_vector constant.

I have a TCL script which runs just before synthesis to encode the current time into a constant in a package, which is then included in the FPGA so it can be read out in some fashion.

There's a non-autogenerated version of the same package which I use in simulations - this doesn't change, so I don't have to keep updating the tests.

Martin Thompson
  • 16,395
  • 1
  • 38
  • 56
1

You don't need to write out the full code every time the timestamp is update. In Quartus you can use TCL to set top-level generics prior to compilation:

Pass the generics down to you timestamp entity:

entity top is
generic (day, month, year : integer);
end entity top;

architecture struct of top is
begin
timestamp_inst : entity work.timestamp generic map(day, month, year);
end architecture struct;

And then use a preflow-script to set the generics:

set_parameter -name day $someday
set_parameter -name year $someyear
# etc

I've used this approach successfully with both timestamps, git revision, build ID. I find it convenient to convert it to a word array and then accessing as a ROM. Just use your imagination.

trondd
  • 878
  • 1
  • 7
  • 12