OpenCores
URL https://opencores.org/ocsvn/forth-cpu/forth-cpu/trunk

Subversion Repositories forth-cpu

[/] [forth-cpu/] [trunk/] [tb.vhd] - Blame information for rev 5

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 howe.r.j.8
-------------------------------------------------------------------------------
2
--| @file tb.vhd
3
--| @brief Main test bench.
4
--|
5
--| @author         Richard James Howe.
6 5 howe.r.j.8
--| @copyright      Copyright 2013-2019 Richard James Howe.
7 3 howe.r.j.8
--| @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 5 howe.r.j.8
--| in the fact that it uses configurable variables that it reads in from a
12
--| file, which it does in an awkward but usable fashion. It also has a
13
--| partially working way of connecting a simulated UART to STDIN/STDOUT, which
14
--| is a work in progress.
15 3 howe.r.j.8
--|
16
--| It also tests multiple modules.
17
--|
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
 
29
entity tb is
30
end tb;
31
 
32
architecture testing of tb is
33 5 howe.r.j.8
        constant g: common_generics := (
34
                clock_frequency    => 100_000_000,
35
                asynchronous_reset => true,
36
                delay              => 0 ns);
37
 
38 3 howe.r.j.8
        constant number_of_interrupts:    positive := 8;
39 5 howe.r.j.8
        constant uart_baud:               positive := 115200;
40 3 howe.r.j.8
        constant configuration_file_name: string   := "tb.cfg";
41
        constant uart_tx_time:            time     := (10*1000 ms) / 115200;
42 5 howe.r.j.8
        constant uart_default_input:      std_ulogic_vector(7 downto 0) := x"AA";
43
        constant reset_period_us:         natural  := 1;
44
        constant jitter_on:               boolean  := false;
45
        constant clock_period:            time     := 1000 ms / g.clock_frequency;
46
        constant tb_vga_on:               boolean  := false;
47
        constant tb_uart_on:              boolean  := false;
48
        constant tb_util_on:              boolean  := false;
49 3 howe.r.j.8
 
50
        -- Test bench configurable options --
51
 
52
        type configurable_items is record
53 5 howe.r.j.8
                number_of_iterations: natural; -- 0 == loop forever
54 3 howe.r.j.8
                verbose:              boolean;
55
                report_number:        natural;
56
                interactive:          boolean;
57 5 howe.r.j.8
                input_wait_for:       time;
58 3 howe.r.j.8
        end record;
59
 
60
        function set_configuration_items(ci: configuration_items) return configurable_items is
61
                variable r: configurable_items;
62
        begin
63
                r.number_of_iterations := ci(0).value;
64
                r.verbose              := ci(1).value > 0;
65
                r.interactive          := ci(2).value > 0;
66 5 howe.r.j.8
                r.input_wait_for       := ci(3).value * 1 ms;
67
                r.report_number        := ci(4).value;
68 3 howe.r.j.8
                return r;
69
        end function;
70
 
71 5 howe.r.j.8
        constant configuration_default: configuration_items(0 to 4) := (
72 3 howe.r.j.8
                (name => "Cycles  ", value => 1000),
73
                (name => "Verbose ", value => 1),
74
                (name => "Interact", value => 0),
75 5 howe.r.j.8
                (name => "InWaitMs", value => 8),
76 3 howe.r.j.8
                (name => "LogFor  ", value => 256));
77
 
78
        -- Test bench configurable options --
79
 
80 5 howe.r.j.8
        signal stop:  boolean := false;
81
        signal dbgi:  cpu_debug_interface;
82 3 howe.r.j.8
 
83 5 howe.r.j.8
        signal clk:          std_ulogic := '0';
84
        signal rst:          std_ulogic := '0';
85 3 howe.r.j.8
 
86
        -- Basic I/O
87
        signal btnu:  std_ulogic := '0';  -- button up
88
        signal btnd:  std_ulogic := '0';  -- button down
89
        signal btnc:  std_ulogic := '0';  -- button centre
90
        signal btnl:  std_ulogic := '0';  -- button left
91
        signal btnr:  std_ulogic := '0';  -- button right
92
        signal sw:    std_ulogic_vector(7 downto 0) := (others => '0'); -- switches
93
        signal an:    std_ulogic_vector(3 downto 0) := (others => '0'); -- anodes   8 segment display
94
        signal ka:    std_ulogic_vector(7 downto 0) := (others => '0'); -- kathodes 8 segment display
95
        signal ld:    std_ulogic_vector(7 downto 0) := (others => '0'); -- leds
96
 
97
        -- VGA
98
        signal o_vga: vga_physical_interface;
