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

Subversion Repositories forth-cpu

[/] [forth-cpu/] [trunk/] [tb.vhd] - Rev 4

Go to most recent revision | Compare with Previous | Blame | View Log

-------------------------------------------------------------------------------
--| @file tb.vhd
--| @brief Main test bench.
--|
--| @author         Richard James Howe.
--| @copyright      Copyright 2013,2017 Richard James Howe.
--| @license        MIT
--| @email          howe.r.j.89@gmail.com
--|
--| This test bench does quite a lot. It is not like normal VHDL test benches
--| in the fact that it uses configurable variables that it read in from a
--| file, which it does in an awkward but usable fashion.
--|
--| It also tests multiple modules.
--|
--| @todo Optionally, read in from standard input and send the character
--| over the UART, then print out any received characters to standard out.
-------------------------------------------------------------------------------
 
library ieee,work;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.textio.all;
use work.util.all;
use work.core_pkg.all;
use work.vga_pkg.all;
use work.uart_pkg.uart_core;
 
entity tb is
end tb;
 
architecture testing of tb is
	constant clock_frequency:         positive := 100_000_000;
	constant number_of_interrupts:    positive := 8;
	constant uart_baud_rate:          positive := 115200;
	constant configuration_file_name: string   := "tb.cfg";
	constant clk_period:              time     := 1000 ms / clock_frequency;
	constant uart_tx_time:            time     := (10*1000 ms) / 115200;
 
	-- Test bench configurable options --
 
	type configurable_items is record
		number_of_iterations: positive;
		verbose:              boolean;
		report_number:        natural;
		interactive:          boolean;
	end record;
 
	function set_configuration_items(ci: configuration_items) return configurable_items is
		variable r: configurable_items;
	begin
		r.number_of_iterations := ci(0).value;
		r.verbose              := ci(1).value > 0;
		r.interactive          := ci(2).value > 0;
		r.report_number        := ci(3).value;
		return r;
	end function;
 
	constant configuration_default: configuration_items(0 to 3) := (
		(name => "Cycles  ", value => 1000),
		(name => "Verbose ", value => 1),
		(name => "Interact", value => 0),
		(name => "LogFor  ", value => 256));
 
	-- Test bench configurable options --
 
	signal stop:  std_ulogic :=  '0';
	signal debug: cpu_debug_interface;
 
	signal clk:   std_ulogic := '0';
	signal rst:   std_ulogic := '0';
 
--	signal  cpu_wait: std_ulogic := '0'; -- CPU wait flag
 
	-- Basic I/O
	signal btnu:  std_ulogic := '0';  -- button up
	signal btnd:  std_ulogic := '0';  -- button down
	signal btnc:  std_ulogic := '0';  -- button centre
	signal btnl:  std_ulogic := '0';  -- button left
	signal btnr:  std_ulogic := '0';  -- button right
	signal sw:    std_ulogic_vector(7 downto 0) := (others => '0'); -- switches
	signal an:    std_ulogic_vector(3 downto 0) := (others => '0'); -- anodes   8 segment display
	signal ka:    std_ulogic_vector(7 downto 0) := (others => '0'); -- kathodes 8 segment display
	signal ld:    std_ulogic_vector(7 downto 0) := (others => '0'); -- leds
 
	-- VGA
	signal o_vga: vga_physical_interface;
	signal hsync_gone_high: boolean := false;
	signal vsync_gone_high: boolean := false;
 
	-- HID
	signal ps2_keyboard_data: std_ulogic := '0';
	signal ps2_keyboard_clk:  std_ulogic := '0';
 
	-- UART
	signal rx:                 std_ulogic := '0';
	signal tx:                 std_ulogic := '0';
	signal dout_ack, dout_stb: std_ulogic := '0';
	signal din_ack, din_stb:   std_ulogic := '0';
	signal dout:               std_ulogic_vector(7 downto 0) := (others => '0');
	signal din:                std_ulogic_vector(7 downto 0) := (others => '0');
 
	-- Wave form generator
	signal gen_dout:     std_ulogic_vector(15 downto 0) := (others => '0');
 
	shared variable cfg: configurable_items := set_configuration_items(configuration_default);
 
	signal configured: boolean := false;
 
	signal RamCS:     std_ulogic := 'X';
	signal MemOE:     std_ulogic := 'X'; -- negative logic
	signal MemWR:     std_ulogic := 'X'; -- negative logic
	signal MemAdv:    std_ulogic := 'X'; -- negative logic
	signal MemWait:   std_ulogic := 'X'; -- positive!
	signal FlashCS:   std_ulogic := 'X';
	signal FlashRp:   std_ulogic := 'X';
	signal MemAdr:    std_ulogic_vector(26 downto 1) := (others => 'X');
	signal MemDB:     std_logic_vector(15 downto 0) := (others => 'X');
 
