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