99
        signal hsync_gone_high: boolean := false;
100
        signal vsync_gone_high: boolean := false;
101
 
102
        -- HID
103
        signal ps2_keyboard_data: std_ulogic := '0';
104
        signal ps2_keyboard_clk:  std_ulogic := '0';
105
 
106
        -- UART
107
        signal rx:                 std_ulogic := '0';
108
        signal tx:                 std_ulogic := '0';
109
        signal dout_ack, dout_stb: std_ulogic := '0';
110
        signal din_ack, din_stb:   std_ulogic := '0';
111
        signal dout:               std_ulogic_vector(7 downto 0) := (others => '0');
112
        signal din:                std_ulogic_vector(7 downto 0) := (others => '0');
113
 
114
        -- Wave form generator
115
        signal gen_dout:     std_ulogic_vector(15 downto 0) := (others => '0');
116
 
117
        shared variable cfg: configurable_items := set_configuration_items(configuration_default);
118
 
119
        signal configured: boolean := false;
120
 
121 5 howe.r.j.8
        signal ram_cs:     std_ulogic := 'X';
122
        signal mem_oe:     std_ulogic := 'X'; -- negative logic
123
        signal mem_wr:     std_ulogic := 'X'; -- negative logic
124
        signal mem_adv:    std_ulogic := 'X'; -- negative logic
125
        signal mem_wait:   std_ulogic := 'X'; -- positive!
126
        signal flash_cs:   std_ulogic := 'X';
127
        signal flash_rp:   std_ulogic := 'X';
128
        signal mem_addr:   std_ulogic_vector(26 downto 1) := (others => 'X');
129
        signal mem_data:   std_logic_vector(15 downto 0)  := (others => 'X');
130 3 howe.r.j.8
 
131
begin
132
---- Units under test ----------------------------------------------------------
133
 
134 5 howe.r.j.8
        mem_data <= (others => '0') when mem_oe = '1' else (others => 'Z');
135 3 howe.r.j.8
 
136
        uut: entity work.top
137
        generic map(
138 5 howe.r.j.8
                g               => g,
139
                reset_period_us => reset_period_us,
140
                uart_baud  => uart_baud)
141 3 howe.r.j.8
        port map(
142 5 howe.r.j.8
                debug       => dbgi,
143 3 howe.r.j.8
                clk         => clk,
144
                -- rst      => rst,
145
                btnu        => btnu,
146
                btnd        => btnd,
147
                btnc        => btnc,
148
                btnl        => btnl,
149
                btnr        => btnr,
150
                sw          => sw,
151
                an          => an,
152
                ka          => ka,
153
                ld          => ld,
154
                rx          => rx,
155
                tx          => tx,
156
                o_vga       => o_vga,
157
 
158
                ps2_keyboard_data => ps2_keyboard_data,
159
                ps2_keyboard_clk  => ps2_keyboard_clk,
160
 
161 5 howe.r.j.8
                ram_cs    =>  ram_cs,
162
                mem_oe    =>  mem_oe,
163
                mem_wr    =>  mem_wr,
164
                mem_adv   =>  mem_adv,
165
                mem_wait  =>  mem_wait,
166
                flash_cs  =>  flash_cs,
167
                flash_rp  =>  flash_rp,
168
                mem_addr  =>  mem_addr,
169
                mem_data  =>  mem_data);
170 3 howe.r.j.8
 
171 5 howe.r.j.8
        -- NB. It would be nice to configure these as off/on, as well as
172
        -- controlling how long they run for from here.
173
        util_g: if tb_util_on generate uut_util: work.util.util_tb     generic map(g => g); end generate;
174
        vga_g:  if tb_vga_on  generate uut_vga:  work.vga_pkg.vt100_tb generic map(g => g); end generate;
175
        uart_g: if tb_uart_on generate uut_uart: work.uart_pkg.uart_tb generic map(g => g); end generate;
176 3 howe.r.j.8
 
177 5 howe.r.j.8
        uart_0_blk: block
178
                signal uart_clock_rx_we, uart_clock_tx_we, uart_control_we: std_ulogic := '0';
179
                signal uart_reg: std_ulogic_vector(15 downto 0);
180
        begin
181
                uart_0: work.uart_pkg.uart_core
182
                        generic map (g => g, baud => uart_baud)