begin
---- Units under test ----------------------------------------------------------
 
	MemDB <= (others => '0') when MemOE = '1' else (others => 'Z');
 
	uut: entity work.top
	generic map(
		clock_frequency      => clock_frequency,
		uart_baud_rate       => uart_baud_rate)
	port map(
		debug       => debug,
		clk         => clk,
		-- rst      => rst,
		btnu        => btnu,
		btnd        => btnd,
		btnc        => btnc,
		btnl        => btnl,
		btnr        => btnr,
		sw          => sw,
		an          => an,
		ka          => ka,
		ld          => ld,
		rx          => rx,
		tx          => tx,
		o_vga       => o_vga,
 
		ps2_keyboard_data => ps2_keyboard_data,
		ps2_keyboard_clk  => ps2_keyboard_clk,
 
		RamCS    =>  RamCS,
		MemOE    =>  MemOE,
		MemWR    =>  MemWR,
		MemAdv   =>  MemAdv,
		MemWait  =>  MemWait,
		FlashCS  =>  FlashCS,
		FlashRp  =>  FlashRp,
		MemAdr   =>  MemAdr,
		MemDB    =>  MemDB);
 
	uut_util: work.util.util_tb generic map(clock_frequency => clock_frequency);
	uut_vga:  work.vga_pkg.vt100_tb generic map(clock_frequency => clock_frequency);
 
	-- The "io_pins_tb" works correctly, however GHDL 0.29, compiled under
	-- Windows, cannot fails to simulate this component correctly, and it
	-- crashes. This does not affect the Linux build of GHDL. It has
	-- something to do with 'Z' values for std_ulogic types.
	--
 
	uut_io_pins: work.util.io_pins_tb      generic map(clock_frequency => clock_frequency);
 
	uut_uart: work.uart_pkg.uart_core
		generic map(
			baud_rate            =>  uart_baud_rate,
			clock_frequency      =>  clock_frequency)
		port map(
			clk       =>  clk,
			rst       =>  rst,
			din       =>  din,
			din_stb   =>  din_stb,
			din_ack   =>  din_ack,
			tx        =>  rx,
			rx        =>  tx,
			dout_ack  =>  dout_ack,
			dout_stb  =>  dout_stb,
			dout      =>  dout);
 
