Project

General

Profile

Download (10.3 KB) Statistics
| Branch: | Tag: | Revision:
1
-------------------------------------------------------------------------------
2
--| @file tb.vhd
3
--| @brief Main test bench.
4
--|
5
--| @author         Richard James Howe.
6
--| @copyright      Copyright 2013,2017 Richard James Howe.
7
--| @license        MIT
8
--| @email          howe.r.j.89@gmail.com
9
--|
10
--| This test bench does quite a lot. It is not like normal VHDL test benches
11
--| in the fact that it uses configurable variables that it read in from a
12
--| file, which it does in an awkward but usable fashion.
13
--|
14
--| It also tests multiple modules.
15
--|
16
--| @todo Optionally, read in from standard input and send the character
17
--| over the UART, then print out any received characters to standard out.
18
-------------------------------------------------------------------------------
19

    
20
library ieee,work;
21
use ieee.std_logic_1164.all;
22
use ieee.numeric_std.all;
23
use ieee.math_real.all;
24
use std.textio.all;
25
use work.util.all;
26
use work.core_pkg.all;
27
use work.vga_pkg.all;
28
use work.uart_pkg.uart_core;
29

    
30
entity tb is
31
end tb;
32

    
33
architecture testing of tb is
34
	constant clock_frequency:         positive := 100_000_000;
35
	constant number_of_interrupts:    positive := 8;
36
	constant uart_baud_rate:          positive := 115200;
37
	constant configuration_file_name: string   := "tb.cfg";
38
	constant clk_period:              time     := 1000 ms / clock_frequency;
39
	constant uart_tx_time:            time     := (10*1000 ms) / 115200;
40

    
41
	-- Test bench configurable options --
42

    
43
	type configurable_items is record
44
		number_of_iterations: positive;
45
		verbose:              boolean;
46
		report_number:        natural;
47
		interactive:          boolean;
48
	end record;
49

    
50
	function set_configuration_items(ci: configuration_items) return configurable_items is
51
		variable r: configurable_items;
52
	begin
53
		r.number_of_iterations := ci(0).value;
54
		r.verbose              := ci(1).value > 0;
55
		r.interactive          := ci(2).value > 0;
56
		r.report_number        := ci(3).value;
57
		return r;
58
	end function;
59

    
60
	constant configuration_default: configuration_items(0 to 3) := (
61
		(name => "Cycles  ", value => 1000),
62
		(name => "Verbose ", value => 1),
63
		(name => "Interact", value => 0),
64
		(name => "LogFor  ", value => 256));
65

    
66
	-- Test bench configurable options --
67

    
68
	signal stop:  std_ulogic :=  '0';
69
	signal debug: cpu_debug_interface;
70

    
71
	signal clk:   std_ulogic := '0';
72
	signal rst:   std_ulogic := '0';
73

    
74
--	signal  cpu_wait: std_ulogic := '0'; -- CPU wait flag
75

    
76
	-- Basic I/O
77
	signal btnu:  std_ulogic := '0';  -- button up
78
	signal btnd:  std_ulogic := '0';  -- button down
79
	signal btnc:  std_ulogic := '0';  -- button centre
80
	signal btnl:  std_ulogic := '0';  -- button left
81
	signal btnr:  std_ulogic := '0';  -- button right
82
	signal sw:    std_ulogic_vector(7 downto 0) := (others => '0'); -- switches
83
	signal an:    std_ulogic_vector(3 downto 0) := (others => '0'); -- anodes   8 segment display
84
	signal ka:    std_ulogic_vector(7 downto 0) := (others => '0'); -- kathodes 8 segment display
85
	signal ld:    std_ulogic_vector(7 downto 0) := (others => '0'); -- leds
86

    
87
	-- VGA
88
	signal o_vga: vga_physical_interface;
89
	signal hsync_gone_high: boolean := false;
90
	signal vsync_gone_high: boolean := false;
91

    
92
	-- HID
93
	signal ps2_keyboard_data: std_ulogic := '0';
94
	signal ps2_keyboard_clk:  std_ulogic := '0';
95

    
96
	-- UART
97
	signal rx:                 std_ulogic := '0';
98
	signal tx:                 std_ulogic := '0';
99
	signal dout_ack, dout_stb: std_ulogic := '0';
100
	signal din_ack, din_stb:   std_ulogic := '0';
101
	signal dout:               std_ulogic_vector(7 downto 0) := (others => '0');
102
	signal din:                std_ulogic_vector(7 downto 0) := (others => '0');
