VHDL-verification
Package to ease directed testing of HDL entities
datacompare.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 --! @file
3 --! @author Hipolito Guzman-Miranda
4 --! @brief Compares signals with expected values in file
5 -------------------------------------------------------------------------------
6 
7 --! Use IEEE standard definitions library
8 library ieee;
9 --! Use std_logic* signal types
10 use ieee.std_logic_1164.all;
11 --! Allows use of arithmetical operations between integers and vectors
12 use ieee.numeric_std.all;
13 -- Allows writing strings to lines and lines to files
14 use STD.textio.all;
15 -- Allows writing std_logic_vector(s) to line(s) in BIN, HEX, OCT and reading BIN, HEX, OCT vector(s) from line(s)
16 use ieee.std_logic_textio.all;
17 -- For print() function
18 use work.txt_util.all;
19 -- To use the slv2hexstring conversion function
20 use work.vhdl_verification.all;
21 
22 --! @brief Compares input data with values in file and reports errors
23 --!
24 --! @detailed Reads file at \c GOLD_OUTPUT_FILE, expecting \c GOLD_OUTPUT_NIBBLES chars in
25 --! each line. Data is expected in hex format: 4 bits per character (nibble).
26 --! Reads input \c data and internally reorders it so it can compare
27 --! accumulated data with a complete line in \c GOLD_OUTPUT_FILE outputs it with a
28 --! width of DATA_WIDTH bits. \c data is only sampled when \c valid is active. If
29 --! \c VERBOSE is \c true, will report both correct (OK) data with erroneous
30 --! (ERROR) data
31 entity datacompare is
32  generic(
33  SIMULATION_LABEL : string := "datacompare"; --! Allow to separate messages from different instances in SIMULATION
34  VERBOSE : boolean := false; --! Report correct data and not only erroneous data
35  DEBUG : boolean := false; --! Print debug info (developers only)
36  GOLD_OUTPUT_FILE : string := "../test/datacompare_test.txt"; --! File where data is stored
37  GOLD_OUTPUT_NIBBLES : integer := 2; --! Maximum hex chars for each output data
38  DATA_WIDTH : integer := 8; --! Width of inout data
39  ERROR_MARGIN : integer := 0 --! Comparison is ok if data differs by this value or less
40  );
41  port(
42  clk : in std_logic; --! Expects input data aligned to this clock
43  data : in std_logic_vector (DATA_WIDTH-1 downto 0); --! Data to compare with data in file
44  valid : in std_logic; --! Active high, indicates data is valid
45  endsim : in std_logic --! Active high, tells the process to close its open files
46  );
47 end datacompare;
48 
49 --! @brief Architecture accumulates input data in a vector and compares with contents of file lines
50 architecture data_comparison of datacompare is
51 
52  constant NUM_CHUNKS : integer := 4*GOLD_OUTPUT_NIBBLES / DATA_WIDTH; --! Each line in output file equals to NUM_CHUNKS data of DATA_WIDTH
53 
54  signal received_data : integer := 0;
55 
56  --! Define this outside the process so we can check endfile(gold_file_pointer) in a concurrent assertion
57  file gold_file_pointer : text;
58  shared variable gold_file_isopen : boolean := false; -- It would be nice if file types had an 'isopen attribute :(
59 
60 begin
61 
62  assert GOLD_OUTPUT_NIBBLES > 0
63  report "datacompare(" & SIMULATION_LABEL & "): GOLD_OUTPUT_NIBBLES must be a positive non-zero integer"
64  severity failure;
65 
66  assert DATA_WIDTH > 0
67  report "datacompare(" & SIMULATION_LABEL & "): DATA_WIDTH must be a positive non-zero integer"
68  severity failure;
69 
71  report "datacompare(" & SIMULATION_LABEL & "): DATA_WIDTH (" & integer'image(DATA_WIDTH) & ") bits must fit into GOLD_OUTPUT_NIBBLES nibbles (4*" & integer'image(GOLD_OUTPUT_NIBBLES) & ") bits"
72  severity failure;
73 
74  assert (4*GOLD_OUTPUT_NIBBLES) mod DATA_WIDTH = 0
75  report "datacompare(" & SIMULATION_LABEL & "): An exact multiple of DATA_WIDTH (" & integer'image(DATA_WIDTH) & ") must fit into GOLD_OUTPUT_NIBBLES nibbles (4*" & integer'image(GOLD_OUTPUT_NIBBLES) & ") bits."
76  severity failure;
77 
78  -- If endsim arrives while the file is still open something went wrong
79  assert not (endsim = '1' and gold_file_isopen)
80  report "datacompare(" & SIMULATION_LABEL & "): endsim asserted before expected, seen only " & integer'image(received_data) & "valid data"
81  severity failure;
82 
83  --! @brief Reads the file line by line, accumulates data and compares
84  --!
85  --! @detailed Also reports errors and checks for unexpected conditions
86  datacompare_read : process
87 
88  --file gold_file_pointer : text;
89  variable current_line : line;
90  variable expected_data : std_logic_vector (GOLD_OUTPUT_NIBBLES*4-1 downto 0); -- Data read from file
91  variable current_data : std_logic_vector (GOLD_OUTPUT_NIBBLES*4-1 downto 0); -- Data read from input
92  variable chunk_idx : integer range 0 to NUM_CHUNKS := 0; -- Points to current data chunk in line
93  variable error_count : integer := 0; -- Store differences between received and expected data
94  variable correct_count : integer := 0; -- Store number of correct data
95 
96  begin
97 
98  print ("datacompare(" & SIMULATION_LABEL & "): NUM_CHUNKS: " & integer'image(NUM_CHUNKS));
99  print ("datacompare(" & SIMULATION_LABEL & "): opening gold_output file " & GOLD_OUTPUT_FILE);
100  file_open(gold_file_pointer, GOLD_OUTPUT_FILE, READ_MODE);
101  gold_file_isopen := true;
102 
103  while (not endfile(gold_file_pointer)) loop
104 
105  print (DEBUG, "datacompare(" & SIMULATION_LABEL & "): reading line");
106  readline (gold_file_pointer, current_line); -- Read the whole line from the file
107 
108  -- Before converting line to std_logic_vector, assert that number of nibbles read matches expected
109  -- Since a line is a pointer (technically an "access", in VHDL) to a string,
110  -- current_line.all is a string, so check its length
111  assert current_line.all'LENGTH = GOLD_OUTPUT_NIBBLES
112  report "datagen: unexpected number of nibbles in gold output file, got " & integer'image(current_line.all'LENGTH) & ", expected " & integer'image(GOLD_OUTPUT_NIBBLES)
113  severity failure;
114 
115  hread (current_line, expected_data); -- Interpret the line as hex data and put it in a std_logic_vector
116 
117  while ((chunk_idx < NUM_CHUNKS)) loop
118  wait until rising_edge(clk);
119  if (valid = '1') then
120  print (DEBUG, "datacompare(" & SIMULATION_LABEL & "): chunk_idx: " & integer'image(chunk_idx));
121  current_data(DATA_WIDTH*(chunk_idx+1)-1 downto DATA_WIDTH*chunk_idx) := data; -- Put input data in the correct chunk
122  chunk_idx := chunk_idx + 1;
123  received_data <= received_data + 1;
124  end if;
125  end loop;
126 
127  if (abs(signed(current_data) - signed(expected_data)) > ERROR_MARGIN) then
128  report "datacompare(" & SIMULATION_LABEL & "): ERROR: received " & slv2hexstring (current_data) & ", expecting " & slv2hexstring (expected_data)
129  severity error;
130  error_count := error_count + 1;
131  else
132  if (VERBOSE = true) then
133  report "datacompare(" & SIMULATION_LABEL & "): data OK, received " & slv2hexstring (current_data) & ", expecting " & slv2hexstring (expected_data) severity note;
134  end if;
135  correct_count := correct_count + 1;
136  end if;
137 
138  chunk_idx := 0;
139 
140  end loop;
141 
142  file_close(gold_file_pointer);
143  gold_file_isopen := false;
144 
145  wait until (falling_edge(clk) or (endsim='1'));
146 
147  print (VERBOSE, "datacompare(" & SIMULATION_LABEL & "): " & integer'image(received_data) & " data received");
148  print (VERBOSE, "datacompare(" & SIMULATION_LABEL & "): No more data in output file, closing it");
149 
150  wait until endsim='1';
151 
152  assert correct_count > 0
153  report "datacompare(" & SIMULATION_LABEL & "): simulation finished but correct data is not > 0. correct data: " & integer'image(correct_count) severity failure;
154 
155  report "datacompare(" & SIMULATION_LABEL & "): test end, errors: " & integer'image(error_count) & " correct data: " & integer'image(correct_count) severity note;
156 
157  wait;
158 
159  end process datacompare_read;
160 
161 end data_comparison;
162 
GOLD_OUTPUT_FILEstring := "../test/datacompare_test.txt"
File where data is stored.
Definition: datacompare.vhd:36
SIMULATION_LABELstring := "datacompare"
Allow to separate messages from different instances in SIMULATION.
Definition: datacompare.vhd:33
GOLD_OUTPUT_NIBBLESinteger := 2
Maximum hex chars for each output data.
Definition: datacompare.vhd:37
VERBOSEboolean := false
Report correct data and not only erroneous data.
Definition: datacompare.vhd:34
Compares input data with values in file and reports errors.
Definition: datacompare.vhd:31
Common datatypes and component declarations.
text gold_file_pointer
Define this outside the process so we can check endfile(gold_file_pointer) in a concurrent assertion...
Definition: datacompare.vhd:57
DEBUGboolean := false
Print debug info (developers only)
Definition: datacompare.vhd:35
integer := 4* GOLD_OUTPUT_NIBBLES/ DATA_WIDTH NUM_CHUNKS
Each line in output file equals to NUM_CHUNKS data of DATA_WIDTH.
Definition: datacompare.vhd:52
ERROR_MARGINinteger := 0
Comparison is ok if data differs by this value or less.
Definition: datacompare.vhd:40
in datastd_logic_vector( DATA_WIDTH- 1 downto 0)
Data to compare with data in file.
Definition: datacompare.vhd:43
_library_ ieeeieee
Use IEEE standard definitions library.
Definition: clkmanager.vhd:8
DATA_WIDTHinteger := 8
Width of inout data.
Definition: datacompare.vhd:38
in clkstd_logic
Expects input data aligned to this clock.
Definition: datacompare.vhd:42
Allows for text output in simulation.
Definition: txt_util.vhd:12
in endsimstd_logic
Active high, tells the process to close its open files.
Definition: datacompare.vhd:46
in validstd_logic
Active high, indicates data is valid.
Definition: datacompare.vhd:44