183
                        port map (
184
                                clk   => clk,
185
                                rst   => rst,
186
                                tx_di => din,
187
                                tx_we => din_stb,
188
                                tx_ok => din_ack,
189
                                tx    => rx,
190
 
191
                                rx    => tx,
192
                                rx_ok => open,
193
                                rx_nd => dout_stb,
194
                                rx_do => dout,
195
                                rx_re => dout_ack,
196
 
197
                                reg             => uart_reg,
198
                                clock_reg_tx_we => uart_clock_tx_we,
199
                                clock_reg_rx_we => uart_clock_rx_we,
200
                                control_reg_we  => uart_control_we);
201
        end block;
202 3 howe.r.j.8
 
203
------ Simulation only processes ----------------------------------------------
204
        clk_process: process
205 5 howe.r.j.8
                variable seed1, seed2 : positive;
206
                variable r : real;
207
                variable jit_high, jit_low: time  := 0 ns;
208 3 howe.r.j.8
        begin
209 5 howe.r.j.8
                while not stop loop
210
                        if jitter_on then
211
                                uniform(seed1, seed2, r);
212
                                jit_high := r * g.delay;
213
                                uniform(seed1, seed2, r);
214
                                jit_low := r * g.delay;
215
                                uniform(seed1, seed2, r);
216
                                if r < 0.5 then jit_high := -jit_high; end if;
217
                                uniform(seed1, seed2, r);
218
                                if r < 0.5 then jit_low := -jit_low; end if;
219
                        else
220
                                jit_high := 0 ns;
221
                                jit_low  := 0 ns;
222
                        end if;
223 3 howe.r.j.8
                        clk <= '1';
224 5 howe.r.j.8
                        wait for (clock_period / 2) + jit_high;
225 3 howe.r.j.8
                        clk <= '0';
226 5 howe.r.j.8
                        wait for (clock_period / 2) + jit_low;
227 3 howe.r.j.8
                end loop;
228 5 howe.r.j.8
                report "clk_process end";
229 3 howe.r.j.8
                wait;
230
        end process;
231
 
232
        output_process: process
233
                variable oline: line;
234
                variable c: character;
235
                variable have_char: boolean := true;
236
        begin
237
                wait until configured;
238
 
239
                if not cfg.interactive then
240 5 howe.r.j.8
                        report "Output turned off";
241
                        report "output_process end";
242 3 howe.r.j.8
                        wait;
243
                end if;
244
 
245 5 howe.r.j.8
                report "Writing to STDOUT";
246
                while not stop loop
247
                        wait until (dout_stb = '1' or stop);
248
                        if not stop then
249 3 howe.r.j.8
                                c := character'val(to_integer(unsigned(dout)));
250
                                write(oline, c);
251
                                have_char := true;
252
                                if dout = x"0d" then
253
                                        writeline(output, oline);
254
                                        have_char := false;
255
                                end if;
256 5 howe.r.j.8
                                wait for clock_period;
257 3 howe.r.j.8
                                dout_ack <= '1';
258 5 howe.r.j.8
                                wait for clock_period;
259 3 howe.r.j.8
                                dout_ack <= '0';
260
                        end if;
261
                end loop;
262
                if have_char then
263
                        writeline(output, oline);
264
                end if;
265 5 howe.r.j.8
                report "output_process end";
266 3 howe.r.j.8
                wait;
267
        end process;
268
 
269
 
270 5 howe.r.j.8
        -- The Input and Output mechanism that allows the tester to
271 3 howe.r.j.8
        -- interact with the running simulation needs more work, it is buggy
272
        -- and experimental, but demonstrates the principle - that a VHDL
273
        -- test bench can be interacted with at run time.
274
        input_process: process
275
                variable c: character := ' ';
276
                variable iline: line;
277
                -- variable oline: line;
278
                variable good: boolean := true;
279 5 howe.r.j.8
                variable eoi:  boolean := false;
280 3 howe.r.j.8
        begin
281
                din_stb <= '0';
282
                din     <= x"00";
283
                wait until configured;
284
                if not cfg.interactive then
285
                        din_stb <= '1';
286 5 howe.r.j.8
                        din     <= uart_default_input;
287
                        report "input process non-interactive";
288
                        report "input_process end";
289 3 howe.r.j.8
                        wait;
290
                end if;
291
 
292 5 howe.r.j.8
                report "Waiting for " & time'image(cfg.input_wait_for) & " (before reading from STDIN)";
293
                wait for cfg.input_wait_for;
294
                report "Reading from STDIN (Hit EOF/CTRL-D/CTRL-Z After entering a line)";
295
                while (not endfile(input)) and not stop and eoi = false loop
296
                        report "readline...";
297 3 howe.r.j.8
                        readline(input, iline);
298
                        good := true;
299 5 howe.r.j.8
                        while good and not stop loop
300 3 howe.r.j.8
                                read(iline, c, good);
301
                                if good then