103

    
104
	-- Wave form generator
105
	signal gen_dout:     std_ulogic_vector(15 downto 0) := (others => '0');
106

    
107
	shared variable cfg: configurable_items := set_configuration_items(configuration_default);
108

    
109
	signal configured: boolean := false;
110

    
111
	signal RamCS:     std_ulogic := 'X';
112
	signal MemOE:     std_ulogic := 'X'; -- negative logic
113
	signal MemWR:     std_ulogic := 'X'; -- negative logic
114
	signal MemAdv:    std_ulogic := 'X'; -- negative logic
115
	signal MemWait:   std_ulogic := 'X'; -- positive!
116
	signal FlashCS:   std_ulogic := 'X';
117
	signal FlashRp:   std_ulogic := 'X';
118
	signal MemAdr:    std_ulogic_vector(26 downto 1) := (others => 'X');
119
	signal MemDB:     std_logic_vector(15 downto 0) := (others => 'X');
120

    
121
begin
122
---- Units under test ----------------------------------------------------------
123

    
124
	MemDB <= (others => '0') when MemOE = '1' else (others => 'Z');
125

    
126
	uut: entity work.top
127
	generic map(
128
		clock_frequency      => clock_frequency,
129
		uart_baud_rate       => uart_baud_rate)
130
	port map(
131
		debug       => debug,
132
		clk         => clk,
133
		-- rst      => rst,
134
		btnu        => btnu,
135
		btnd        => btnd,
136
		btnc        => btnc,
137
		btnl        => btnl,
138
		btnr        => btnr,
139
		sw          => sw,
140
		an          => an,
141
		ka          => ka,
142
		ld          => ld,
143
		rx          => rx,
144
		tx          => tx,
145
		o_vga       => o_vga,
146

    
147
		ps2_keyboard_data => ps2_keyboard_data,
148
		ps2_keyboard_clk  => ps2_keyboard_clk,
149

    
150
		RamCS    =>  RamCS,
151
		MemOE    =>  MemOE,
152
		MemWR    =>  MemWR,
153
		MemAdv   =>  MemAdv,
154
		MemWait  =>  MemWait,
155
		FlashCS  =>  FlashCS,
156
		FlashRp  =>  FlashRp,
157
		MemAdr   =>  MemAdr,
158
		MemDB    =>  MemDB);
159

    
160
	uut_util: work.util.util_tb generic map(clock_frequency => clock_frequency);
161
	uut_vga:  work.vga_pkg.vt100_tb generic map(clock_frequency => clock_frequency);
162

    
163
	-- The "io_pins_tb" works correctly, however GHDL 0.29, compiled under
164
	-- Windows, cannot fails to simulate this component correctly, and it
165
	-- crashes. This does not affect the Linux build of GHDL. It has
166
	-- something to do with 'Z' values for std_ulogic types.
167
	--
168

    
169
	uut_io_pins: work.util.io_pins_tb      generic map(clock_frequency => clock_frequency);
170

    
171
	uut_uart: work.uart_pkg.uart_core
172
		generic map(
173
			baud_rate            =>  uart_baud_rate,
174
			clock_frequency      =>  clock_frequency)
175
		port map(
176
			clk       =>  clk,
177
			rst       =>  rst,
178
			din       =>  din,
179
			din_stb   =>  din_stb,
180
			din_ack   =>  din_ack,
181
			tx        =>  rx,
182
			rx        =>  tx,
183
			dout_ack  =>  dout_ack,
184
			dout_stb  =>  dout_stb,
185
			dout      =>  dout);
186

    
187
------ Simulation only processes ----------------------------------------------
188
	clk_process: process
189
	begin
190
		while stop = '0' loop
191
			clk <= '1';
192
			wait for clk_period / 2;
193
			clk <= '0';
194
			wait for clk_period / 2;
195
		end loop;
196
		wait;
197
	end process;
198

    
199
	output_process: process
200
		variable oline: line;
201
		variable c: character;
202
		variable have_char: boolean := true;
203
	begin
204
		wait until configured;
205

    
206
		if not cfg.interactive then
207
			wait;
208
		end if;
209

    
210
		report "WRITING TO STDOUT";
211
		while stop = '0' loop
212
			wait until (dout_stb = '1' or stop = '1');
213
			if stop = '0' then
214
				c := character'val(to_integer(unsigned(dout)));
215
				write(oline, c);
216
				have_char := true;
217
				if dout = x"0d" then
218
					writeline(output, oline);
219
					have_char := false;
