Using Files in VHDL

This example demonstrates the usage of files in VHDL. Files are useful to store vectors that might be used to stimulate or drive test benches. Additionally, the output results can be recorded to a file. Their behavior is similar to how files work in other programming languages such as C. Note that none of the file operator keywords described below produce synthesizable code.. They are only intended for use in simulation test benches.

The package file that needs to be included to make File IO work correctly is std.textio. This allows the usage of the keywords: file_open, file_close, read, readline, write, writeline, flush, endfile, and others. One issue to be aware of is that std.textio.all only allows for reading and writing of type bit, bit_vector_boolean, character, integer, real, string, and time. This package file does not allow for reading and writing std_logic_vector type to a file. To allow for this, include the package file: ieee.std_logic_textio.all at the top of your design.

This example uses a 1-bit full-adder at the lowest level. The next highest level creates what is known as a ripple-carry adder. The test bench creates stimulus for the ripple-carry adder to exercise the logic and store the results to a file. In order to compile this code correctly, all three source files need to be in the same directory and compiled into Library Work. See the Modelsim tutorial for beginners for detail. You also need the input_vectors.txt and output_results.txt files in the same directory.



Testbench Code:

-------------------------------------------------------------------------------
-- File Downloaded from http://www.nandland.com
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use STD.textio.all;
use ieee.std_logic_textio.all;

entity example_file_io_tb is

end example_file_io_tb;


architecture behave of example_file_io_tb is

  -----------------------------------------------------------------------------
  -- Declare the Component Under Test
  -----------------------------------------------------------------------------
  component module_ripple_carry_adder is
    generic (
      g_WIDTH : natural);
    port (
      i_add_term1 : in  std_logic_vector(g_WIDTH-1 downto 0);
      i_add_term2 : in  std_logic_vector(g_WIDTH-1 downto 0);
      o_result    : out std_logic_vector(g_WIDTH downto 0)
      );
  end component module_ripple_carry_adder;


  -----------------------------------------------------------------------------
  -- Testbench Internal Signals
  -----------------------------------------------------------------------------
  file file_VECTORS : text;
  file file_RESULTS : text;

  constant c_WIDTH : natural := 4;

  signal r_ADD_TERM1 : std_logic_vector(c_WIDTH-1 downto 0) := (others => '0');
  signal r_ADD_TERM2 : std_logic_vector(c_WIDTH-1 downto 0) := (others => '0');
  signal w_SUM       : std_logic_vector(c_WIDTH downto 0);
  
begin

  -----------------------------------------------------------------------------
  -- Instantiate and Map UUT
  -----------------------------------------------------------------------------
  MODULE_RIPPLE_CARRY_ADDER_INST : module_ripple_carry_adder
    generic map (
      g_WIDTH => c_WIDTH)
    port map (
      i_add_term1 => r_ADD_TERM1,
      i_add_term2 => r_ADD_TERM2,
      o_result    => w_SUM
      );


  ---------------------------------------------------------------------------
  -- This procedure reads the file input_vectors.txt which is located in the
  -- simulation project area.
  -- It will read the data in and send it to the ripple-adder component
  -- to perform the operations.  The result is written to the
  -- output_results.txt file, located in the same directory.
  ---------------------------------------------------------------------------
  process
    variable v_ILINE     : line;
    variable v_OLINE     : line;
    variable v_ADD_TERM1 : std_logic_vector(c_WIDTH-1 downto 0);
    variable v_ADD_TERM2 : std_logic_vector(c_WIDTH-1 downto 0);
    variable v_SPACE     : character;
    
  begin 

    file_open(file_VECTORS, "input_vectors.txt",  read_mode);
    file_open(file_RESULTS, "output_results.txt", write_mode);

    while not endfile(file_VECTORS) loop
      readline(file_VECTORS, v_ILINE);
      read(v_ILINE, v_ADD_TERM1);
      read(v_ILINE, v_SPACE);           -- read in the space character
      read(v_ILINE, v_ADD_TERM2);

      -- Pass the variable to a signal to allow the ripple-carry to use it
      r_ADD_TERM1 <= v_ADD_TERM1;
      r_ADD_TERM2 <= v_ADD_TERM2;

      wait for 60 ns;

      write(v_OLINE, w_SUM, right, c_WIDTH);
      writeline(file_RESULTS, v_OLINE);
    end loop;

    file_close(file_VECTORS);
    file_close(file_RESULTS);
    
    wait;
  end process;

end behave;

input_vectors.txt:

0000 0000
0000 0001
1000 1000
1111 1111

output_results.txt:

00000
00001
10000
11110

Modelsim simulation wave output

Learn Verilog

Modules

Learn VHDL