Testbenches - FPGA Designs With VHDL Documentation
Testbenches - FPGA Designs With VHDL Documentation
Testbenches
10. Testbenches
10.1. Introduction
In previous chapters, we generated the simula on waveforms using modelsim, by providing the
input signal values manually; if the number of input signals are very large and/or we have to
perform simula on several mes, then this process can be quite complex, me consuming and
irrita ng. Suppose input is of 10 bit, and we want to test all the possible values of input i.e.
10
2 − 1, then it is impossible to do it manually. In such cases, testbenches are very useful; also,
tested design more reliable and prefer by the other clients as well. Further, with the help of
testbenches, we can generate results in the form of csv (comma separated file), which can be
used by other so wares for further analysis e.g. Python, Excel and Matlab etc.
Since testbenches are used for simula on purpose only (not for synthesis), therefore full range
of VHDL constructs can be used e.g. keywords ‘assert’, ‘report’ and ‘for loops’ etc. can be used
for wri ng testbenches.
Modelsim-project is created in this chapter for simula ons, which allows the rela ve path to the
files with respect to project directory as shown in Sec on 10.2.5. Simula on can be run without
crea ng the project, but we need to provide the full path of the files as shown in Lines 30-34 of
Lis ng 10.5.
Lastly, mixed modeling is not supported by Altera-Modelsim-starter version, i.e. Verilog designs
with VHDL and vice-versa can not be compiled in this version of Modelsim.
Lis ng 10.1 shows the VHDL code for the half adder which is tested using different ways,
Note that, testbenches are wri en in separate VHDL files as shown in Lis ng 10.2. Simplest way
to write a testbench, is to invoke the ‘design for tes ng’ in the testbench and provide all the
input values in the file, as explained below,
In this lis ng, a testbench with name ‘half_adder_simple_tb’ is defined at Lines 7-8. Note that,
en ty of testbench is always empty i.e. no ports are defined in the en ty (see Lines 7-8).
Then 4 signals are defined i.e. a, b, sum and carry (Lines 11-12) inside the architecture body;
these signals are then connected to actual half adder design using structural modeling (see
Line 15). Lastly, different values are assigned to input signals e.g. ‘a’ and ‘b’ at lines 16 and 17
respec vely.
In Line 22, value of ‘a’ is 0 ini ally (at 0 ns), then it changes to ‘1’ at 20 ns and again changes
to ‘0’ at 40 ns (do not confuse with a er 40 ns, as a er 40 ns is with respect to 0 ns, not
with respect to 20 ns). Similarly, the values of ‘a’ becomes ‘0’ and ‘1’ at 40 and 60 ns
respec vely. In the same way value of ‘b’ is ini ally ‘0’ and change to ‘1’ at 40 ns at Line 23.
In this way 4 possible combina on are generated for two bits (‘ab’) i.e. 00, 01, 10 and 11 as
shown in Fig. 10.1; also corresponding outputs, i.e. sum and carry, are shown in the figure.
/
Problem: Although, the testbench is very simple, but input pa erns are not readable. By using
the process statement in the testbench, we can make input pa erns more readable along with
inclusion of various other features e.g. report genera on etc., as shown in next sec on.
1 -- half_adder_simple_tb.vhd
2
3 library ieee;
4 use ieee.std_logic_1164.all;
5
6
7 entity half_adder_simple_tb is
8 end half_adder_simple_tb;
9
10 architecture tb of half_adder_simple_tb is
11 signal a, b : std_logic; -- inputs
12 signal sum, carry : std_logic; -- outputs
13 begin
14 -- connecting testbench signals with half_adder.vhd
15 UUT : entity work.half_adder port map (a => a, b => b, sum => sum, carry => carry);
16
17 -- inputs
18 -- 00 at 0 ns
19 -- 01 at 20 ns, as b is 0 at 20 ns and a is changed to 1 at 20 ns
20 -- 10 at 40 ns
21 -- 11 at 60 ns
22 a <= '0', '1' after 20 ns, '0' after 40 ns, '1' after 60 ns;
23 b <= '0', '1' after 40 ns;
24 end tb ;
In Lis ng 10.3, process statement is used in the testbench; which includes the input values along
with the corresponding output values. If the specified outputs are not matched with the output
generated by half-adder, then errors will be generated. Note that, process statement is wri en
without the sensi vity list.
Also, ‘period’ is defined as 20 ns at Line 18; and then used a er each input values e.g line 22,
which indicates that input will be displayed for 20 ns before going to next input values (see in
Fig. 10.3).
/
1 -- half_adder_process_tb.vhd
2
3 library ieee;
4 use ieee.std_logic_1164.all;
5
6
7 entity half_adder_process_tb is
8 end half_adder_process_tb;
9
10 architecture tb of half_adder_process_tb is
11 signal a, b : std_logic;
12 signal sum, carry : std_logic;
13 begin
14 -- connecting testbench signals with half_adder.vhd
15 UUT : entity work.half_adder port map (a => a, b => b, sum => sum, carry => carry);
16
17 tb1 : process
18 constant period: time := 20 ns;
19 begin
20 a <= '0';
21 b <= '0';
22 wait for period;
23 assert ((sum = '0') and (carry = '0')) -- expected output
24 -- error will be reported if sum or carry is not 0
25 report "test failed for input combination 00" severity error;
26
27 a <= '0';
28 b <= '1';
29 wait for period;
30 assert ((sum = '1') and (carry = '0'))
31 report "test failed for input combination 01" severity error;
32
33 a <= '1';
34 b <= '0';
35 wait for period;
36 assert ((sum = '1') and (carry = '0'))
37 report "test failed for input combination 10" severity error;
38
39 a <= '1';
40 b <= '1';
41 wait for period;
42 assert ((sum = '0') and (carry = '1'))
43 report "test failed for input combination 11" severity error;
44
45 -- Fail test
46 a <= '0';
47 b <= '1';
48 wait for period;
49 assert ((sum = '0') and (carry = '1'))
50 report "test failed for input combination 01 (fail test)" severity error;
51
52
53 wait; -- indefinitely suspend process
54 end process;
55 end tb;
/
Fig. 10.2 Simula on results for Lis ng 10.3
The inputs pa erns can be defined in the form of look-table as well as shown in Lis ng 10.4,
instead of define separately at different loca on as done in Lis ng 10.3 e.g. at lines 20 and 27
etc.
Basic concept of this Lis ng is similar to Lis ng 10.3 but wri en in different style. Testbench
with lookup table can be wri en using three steps as shown below,
Define record : First we need to define a record which contains the all the possible
columns in the look table. Here, there are four possible columns i.e. a, b, sum and carry,
which are defined in record at Lines 15-18.
Create lookup table : Next, we need to define the lookup table values, which is done at
Lines 20-28. Here posi onal method is used for assigning the values to columns (see line
22-27); further, name-associa on method can also be used as shown in the comment at
Line 23.
Assign values to signals : Then the values of the lookup table need to be assigned to
half_adder en ty (one by one). For this ‘for loop’ is used at line 35, which assigns the
values of ‘’test-vector’s ‘a’ and ‘b’ ‘’ to signal ‘a’ and ‘b’ (see comment at Line 36 for be er
understanding). Similarly, expected values of sum and carry are generated at Lines 41-44.
Lastly, report is generated for wrong outputs at Lines 46-50.
The simula ons results and reported-error are shown in Fig. 10.4 and Fig. 10.5 respec vely.
/
1 -- half_adder_lookup_tb.vhd
2
3 library ieee;
4 use ieee.std_logic_1164.all;
5
6 entity half_adder_lookup_tb is
7 end half_adder_lookup_tb;
8
9 architecture tb of half_adder_lookup_tb is
10
11 signal a, b : std_logic; -- input
12 signal sum, carry : std_logic; -- output
13
14 -- declare record type
15 type test_vector is record
16 a, b : std_logic;
17 sum, carry : std_logic;
18 end record;
19
20 type test_vector_array is array (natural range <>) of test_vector;
21 constant test_vectors : test_vector_array := (
22 -- a, b, sum , carry -- positional method is used below
23 ('0', '0', '0', '0'), -- or (a => '0', b => '0', sum => '0', carry => '0')
24 ('0', '1', '1', '0'),
25 ('1', '0', '1', '0'),
26 ('1', '1', '0', '1'),
27 ('0', '1', '0', '1') -- fail test
28 );
29
30 begin
31 UUT : entity work.half_adder port map (a => a, b => b, sum => sum, carry => carry);
32
33 tb1 : process
34 begin
35 for i in test_vectors'range loop
36 a <= test_vectors(i).a; -- signal a = i^th-row-value of test_vector's a
37 b <= test_vectors(i).b;
38
39 wait for 20 ns;
40
41 assert (
42 (sum = test_vectors(i).sum) and
43 (carry = test_vectors(i).carry)
44 )
45
46 -- image is used for string-representation of integer etc.
47 report "test_vector " & integer'image(i) & " failed " &
48 " for input a = " & std_logic'image(a) &
49 " and b = " & std_logic'image(b)
50 severity error;
51 end loop;
52 wait;
53 end process;
54
55 end tb;
/
Fig. 10.4 Simula on results for Lis ng 10.4
In this sec on, data from file ‘read_file_ex.txt’ is read and displayed in simula on results. Date
stored in the file is shown in Fig. 10.6.
To read the file, first we need to define a buffer of type ‘text’, which can store the values of
the file in it, as shown in Line 17; file is open in read-mode and values are stored in this buffer
at Line 32.
Next, we need to define the variable to read the value from the buffer. Since there are 4
types of values (i.e. a, b, c and spaces) in file ‘read_file_ex.txt’, therefore we need to define 4
variables to store them, as shown in Line 24-26. Since, variable c is of 2 bit, therefore Line 25
is 2-bit vector; further, for spaces, variable of character type is defined at Line 26.
Then, values are read and store in the variables at Lines 36-42. Lastly, these values are
assigned to appropriate signals at Lines 45-47. Finally, file is closed at Line 52. The simula on
results of the lis ng are show in Fig. 10.7.
/
1 -- read_file_ex.vhd
2
3
4 library ieee;
5 use ieee.std_logic_1164.all;
6 use std.textio.all;
7 use ieee.std_logic_textio.all; -- require for writing/reading std_logic etc.
8
9 entity read_file_ex is
10 end read_file_ex;
11
12 architecture tb of read_file_ex is
13 signal a, b : std_logic;
14 signal c : std_logic_vector(1 downto 0);
15
16 -- buffer for storing the text from input read-file
17 file input_buf : text; -- text is keyword
18
19 begin
20
21 tb1 : process
22 variable read_col_from_input_buf : line; -- read lines one by one from input_buf
23
24 variable val_col1, val_col2 : std_logic; -- to save col1 and col2 values of 1 bit
25 variable val_col3 : std_logic_vector(1 downto 0); -- to save col3 value of 2 bit
26 variable val_SPACE : character; -- for spaces between data in file
27
28 begin
29
30 -- if modelsim-project is created, then provide the relative path of
31 -- input-file (i.e. read_file_ex.txt) with respect to main project folder
32 file_open(input_buf, "VHDLCodes/input_output_files/read_file_ex.txt", read_mode);
33 -- else provide the complete path for the input file as show below
34 -- file_open(input_buf, "E:/VHDLCodes/input_output_files/read_file_ex.txt",
35 read_mode);
36
37 while not endfile(input_buf) loop
38 readline(input_buf, read_col_from_input_buf);
39 read(read_col_from_input_buf, val_col1);
40 read(read_col_from_input_buf, val_SPACE); -- read in the space
41 character
42 read(read_col_from_input_buf, val_col2);
43 read(read_col_from_input_buf, val_SPACE); -- read in the space
44 character
45 read(read_col_from_input_buf, val_col3);
46
47 -- Pass the read values to signals
48 a <= val_col1;
49 b <= val_col2;
50 c <= val_col3;
51
52 wait for 20 ns; -- to display results for 20 ns
53 end loop;
54
55 file_close(input_buf);
wait;
end process;
end tb ; -- tb
/
Fig. 10.7 Simula on results of Lis ng 10.5
In this part, different types of values are defined in Lis ng 10.6 and then stored in the file. Here,
only ‘write_mode’ is used for wri ng the data to file (not the ‘append_mode’).
To write the data to the file, first we need to define a buffer, which will load the file on the
simula on environment for wri ng the data during simula on, as shown in Line 15 (buffer-
defined) and Line 27 (load the file to buffer).
Next, we need to define a variable, which will store the values to write into the buffer, as
shown in Line 19. In the lis ng, this variable stores three types of value i.e. strings (Lines 31
and 34 etc.), signal ‘a’ (Line 35) and variable ‘b’ (Line 37).
Note that, two keyword are used for wri ng the data into the file i.e. ‘write’ and ‘writeline’.
‘write’ keyword store the values in the ‘write_col_to_output_buf’ and ‘writeline’ writes the
values in the file. Remember that, all the ‘write’ statements before the ‘writeline’ will be
wri en in same line e.g. Lines 34-37 will be wri en in same line as shown in Fig. 10.8. Lastly,
the simula on result for the lis ng is shown in Fig. 10.9.
/
1 -- write_file_ex.vhd
2
3
4 library ieee;
5 use ieee.std_logic_1164.all;
6 use std.textio.all;
7 use ieee.std_logic_textio.all; -- require for writing std_logic etc.
8
9 entity write_file_ex is
10 end write_file_ex;
11
12 architecture tb of write_file_ex is
13 signal a : std_logic;
14
15 file output_buf : text; -- text is keyword
16 begin
17
18 tb1 : process
19 variable write_col_to_output_buf : line; -- line is keyword
20 variable b : integer := 40;
21 begin
22 a <= '1'; -- assign value to a
23 wait for 20 ns;
24
25 -- if modelsim-project is created, then provide the relative path of
26 -- input-file (i.e. read_file_ex.txt) with respect to main project folder
27 file_open(output_buf, "VHDLCodes/input_output_files/write_file_ex.txt",
28 write_mode);
29 -- else provide the complete path for the input file as show below
30 --file_open(output_buf, "E:/VHDLCodes/input_output_files/write_file_ex.txt",
31 write_mode);
32
33 write(write_col_to_output_buf, string'("Printing values"));
34 writeline(output_buf, write_col_to_output_buf); -- write in line 1
35
36 write(write_col_to_output_buf, string'("a = "));
37 write(write_col_to_output_buf, a);
38 write(write_col_to_output_buf, string'(", b = "));
39 write(write_col_to_output_buf, b);
40 writeline(output_buf, write_col_to_output_buf); -- write in new line 2
41
42 write(write_col_to_output_buf, string'("Thank you"));
43 writeline(output_buf, write_col_to_output_buf); -- write in new line 3
44
45 file_close(output_buf);
46 wait; -- indefinitely suspend process
end process;
end tb ; -- tb
/
Fig. 10.9 Simula on results of Lis ng 10.6
In this sec on, both read and write opera ons are performed in Lis ng 10.7. Further, csv file is
used for read and write opera ons. Content of input and output files are shown in Fig. 10.11
and Fig. 10.12 respec vely.
Please read Lis ng 10.5 and Lis ng 10.6 to understand this part, as only these two lis ngs are
merged together here.
Lines 63-64 are added to skip the header row, i.e. any row which does not start with
boolean-number(see line 42).
Also, error will be reported for value ‘b’ if it is not the boolean. Similarly, this func onality can
be added to other values as well.
Lastly, errors are reported in CSV file at Lines 96-109. This can be seen in Fig. 10.12. It’s
always easier to find the loca on of error using csv file as compare to simula on waveforms
(try to find the errors using Fig. 10.12 and compare it with Fig. 10.12).
1 -- read_write_file_ex.vhd
2
3 -- testbench for half adder,
4
5 -- Features included in this code are
6 -- inputs are read from csv file, which stores the desired outputs as well
7 -- outputs are written to csv file
8 -- actual output and calculated outputs are compared
9 -- Error message is displayed in the file
10 -- header line is skipped while reading the csv file
11
12
13 library ieee;
14 use ieee.std_logic_1164.all;
15 use std.textio.all;
16 use ieee.std_logic_textio.all; -- require for writing/reading std_logic etc.
17
18 entity read_write_file_ex is
19 end read_write_file_ex;
20
21 architecture tb of read_write_file_ex is
/
22 signal a, b : std_logic;
23 signal sum_actual, carry_actual : std_logic;
24 signal sum, carry : std_logic; -- calculated sum and carry by half_adder
25
26 -- buffer for storing the text from input and for output files
27 file input_buf : text; -- text is keyword
28 file output_buf : text; -- text is keyword
29
30 begin
31 UUT : entity work.half_adder port map (a => a, b => b, sum => sum, carry => carry);
32
33 tb1 : process
34 variable read_col_from_input_buf : line; -- read lines one by one from input_buf
35 variable write_col_to_output_buf : line; -- write lines one by one to output_buf
36
37 variable buf_data_from_file : line; -- buffer for storind the data from input read-file
38 variable val_a, val_b : std_logic;
39 variable val_sum, val_carry: std_logic;
40 variable val_comma : character; -- for commas between data in file
41
42 variable good_num : boolean;
43 begin
44
45 -- ####################################################################
46 -- Reading data
47
48 -- if modelsim-project is created, then provide the relative path of
49 -- input-file (i.e. read_file_ex.txt) with respect to main project folder
50 file_open(input_buf, "VHDLCodes/input_output_files/half_adder_input.csv",
51 read_mode);
52 -- else provide the complete path for the input file as show below
53 -- file_open(input_buf, "E:/VHDLCodes/input_output_files/read_file_ex.txt",
54 read_mode);
55
56 -- writing data
57 file_open(output_buf, "VHDLCodes/input_output_files/half_adder_output.csv",
58 write_mode);
59
60 write(write_col_to_output_buf,
61
62 string'("#a,b,sum_actual,sum,carry_actual,carry,sum_test_results,carry_test_results"));
63 writeline(output_buf, write_col_to_output_buf);
64
65 while not endfile(input_buf) loop
66 readline(input_buf, read_col_from_input_buf);
67 read(read_col_from_input_buf, val_a, good_num);
68 next when not good_num; -- i.e. skip the header lines
69
70 read(read_col_from_input_buf, val_comma); -- read in the space character
71 read(read_col_from_input_buf, val_b, good_num);
72 assert good_num report "bad value assigned to val_b";
73
74 read(read_col_from_input_buf, val_comma); -- read in the space character
75 read(read_col_from_input_buf, val_sum);
76 read(read_col_from_input_buf, val_comma); -- read in the space character
77 read(read_col_from_input_buf, val_carry);
78
79 -- Pass the variable to a signal to allow the ripple-carry to use it
80 a <= val_a;
81 b <= val_b;
82 sum_actual <= val_sum;
83 carry_actual <= val_carry;
84
/
85 wait for 20 ns; -- to display results for 20 ns
86
87 write(write_col_to_output_buf, a);
88 write(write_col_to_output_buf, string'(","));
89 write(write_col_to_output_buf, b);
90 write(write_col_to_output_buf, string'(","));
91 write(write_col_to_output_buf, sum_actual);
92 write(write_col_to_output_buf, string'(","));
93 write(write_col_to_output_buf, sum);
94 write(write_col_to_output_buf, string'(","));
95 write(write_col_to_output_buf, carry_actual);
96 write(write_col_to_output_buf, string'(","));
97 write(write_col_to_output_buf, carry);
98 write(write_col_to_output_buf, string'(","));
99
100 -- display Error or OK if results are wrong
101 if (sum_actual /= sum) then
102 write(write_col_to_output_buf, string'("Error,"));
103 else
104 write(write_col_to_output_buf, string'(",")); -- write nothing
105
106 end if;
107
108 -- display Error or OK based on comparison
109 if (carry_actual /= carry) then
110 write(write_col_to_output_buf, string'("Error,"));
111 else
112 write(write_col_to_output_buf, string'("OK,"));
113 end if;
114
115
116 --write(write_col_to_output_buf, a, b, sum_actual, sum, carry_actual, carry);
117 writeline(output_buf, write_col_to_output_buf);
118 end loop;
119
120 file_close(input_buf);
file_close(output_buf);
wait;
end process;
end tb ; -- tb
/
Fig. 10.11 Content of input file ‘half_adder_input.csv’
In this sec on, we have created a testbench which will not stop automa cally i.e. if we press the
‘run all’ bu on then the simula on will run forever, therefore we need to press the ‘run’ bu on
as shown in Fig. 10.13.
/
Lis ng 10.8 is the testbench for mod-M counter, which is discussed in Sec on 8.3.2. Here
‘clk’ signal is generated in the separate process block i.e. Lines 27-33; in this way, clock signal
will be available throughout the simula on process. Further, reset signal is set to ‘1’ in the
beginning and then set to ‘0’ in next clock cycle (Line 37). If there are further, inputs signals,
then those signals can be defined in separate process statement, as discussed in combina on
circuits’ testbenches.
The simula on results are shown in Fig. 10.13, where counter values goes from 0 to 9 as M is
set to 10 (i.e. A in hexadecimal). Further, use ‘run’ bu on for simula ng the sequen al circuits
(instead of run-all), as shown in the figure.
1 -- modMCounter_tb.vhd
2
3 library ieee;
4 use ieee.std_logic_1164.all;
5 use ieee.numeric_std.all;
6
7 entity modMCounter_tb is
8 end modMCounter_tb;
9
10
11 architecture arch of modMCounter_tb is
12 constant M : integer := 10;
13 constant N : integer := 4;
14 constant T : time := 20 ns;
15
16 signal clk, reset : std_logic; -- input
17 signal complete_tick : std_logic; -- output
18 signal count : std_logic_vector(N-1 downto 0); -- output
19 begin
20
21 modMCounter_unit : entity work.modMCounter
22 generic map (M => M, N => N)
23 port map (clk=>clk, reset=>reset, complete_tick=>complete_tick,
24 count=>count);
25
26 -- continuous clock
27 process
28 begin
29 clk <= '0';
30 wait for T/2;
31 clk <= '1';
32 wait for T/2;
33 end process;
34
35
36 -- reset = 1 for first clock cycle and then 0
37 reset <= '1', '0' after T/2;
38
39 end arch;
/
Fig. 10.13 Simula on results of Lis ng 10.8
To run the simula on for the finite dura on, we need to provide the ‘number of clocks’ for which
we want to run the simula on, as shown in Line 23 of Lis ng 10.9. Then at Lines 47-52 are
added to close the file a er desired number of clocks i.e. ‘num_of_clocks’. Also, the data is saved
into the file, which is discussed in Sec on 10.2.6. Now, if we press the run all bu on, then the
simulator will stop a er ‘num_of_clocks’ cycles. Note that, if the data is in ‘signed or unsigned’
format, then it can not be saved into the file. We need to change the data into other format e.g.
‘integer’, ‘natural’ or ‘std_logic_vector’ etc. before saving it into the file, as shown in Line 73. The
simula on waveforms and saved results are shown in Fig. 10.14 and Fig. 10.15 respec vely.
/
Lis ng 10.9 Testbench with finite dura on for modMCounter.vhd
1 -- modMCounter_tb2.vhd
2
3 library ieee;
4 use ieee.std_logic_1164.all;
5 use ieee.numeric_std.all;
6 use std.textio.all;
7 use ieee.std_logic_textio.all; -- require for std_logic etc.
8
9 entity modMCounter_tb2 is
10 end modMCounter_tb2;
11
12
13 architecture arch of modMCounter_tb2 is
14 constant M : integer := 3; -- count upto 2 (i.e. 0 to 2)
15 constant N : integer := 4;
16 constant T : time := 20 ns;
17
18 signal clk, reset : std_logic; -- input
19 signal complete_tick : std_logic; -- output
20 signal count : std_logic_vector(N-1 downto 0); -- output
21
22 -- total samples to store in file
23 constant num_of_clocks : integer := 30;
24 signal i : integer := 0; -- loop variable
25 file output_buf : text; -- text is keyword
26
27 begin
28
29 modMCounter_unit : entity work.modMCounter
30 generic map (M => M, N => N)
31 port map (clk=>clk, reset=>reset, complete_tick=>complete_tick,
32 count=>count);
33
34
35 -- reset = 1 for first clock cycle and then 0
36 reset <= '1', '0' after T/2;
37
38 -- continuous clock
39 process
40 begin
41 clk <= '0';
42 wait for T/2;
43 clk <= '1';
44 wait for T/2;
45
46 -- store 30 samples in file
47 if (i = num_of_clocks) then
48 file_close(output_buf);
49 wait;
50 else
51 i <= i + 1;
52 end if;
53 end process;
54
55
56 -- save data in file : path is relative to Modelsim-project directory
57 file_open(output_buf, "input_output_files/counter_data.csv", write_mode);
58 process(clk)
59 variable write_col_to_output_buf : line; -- line is keyword
60 begin /
61 if(clk'event and clk='1' and reset /= '1') then -- avoid reset data
62 -- comment below 'if statement' to avoid header in saved file
63 if (i = 0) then
64 write(write_col_to_output_buf, string'("clock_tick,count"));
65 writeline(output_buf, write_col_to_output_buf);
66 end if;
67
68 write(write_col_to_output_buf, complete_tick);
69 write(write_col_to_output_buf, string'(","));
70 -- Note that unsigned/signed values can not be saved in file,
71 -- therefore change into integer or std_logic_vector etc.
72 -- following line saves the count in integer format
73 write(write_col_to_output_buf, to_integer(unsigned(count)));
74 writeline(output_buf, write_col_to_output_buf);
75 end if;
76 end process;
77 end arch;
10.4. Conclusion
In this chapter, we learn to write testbenches with different styles for combina onal circuits. We
saw the methods by which inputs can be read from the file and the outputs can be wri en in the
file. Simula on results and expected results are compared and saved in the csv file and displayed
as simula on waveforms; which demonstrated that loca ng the errors in csv files is easier than
the simula on waveforms. Further, we saw the simula on of sequen al circuits as well, which is
slightly different from combina on circuits; but all the methods of combina onal circuit
simula ons can be applied to sequen al circuits as well.