------ Simulation only processes ----------------------------------------------
	clk_process: process
	begin
		while stop = '0' loop
			clk <= '1';
			wait for clk_period / 2;
			clk <= '0';
			wait for clk_period / 2;
		end loop;
		wait;
	end process;
 
	output_process: process
		variable oline: line;
		variable c: character;
		variable have_char: boolean := true;
	begin
		wait until configured;
 
		if not cfg.interactive then
			wait;
		end if;
 
		report "WRITING TO STDOUT";
		while stop = '0' loop
			wait until (dout_stb = '1' or stop = '1');
			if stop = '0' then
				c := character'val(to_integer(unsigned(dout)));
				write(oline, c);
				have_char := true;
				if dout = x"0d" then
					writeline(output, oline);
					have_char := false;
				end if;
				wait for clk_period;
				dout_ack <= '1';
				wait for clk_period;
				dout_ack <= '0';
			end if;
		end loop;
		if have_char then
			writeline(output, oline);
		end if;
		wait;
	end process;
 
 
	-- @note The Input and Output mechanism that allows the tester to
	-- interact with the running simulation needs more work, it is buggy
	-- and experimental, but demonstrates the principle - that a VHDL
	-- test bench can be interacted with at run time.
	input_process: process
		variable c: character := ' ';
		variable iline: line;
		-- variable oline: line;
		variable good: boolean := true;
	begin
		din_stb <= '0';
		din     <= x"00";
		wait until configured;
		if not cfg.interactive then
			din_stb <= '1';
			din     <= x"AA";
			wait;
		end if;
 
		report "READING FROM STDIN";
		while (not endfile(input)) and stop = '0' loop
			readline(input, iline);
			good := true;
			while good and stop = '0' loop
				read(iline, c, good);
				if good then
					report "" & c;
				end if;
				din <=
				std_ulogic_vector(to_unsigned(character'pos(c), din'length));
				din_stb <= '1';
				wait for clk_period;
				din_stb <= '0';
				assert din_ack = '1' severity warning;
				-- wait for 100 us;
				wait for 10 ms;
			end loop;
		end loop;
		-- stop <= '1';
		wait;
	end process;
 
	hsync_gone_high <= true when o_vga.hsync = '1' else hsync_gone_high;
	vsync_gone_high <= true when o_vga.vsync = '1' else vsync_gone_high;
 
	-- I/O settings go here.
	stimulus_process: process
		variable w: line;
		variable count: integer := 0;
 
		function stringify(slv: std_ulogic_vector) return string is
		begin
			return integer'image(to_integer(unsigned(slv)));
		end stringify;
 
		procedure element(l: inout line; we: boolean; name: string; slv: std_ulogic_vector) is
		begin
			if we then
				write(l, name & "(" & stringify(slv) & ") ");
			end if;
		end procedure;
 
		procedure element(l: inout line; name: string; slv: std_ulogic_vector) is
		begin
			element(l, true, name, slv);
		end procedure;
 
		function reportln(debug: cpu_debug_interface; cycles: integer) return line is
			variable l: line;
		begin
			write(l, integer'image(cycles) & ": ");
			element(l, "pc",    debug.pc);
			element(l, "insn",  debug.insn);
			element(l, "daddr", debug.daddr);
			element(l, "dout",  debug.dout);
			return l;
		end function;
 
		variable configuration_values: configuration_items(configuration_default'range) := configuration_default;
	begin
		-- write_configuration_tb(configuration_file_name, configuration_default);
		read_configuration_tb(configuration_file_name, configuration_values);
		cfg := set_configuration_items(configuration_values);
		configured <= true;
 
		rst  <= '1';
		wait for clk_period * 2;
		rst  <= '0';
		for i in 0 to cfg.number_of_iterations loop
			if cfg.verbose then
				if count < cfg.report_number then
					w := reportln(debug, count);
					writeline(OUTPUT, w);
					count := count + 1;
				elsif count < cfg.report_number + 1 then
					report "Simulation continuing: Reporting turned off";
					count := count + 1;
				end if;
			end if;
			wait for clk_period * 1;
		end loop;
 
		-- It would be nice to test the other peripherals as
		-- well, the CPU-ID should be written to the LED 7 Segment
		-- displays, however we only get the cathode and anode
		-- values out of the unit.
 
		assert hsync_gone_high report "HSYNC not active - H2 failed to initialize VGA module";
		assert vsync_gone_high report "VSYNC not active - H2 failed to initialize VGA module";
 
		stop   <=  '1';
		wait;
	end process;
 
end architecture;
------ END ---------------------------------------------------------------------
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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