302
                                        report "" & c;
303 5 howe.r.j.8
                                else
304
                                        report "EOL/EOI";
305
                                        c   := LF;
306
                                        eoi := true;
307 3 howe.r.j.8
                                end if;
308 5 howe.r.j.8
                                din <= std_ulogic_vector(to_unsigned(character'pos(c), din'length));
309 3 howe.r.j.8
                                din_stb <= '1';
310 5 howe.r.j.8
                                wait for clock_period;
311 3 howe.r.j.8
                                din_stb <= '0';
312 5 howe.r.j.8
                                wait for 100 us;
313 3 howe.r.j.8
                        end loop;
314
                end loop;
315 5 howe.r.j.8
                report "input_process end";
316 3 howe.r.j.8
                wait;
317
        end process;
318
 
319
        hsync_gone_high <= true when o_vga.hsync = '1' else hsync_gone_high;
320
        vsync_gone_high <= true when o_vga.vsync = '1' else vsync_gone_high;
321
 
322
        -- I/O settings go here.
323
        stimulus_process: process
324
                variable w: line;
325
                variable count: integer := 0;
326
 
327
                function stringify(slv: std_ulogic_vector) return string is
328
                begin
329
                        return integer'image(to_integer(unsigned(slv)));
330
                end stringify;
331
 
332
                procedure element(l: inout line; we: boolean; name: string; slv: std_ulogic_vector) is
333
                begin
334
                        if we then
335
                                write(l, name & "(" & stringify(slv) & ") ");
336
                        end if;
337
                end procedure;
338
 
339
                procedure element(l: inout line; name: string; slv: std_ulogic_vector) is
340
                begin
341
                        element(l, true, name, slv);
342
                end procedure;
343
 
344
                function reportln(debug: cpu_debug_interface; cycles: integer) return line is
345
                        variable l: line;
346
                begin
347
                        write(l, integer'image(cycles) & ": ");
348
                        element(l, "pc",    debug.pc);
349
                        element(l, "insn",  debug.insn);
350
                        element(l, "daddr", debug.daddr);
351
                        element(l, "dout",  debug.dout);
352
                        return l;
353
                end function;
354
 
355
                variable configuration_values: configuration_items(configuration_default'range) := configuration_default;
356
        begin
357
                -- write_configuration_tb(configuration_file_name, configuration_default);
358
                read_configuration_tb(configuration_file_name, configuration_values);
359
                cfg := set_configuration_items(configuration_values);
360
                configured <= true;
361
 
362
                rst  <= '1';
363 5 howe.r.j.8
                wait for clock_period * 2;
364 3 howe.r.j.8
                rst  <= '0';
365 5 howe.r.j.8
 
366
                if cfg.number_of_iterations = 0 then
367
                        report "RUNNING FOREVER: number of iterations is zero" severity warning;
368
                        report "stimulus_process end";
369
                        wait;
370
                end if;
371
 
372 3 howe.r.j.8
                for i in 0 to cfg.number_of_iterations loop
373
                        if cfg.verbose then
374
                                if count < cfg.report_number then
375 5 howe.r.j.8
                                        w := reportln(dbgi, count);
376 3 howe.r.j.8
                                        writeline(OUTPUT, w);
377
                                        count := count + 1;
378
                                elsif count < cfg.report_number + 1 then
379
                                        report "Simulation continuing: Reporting turned off";
380
                                        count := count + 1;
381
                                end if;
382
                        end if;
383 5 howe.r.j.8
                        wait for clock_period * 1;
384 3 howe.r.j.8
                end loop;
385
 
386 5 howe.r.j.8
                -- These HSYNC and VSYNC asserts are included under the assumption
387
                -- that the image running on the H2 CPU will initiate the VGA, if
388
                -- it does not (perhaps because it is running it's own initialization
389
                -- routines), then the HSYNC or VSYNC will never go high - so this is
390
                -- not necessarily an error.
391
                --
392 3 howe.r.j.8
                -- It would be nice to test the other peripherals as
393
                -- well, the CPU-ID should be written to the LED 7 Segment
394
                -- displays, however we only get the cathode and anode
395
                -- values out of the unit.
396
 
397
                assert hsync_gone_high report "HSYNC not active - H2 failed to initialize VGA module";
398
                assert vsync_gone_high report "VSYNC not active - H2 failed to initialize VGA module";
399
 
400 5 howe.r.j.8
                stop   <=  true;
401
                report "stimulus_process end";
402 3 howe.r.j.8
                wait;
403
        end process;
404
 
405
end architecture;
406
------ END ---------------------------------------------------------------------
407
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.