VHDL-verification
Package to ease directed testing of HDL entities
datagen.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 --! @file
3 --! @author Hipolito Guzman-Miranda
4 --! @brief Generates stimuli from a 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 --! For datagen_invalid_data definition
20 use work.vhdl_verification.all;
21 
22 --! @brief Reads stimuli from file and outputs it with specified format
23 --!
24 --! @detailed Reads file at STIMULI_FILE, expecting STIMULI_NIBBLES chars in
25 --! each line. Data is expected in hex format: 4 bits per character (nibble).
26 --! Reads the data and outputs it with a width of DATA_WIDTH bits, asserting
27 --! valid='1' when a new data is available. Outputs a new data each THROUGHPUT
28 --! cycles, unless can_write='0'. When valid='0', output bits are set to
29 --! INVALID_DATA. After last data in STIMULI_FILE has been output, waits for
30 --! CYCLES_AFTER_LAST_VECTOR clk cycles and afterwards asserts endsim.
31 entity datagen is
32  generic(
33  VERBOSE : boolean := false; --! Print more internal details
34  DEBUG : boolean := false; --! Print debug info (developers only)
35  STIMULI_FILE : string := "../test/datagen_test.txt"; --! File where data is stored
36  STIMULI_NIBBLES : integer := 2; --! Maximum hex chars for each input data
37  DATA_WIDTH : integer := 8; --! Width of generated data
38  THROUGHPUT : integer := 0; --! Output 1 valid data each THROUGHPUT cycles
39  INVALID_DATA : datagen_invalid_data := unknown; --! Output value when data is not valid
40  CYCLES_AFTER_LAST_VECTOR : integer := 10 --! Number of cycles between last data and assertion of endsim
41  );
42  port(
43  clk : in std_logic; --! Align generated data to this clock
44  can_write : in std_logic; --! Active high, tells datagen it can assert valid. Use for control-flow
45  data : out std_logic_vector (DATA_WIDTH-1 downto 0); --! Generated data
46  valid : out std_logic; --! Active high, indicates data is valid
47  endsim : out std_logic --! Active high, tells the other simulation processes to close their open files
48  );
49 end datagen;
50 
51 --! Architecture reads file lines and slices it into chunks of size \c DATA_WIDTH
52 architecture data_generation of datagen is
53 
54  constant NUM_CHUNKS : integer := 4*STIMULI_NIBBLES / DATA_WIDTH; --! Each line in input file equals to NUM_CHUNK data of DATA_WIDTH
55 
56  signal cycle_count : integer := 0; --! Cycle counter
57  signal sent_data : integer := 0; --! Data sent to output
58  signal last_valid_data : std_logic_vector (DATA_WIDTH-1 downto 0); --! Last data when valid was '1'
59  signal invalid_output : std_logic_vector (DATA_WIDTH-1 downto 0); --! Output value when data_valid = '0'
60 
61 begin
62 
63  print ("CYCLES_AFTER_LAST_VECTOR: " & integer'image(CYCLES_AFTER_LAST_VECTOR));
64 
65  assert STIMULI_NIBBLES > 0
66  report "datagen: STIMULI_NIBBLES must be a positive non-zero integer"
67  severity failure;
68 
69  assert DATA_WIDTH > 0
70  report "datagen: DATA_WIDTH must be a positive non-zero integer"
71  severity failure;
72 
73  assert THROUGHPUT > 0
74  report "datagen: THROUGHPUT must be a positive non-zero integer"
75  severity failure;
76 
77  assert 4*STIMULI_NIBBLES >= DATA_WIDTH
78  report "datagen: DATA_WIDTH (" & integer'image(DATA_WIDTH) & ") bits must fit into STIMULI_NIBBLES nibbles (4*" & integer'image(STIMULI_NIBBLES) & ") bits"
79  severity failure;
80 
81  assert (4*STIMULI_NIBBLES) mod DATA_WIDTH = 0
82  report "datagen: An exact multiple of DATA_WIDTH (" & integer'image(DATA_WIDTH) & ") must fit into STIMULI_NIBBLES nibbles (4*" & integer'image(STIMULI_NIBBLES) & ") bits."
83  severity failure;
84 
85  assert sent_data >= 0
86  report "datagen: sent_data is negative (" & integer'image(sent_data) & "). Aborting."
87  severity failure;
88 
89  --! @brief Manage data generation from data in STIMULI_FILE
90  datagen_read : process
91 
92  file file_pointer : text; --! File pointer
93  variable current_line : line; --! Last line read from file
94  variable current_hex_data : std_logic_vector (STIMULI_NIBBLES*4-1 downto 0); --! Last line read, converted to hex data
95  variable chunk_idx : integer range 0 to NUM_CHUNKS := 0; --! Points to current data chunk in line
96  variable cycles_to_wait : integer := THROUGHPUT - 1; --! Cycles to wait before outputting next data
97 
98  begin
99 
100  assert cycles_to_wait >= 0
101  report "datagen: cycles_to_wait is negative (" & integer'image(cycles_to_wait) & "). Aborting."
102  severity failure;
103 
104  endsim <= '0';
105  print ("datagen: NUM_CHUNKS: " & integer'image(NUM_CHUNKS));
106  print ("datagen: opening input file" & STIMULI_FILE);
107  file_open(file_pointer, STIMULI_FILE, READ_MODE);
108 
109  wait until rising_edge(clk); -- do nothing until first valid clock event
110 
111  while (not endfile(file_pointer)) loop
112 
113  print (DEBUG, "datagen: reading line");
114  readline (file_pointer, current_line); -- Read the whole line from the file
115 
116  -- Before converting line to std_logic_vector, assert that number of nibbles read matches expected
117  -- Since a line is a pointer (technically an "access", in VHDL) to a string,
118  -- current_line.all is a string, so check its length
119  assert current_line.all'LENGTH = STIMULI_NIBBLES
120  report "datagen: unexpected number of nibbles in stimuli file, got " & integer'image(current_line.all'LENGTH) & ", expected " & integer'image(STIMULI_NIBBLES)
121  severity failure;
122 
123  hread (current_line, current_hex_data); -- Interpret the line as hex data and put it in a std_logic_vector
124 
125  while (chunk_idx < NUM_CHUNKS) loop
126  print (DEBUG, "datagen: chunk_idx: " & integer'image(chunk_idx));
127 
128  while (cycles_to_wait > 0) loop
129  print (DEBUG, "datagen: cycles_to_wait: " & integer'image(cycles_to_wait));
130  cycles_to_wait := cycles_to_wait - 1;
131  data <= invalid_output; -- by default, data is NOT valid
132  valid <= '0';
133  cycle_count <= cycle_count + 1;
134  wait until rising_edge(clk);
135  end loop;
136 
137  if (can_write /= '1') then
138  wait until can_write = '1' and rising_edge(clk);
139  end if;
140 
141  cycles_to_wait := THROUGHPUT - 1;
142  data <= current_hex_data(DATA_WIDTH*(chunk_idx+1)-1 downto DATA_WIDTH*chunk_idx); --Get DATA_WIDTH bits from current_hex_data into data
143  last_valid_data <= current_hex_data(DATA_WIDTH*(chunk_idx+1)-1 downto DATA_WIDTH*chunk_idx); --Store also, for the case where we have to output last_valid_data when valid='0'
144  valid <= '1';
145  cycle_count <= cycle_count + 1;
146  sent_data <= sent_data + 1;
147  chunk_idx := chunk_idx + 1;
148  wait until rising_edge(clk);
149 
150  end loop;
151  chunk_idx := 0;
152  end loop;
153 
154  print ("datagen: " & integer'image(sent_data) & " data sent, closing input file");
155  file_close(file_pointer);
156 
157  cycles_to_wait := CYCLES_AFTER_LAST_VECTOR;
158  while (cycles_to_wait > 0) loop
159  cycles_to_wait := cycles_to_wait - 1;
160  data <= invalid_output; -- when finished, data is NOT valid
161  valid <= '0';
162  cycle_count <= cycle_count + 1;
163  wait until rising_edge(clk);
164  end loop;
165 
166  report "datagen: asserting endsim. cycle_count: " & integer'image(cycle_count) severity note;
167  endsim <= '1';
168  wait;
169 
170  end process datagen_read;
171 
172  --! @brief Determine what will be the output when data_valid = '0'
173  --!
174  --! @details
175  invalid_data_behavior: process (last_valid_data)
176  begin
177 
178  case INVALID_DATA is
179  when keep => invalid_output <= last_valid_data;
180  when uninitialized => invalid_output <= (others => 'U');
181  when unknown => invalid_output <= (others => 'X');
182  when zero => invalid_output <= (others => '0');
183  when one => invalid_output <= (others => '1');
184  when high_impedance => invalid_output <= (others => 'Z');
185  when weak_unknown => invalid_output <= (others => 'W');
186  when weak_zero => invalid_output <= (others => 'L');
187  when weak_one => invalid_output <= (others => 'H');
188  when dont_care => invalid_output <= (others => '-');
189  end case;
190 
191  end process invalid_data_behavior;
192 
193 end data_generation;
194 
Reads stimuli from file and outputs it with specified format.
Definition: datagen.vhd:31
out validstd_logic
Active high, indicates data is valid.
Definition: datagen.vhd:46
DEBUGboolean := false
Print debug info (developers only)
Definition: datagen.vhd:34
Common datatypes and component declarations.
CYCLES_AFTER_LAST_VECTORinteger := 10
Number of cycles between last data and assertion of endsim.
Definition: datagen.vhd:41
std_logic_vector( DATA_WIDTH- 1 downto 0) invalid_output
Output value when data_valid = &#39;0&#39;.
Definition: datagen.vhd:59
integer := 0 sent_data
Data sent to output.
Definition: datagen.vhd:57
INVALID_DATAdatagen_invalid_data := unknown
Output value when data is not valid.
Definition: datagen.vhd:39
STIMULI_NIBBLESinteger := 2
Maximum hex chars for each input data.
Definition: datagen.vhd:36
THROUGHPUTinteger := 0
Output 1 valid data each THROUGHPUT cycles.
Definition: datagen.vhd:38
(keep,uninitialized,unknown,zero,one,high_impedance,weak_unknown,weak_zero,weak_one,dont_care) datagen_invalid_data
Output of datagen when valid=&#39;0&#39;.
out datastd_logic_vector( DATA_WIDTH- 1 downto 0)
Generated data.
Definition: datagen.vhd:45
integer := 4* STIMULI_NIBBLES/ DATA_WIDTH NUM_CHUNKS
Each line in input file equals to NUM_CHUNK data of DATA_WIDTH.
Definition: datagen.vhd:54
VERBOSEboolean := false
Print more internal details.
Definition: datagen.vhd:33
in can_writestd_logic
Active high, tells datagen it can assert valid. Use for control-flow.
Definition: datagen.vhd:44
in clkstd_logic
Align generated data to this clock.
Definition: datagen.vhd:43
STIMULI_FILEstring := "../test/datagen_test.txt"
File where data is stored.
Definition: datagen.vhd:35
integer := 0 cycle_count
Cycle counter.
Definition: datagen.vhd:56
std_logic_vector( DATA_WIDTH- 1 downto 0) last_valid_data
Last data when valid was &#39;1&#39;.
Definition: datagen.vhd:58
DATA_WIDTHinteger := 8
Width of generated data.
Definition: datagen.vhd:37
out endsimstd_logic
Active high, tells the other simulation processes to close their open files.
Definition: datagen.vhd:48
Allows for text output in simulation.
Definition: txt_util.vhd:12
_library_ ieeeieee
Use IEEE standard definitions library.
Definition: datacompare.vhd:8