Writing to files can be useful in a VHDL simulation. This section will illustrate how to implement that with VHDL 93.
Here is the header of an example program:
        library ieee;
        use ieee.std_logic_1164.all;
        use std.textio.all;
        use work.txt_util.all;
        entity FILE_LOG is
          generic (
                   log_file:       string  := "res.log"
                  );
          port(
               CLK              : in std_logic;
               RST              : in std_logic;
               x1               : in std_logic;
               x2               : in std_logic_vector(7 downto 0)
              );
        end FILE_LOG;
For the purpose of this example two signals x1 and x2 shall be logged to a file on every rising clock edge.
To operate on files they need to be declared:
        architecture log_to_file of FILE_LOG is
              file l_file: TEXT open write_mode is log_file;
        begin
Here l_file is the file, it's of type TEXT and opened in write mode. The log_file parameter is of type string and usually assigned with a generic as shown above.
The following loop will log x1 and x2 into the file specified by log_file:
        while true loop
           write(l, str(x1)&" "& hstr(x2)& "h");
           writeline(l_file, l);
        end loop;
As can be seen VHDL writes to a file in two steps: first a string is written to a variable of type line (that's what the write command does), then the line is appended to a file with the writeline command.
In the example shown here x1 is of type std_logic and x2 of type std_logic_vector. The function str() will convert x1 in a string, the function hstr() will convert x2 in a string in hex format. (Both functions are in txt_util.vhd). Strings and characters can be combined into a larger string with the & operator.
The txt_util package provides a simpler way to write to a file, e.g. with:
        print(l_file, str(x1)& " "& hstr(x2)& "h"); 
Which fits into a single line and doesn't require a line type variable. Also since the input to print is always a string no type casting is necessary.
The usage can be illustrated by inserting the lines below in front of the while-loop. (The code will generate a header for the log file.)
        print(l_file, "#  x1   x2 ");
        print(l_file, "#----------");
        print(l_file, " ");
        wait until RST='1';
        wait until RST='0';
        while true loop
           . . .
If the waveforms shown below are applied to the entity:
Then the following will be the contents of res.log:
        #  x1   x2 
        #----------
         
        0 01h
        0 02h
        0 03h
        ...
        0 0Fh
        1 10h
        1 11h
        ...
 
Below are the files which have been simulated in this section: