Developing design: moving average filter. Part 6 – reading and writing to the files.

I had a break in developing filter (last part is here), but before doing next steps, I had to make a short introduction to working with files in VHDL. You can read about it herehere and here. Now I am going to use that knowledge and move on with the filter. In the last part I implemented the filter in Octave, generated test vectors, sent them through the filter and wrote all data to files.

Now it is time to start building testbench, where the filter could be easily and automatically verified with different test vectors. To achieve it, testbench has to read data from a file and pass it to the filter and then, write output values from the filter to another file.

Reading

New value should be read every clock cycle and only when the filter is enabled. Width of data from the file should correspond to width of data in the filter. Below is shown block which reads data from the file and meets all mentioned requirements.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
library ieee;
use ieee.std_logic_1164.all;
use std.textio.all;
 
entity ReadDataFromFile is
   generic (
      G_FILE_NAME          :string  := "DataIn.dat";
      G_DATA_W             :integer := 16
   );
   port (
      clk                  :in std_logic;
      en                   :in std_logic;
      o_data_en            :out std_logic;
      ov_data              :out std_logic_vector(G_DATA_W-1 downto 0);      
      o_eof                :out std_logic
  );
end ReadDataFromFile;

architecture ReadDataFromFile_rtl of ReadDataFromFile is
  
   file fptr: text;
   
begin

GetData_proc: process

   variable file_line      :line;
   variable varstd_data    :std_logic_vector(G_DATA_W-1 downto 0); 
   
begin                                       
   
   o_data_en   <= '0';
   ov_data     <= (others => '0');
   o_eof       <= '0';
   
   file_open(fptr, G_FILE_NAME, read_mode);
   
   while (not endfile(fptr)) loop      
      wait until clk = '1';
      if en = '1' then
         readline(fptr, file_line);
         hread(file_line, varstd_data);
         ov_data     <= varstd_data;
         o_data_en   <= '1';
      else
         ov_data     <= (others => '0');
         o_data_en   <= '0';
      end if;      
   end loop;
   wait until rising_edge(clk);
   o_data_en   <= '0';
   o_eof       <= '1';   
   file_close(fptr);
   wait;
end process;
end ReadDataFromFile_rtl;

I think, the code is self-explanatory, but I will give some notes:

  • DataIn.dat – file with input test vector – generation is described in previous part
  • o_data_en – indicates if data is valid
  • ov_data – data from the file
  • o_eof – end of file, indicates end of reading from the file

Writing

Data should be written to the file, only when filter is on and has active data on its output port. Below is block which does do the job.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
library ieee;
use ieee.std_logic_1164.all;
use std.textio.all;

 
entity WriteDataToFile is
   generic (
      G_FILE_NAME          :string  := "DataOut.dat";
      G_DATA_W             :integer := 16
   );
   port (
      clk                  :in std_logic;
      en                   :in std_logic;
      iv_data              :in std_logic_vector(G_DATA_W-1 downto 0);
      i_eod                :in std_logic;
      o_eof                :out std_logic
  );
end WriteDataToFile;

architecture WriteDataToFile_rtl of WriteDataToFile is
  
   file fptr: text;
   
begin

GetData_proc: process

   variable file_line      :line;
   variable varint_data    :string(1 to 4);
   
begin                                       
   
   o_eof    <= '0';
   
   file_open(fptr, G_FILE_NAME, write_mode);
   
   while i_eod = '0' loop
      wait until clk = '1';
      if en = '1' then
         hwrite(file_line, iv_data);
         writeline(fptr, file_line);      
      end if;
   end loop;
   
   wait until clk = '1';   
   o_eof <= '1';
   file_close(fptr);
   wait;
end process;
end WriteDataToFile_rtl;

 

Notes:

  • DataOut.dat – file with output data from the filter
  • i_eod – indicates end of tests
  • o_eof – end of file, indicates end of writing to the file

***

Values in the files I keep in hexadecimal system, so I used here functions hread, hwrite which are available in standard vhdl-2008. Remember to use that version of language in you simulator.

*** *** ***

All source codes used in that post you can find on gitlab.com.

*** *** ***

Leave a comment