220
				end if;
221
				wait for clk_period;
222
				dout_ack <= '1';
223
				wait for clk_period;
224
				dout_ack <= '0';
225
			end if;
226
		end loop;
227
		if have_char then
228
			writeline(output, oline);
229
		end if;
230
		wait;
231
	end process;
232

    
233

    
234
	-- @note The Input and Output mechanism that allows the tester to
235
	-- interact with the running simulation needs more work, it is buggy
236
	-- and experimental, but demonstrates the principle - that a VHDL
237
	-- test bench can be interacted with at run time.
238
	input_process: process
239
		variable c: character := ' ';
240
		variable iline: line;
241
		-- variable oline: line;
242
		variable good: boolean := true;
243
	begin
244
		din_stb <= '0';
245
		din     <= x"00";
246
		wait until configured;
247
		if not cfg.interactive then
248
			din_stb <= '1';
249
			din     <= x"AA";
250
			wait;
251
		end if;
252

    
253
		report "READING FROM STDIN";
254
		while (not endfile(input)) and stop = '0' loop
255
			readline(input, iline);
256
			good := true;
257
			while good and stop = '0' loop
258
				read(iline, c, good);
259
				if good then
260
					report "" & c;
261
				end if;
262
				din <=
263
				std_ulogic_vector(to_unsigned(character'pos(c), din'length));
264
				din_stb <= '1';
265
				wait for clk_period;
266
				din_stb <= '0';
267
				assert din_ack = '1' severity warning;
268
				-- wait for 100 us;
269
				wait for 10 ms;
270
			end loop;
271
		end loop;
272
		-- stop <= '1';
273
		wait;
274
	end process;
275

    
276
	hsync_gone_high <= true when o_vga.hsync = '1' else hsync_gone_high;
277
	vsync_gone_high <= true when o_vga.vsync = '1' else vsync_gone_high;
278

    
279
	-- I/O settings go here.
280
	stimulus_process: process
281
		variable w: line;
282
		variable count: integer := 0;
283

    
284
		function stringify(slv: std_ulogic_vector) return string is
285
		begin
286
			return integer'image(to_integer(unsigned(slv)));
287
		end stringify;
288

    
289
		procedure element(l: inout line; we: boolean; name: string; slv: std_ulogic_vector) is
290
		begin
291
			if we then
292
				write(l, name & "(" & stringify(slv) & ") ");
293
			end if;
294
		end procedure;
295

    
296
		procedure element(l: inout line; name: string; slv: std_ulogic_vector) is
297
		begin
298
			element(l, true, name, slv);
299
		end procedure;
300

    
301
		function reportln(debug: cpu_debug_interface; cycles: integer) return line is
302
			variable l: line;
303
		begin
304
			write(l, integer'image(cycles) & ": ");
305
			element(l, "pc",    debug.pc);
306
			element(l, "insn",  debug.insn);
307
			element(l, "daddr", debug.daddr);
308
			element(l, "dout",  debug.dout);
309
			return l;
310
		end function;
311

    
312
		variable configuration_values: configuration_items(configuration_default'range) := configuration_default;
313
	begin
314
		-- write_configuration_tb(configuration_file_name, configuration_default);
315
		read_configuration_tb(configuration_file_name, configuration_values);
316
		cfg := set_configuration_items(configuration_values);
317
		configured <= true;
318

    
319
		rst  <= '1';
320
		wait for clk_period * 2;
321
		rst  <= '0';
322
		for i in 0 to cfg.number_of_iterations loop
323
			if cfg.verbose then
324
				if count < cfg.report_number then
325
					w := reportln(debug, count);
326
					writeline(OUTPUT, w);
327
					count := count + 1;
328
				elsif count < cfg.report_number + 1 then
329
					report "Simulation continuing: Reporting turned off";
330
					count := count + 1;
331
				end if;
332
			end if;
333
			wait for clk_period * 1;
334
		end loop;
335

    
336
		-- It would be nice to test the other peripherals as
337
		-- well, the CPU-ID should be written to the LED 7 Segment
338
		-- displays, however we only get the cathode and anode
339
		-- values out of the unit.
340

    
341
		assert hsync_gone_high report "HSYNC not active - H2 failed to initialize VGA module";
342
		assert vsync_gone_high report "VSYNC not active - H2 failed to initialize VGA module";
343

    
344
		stop   <=  '1';
345
		wait;
346
	end process;
347

    
348
end architecture;
349
------ END ---------------------------------------------------------------------
350

    
(7-7/21)