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

Subversion Repositories forth-cpu

[/] [forth-cpu/] [trunk/] [tb.vhd] - Diff between revs 3 and 5

Show entire file | Details | Blame | View Log

Rev 3 Rev 5
Line 1... Line 1...
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
--| @file tb.vhd
--| @file tb.vhd
--| @brief Main test bench.
--| @brief Main test bench.
--|
--|
--| @author         Richard James Howe.
--| @author         Richard James Howe.
--| @copyright      Copyright 2013,2017 Richard James Howe.
--| @copyright      Copyright 2013-2019 Richard James Howe.
--| @license        MIT
--| @license        MIT
--| @email          howe.r.j.89@gmail.com
--| @email          howe.r.j.89@gmail.com
--|
--|
--| This test bench does quite a lot. It is not like normal VHDL test benches
--| 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
--| in the fact that it uses configurable variables that it reads in from a
--| file, which it does in an awkward but usable fashion.
--| file, which it does in an awkward but usable fashion. It also has a
 
--| partially working way of connecting a simulated UART to STDIN/STDOUT, which
 
--| is a work in progress.
--|
--|
--| It also tests multiple modules.
--| 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;
library ieee,work;
use ieee.std_logic_1164.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use ieee.math_real.all;
use std.textio.all;
use std.textio.all;
use work.util.all;
use work.util.all;
use work.core_pkg.all;
use work.core_pkg.all;
use work.vga_pkg.all;
use work.vga_pkg.all;
use work.uart_pkg.uart_core;
 
 
 
entity tb is
entity tb is
end tb;
end tb;
 
 
architecture testing of tb is
architecture testing of tb is
        constant clock_frequency:         positive := 100_000_000;
        constant g: common_generics := (
 
                clock_frequency    => 100_000_000,
 
                asynchronous_reset => true,
 
                delay              => 0 ns);
 
 
        constant number_of_interrupts:    positive := 8;
        constant number_of_interrupts:    positive := 8;
        constant uart_baud_rate:          positive := 115200;
        constant uart_baud:               positive := 115200;
        constant configuration_file_name: string   := "tb.cfg";
        constant configuration_file_name: string   := "tb.cfg";
        constant clk_period:              time     := 1000 ms / clock_frequency;
 
        constant uart_tx_time:            time     := (10*1000 ms) / 115200;
        constant uart_tx_time:            time     := (10*1000 ms) / 115200;
 
        constant uart_default_input:      std_ulogic_vector(7 downto 0) := x"AA";
 
        constant reset_period_us:         natural  := 1;
 
        constant jitter_on:               boolean  := false;
 
        constant clock_period:            time     := 1000 ms / g.clock_frequency;
 
        constant tb_vga_on:               boolean  := false;
 
        constant tb_uart_on:              boolean  := false;
 
        constant tb_util_on:              boolean  := false;
 
 
        -- Test bench configurable options --
        -- Test bench configurable options --
 
 
        type configurable_items is record
        type configurable_items is record
                number_of_iterations: positive;
                number_of_iterations: natural; -- 0 == loop forever
                verbose:              boolean;
                verbose:              boolean;
                report_number:        natural;
                report_number:        natural;
                interactive:          boolean;
                interactive:          boolean;
 
                input_wait_for:       time;
        end record;
        end record;
 
 
        function set_configuration_items(ci: configuration_items) return configurable_items is
        function set_configuration_items(ci: configuration_items) return configurable_items is
                variable r: configurable_items;
                variable r: configurable_items;
        begin
        begin
                r.number_of_iterations := ci(0).value;
                r.number_of_iterations := ci(0).value;
                r.verbose              := ci(1).value > 0;
                r.verbose              := ci(1).value > 0;
                r.interactive          := ci(2).value > 0;
                r.interactive          := ci(2).value > 0;
                r.report_number        := ci(3).value;
                r.input_wait_for       := ci(3).value * 1 ms;
 
                r.report_number        := ci(4).value;
                return r;
                return r;
        end function;
        end function;
 
 
        constant configuration_default: configuration_items(0 to 3) := (
        constant configuration_default: configuration_items(0 to 4) := (
                (name => "Cycles  ", value => 1000),
                (name => "Cycles  ", value => 1000),
                (name => "Verbose ", value => 1),
                (name => "Verbose ", value => 1),
                (name => "Interact", value => 0),
                (name => "Interact", value => 0),
 
                (name => "InWaitMs", value => 8),
                (name => "LogFor  ", value => 256));
                (name => "LogFor  ", value => 256));
 
 
        -- Test bench configurable options --
        -- Test bench configurable options --
 
 
        signal stop:  std_ulogic :=  '0';
        signal stop:  boolean := false;
        signal debug: cpu_debug_interface;
        signal dbgi:  cpu_debug_interface;
 
 
        signal clk:   std_ulogic := '0';
        signal clk:   std_ulogic := '0';
        signal rst:   std_ulogic := '0';
        signal rst:   std_ulogic := '0';
 
 
--      signal  cpu_wait: std_ulogic := '0'; -- CPU wait flag
 
 
 
        -- Basic I/O
        -- Basic I/O
        signal btnu:  std_ulogic := '0';  -- button up
        signal btnu:  std_ulogic := '0';  -- button up
        signal btnd:  std_ulogic := '0';  -- button down
        signal btnd:  std_ulogic := '0';  -- button down
        signal btnc:  std_ulogic := '0';  -- button centre
        signal btnc:  std_ulogic := '0';  -- button centre
        signal btnl:  std_ulogic := '0';  -- button left
        signal btnl:  std_ulogic := '0';  -- button left
Line 106... Line 116...
 
 
        shared variable cfg: configurable_items := set_configuration_items(configuration_default);
        shared variable cfg: configurable_items := set_configuration_items(configuration_default);
 
 
        signal configured: boolean := false;
        signal configured: boolean := false;
 
 
        signal RamCS:     std_ulogic := 'X';
        signal ram_cs:     std_ulogic := 'X';
        signal MemOE:     std_ulogic := 'X'; -- negative logic
        signal mem_oe:     std_ulogic := 'X'; -- negative logic
        signal MemWR:     std_ulogic := 'X'; -- negative logic
        signal mem_wr:     std_ulogic := 'X'; -- negative logic
        signal MemAdv:    std_ulogic := 'X'; -- negative logic
        signal mem_adv:    std_ulogic := 'X'; -- negative logic
        signal MemWait:   std_ulogic := 'X'; -- positive!
        signal mem_wait:   std_ulogic := 'X'; -- positive!
        signal FlashCS:   std_ulogic := 'X';
        signal flash_cs:   std_ulogic := 'X';
        signal FlashRp:   std_ulogic := 'X';
        signal flash_rp:   std_ulogic := 'X';
        signal MemAdr:    std_ulogic_vector(26 downto 1) := (others => 'X');
        signal mem_addr:   std_ulogic_vector(26 downto 1) := (others => 'X');
        signal MemDB:     std_logic_vector(15 downto 0) := (others => 'X');
        signal mem_data:   std_logic_vector(15 downto 0)  := (others => 'X');
 
 
begin
begin
---- Units under test ----------------------------------------------------------
---- Units under test ----------------------------------------------------------
 
 
        MemDB <= (others => '0') when MemOE = '1' else (others => 'Z');
        mem_data <= (others => '0') when mem_oe = '1' else (others => 'Z');
 
 
        uut: entity work.top
        uut: entity work.top
        generic map(
        generic map(
                clock_frequency      => clock_frequency,
                g               => g,
                uart_baud_rate       => uart_baud_rate)
                reset_period_us => reset_period_us,
 
                uart_baud  => uart_baud)
        port map(
        port map(
                debug       => debug,
                debug       => dbgi,
                clk         => clk,
                clk         => clk,
                -- rst      => rst,
                -- rst      => rst,
                btnu        => btnu,
                btnu        => btnu,
                btnd        => btnd,
                btnd        => btnd,
                btnc        => btnc,
                btnc        => btnc,
Line 145... Line 156...
                o_vga       => o_vga,
                o_vga       => o_vga,
 
 
                ps2_keyboard_data => ps2_keyboard_data,
                ps2_keyboard_data => ps2_keyboard_data,
                ps2_keyboard_clk  => ps2_keyboard_clk,
                ps2_keyboard_clk  => ps2_keyboard_clk,
 
 
                RamCS    =>  RamCS,
                ram_cs    =>  ram_cs,
                MemOE    =>  MemOE,
                mem_oe    =>  mem_oe,
                MemWR    =>  MemWR,
                mem_wr    =>  mem_wr,
                MemAdv   =>  MemAdv,
                mem_adv   =>  mem_adv,
                MemWait  =>  MemWait,
                mem_wait  =>  mem_wait,
                FlashCS  =>  FlashCS,
                flash_cs  =>  flash_cs,
                FlashRp  =>  FlashRp,
                flash_rp  =>  flash_rp,
                MemAdr   =>  MemAdr,
                mem_addr  =>  mem_addr,
                MemDB    =>  MemDB);
                mem_data  =>  mem_data);
 
 
        uut_util: work.util.util_tb generic map(clock_frequency => clock_frequency);
        -- NB. It would be nice to configure these as off/on, as well as
        uut_vga:  work.vga_pkg.vt100_tb generic map(clock_frequency => clock_frequency);
        -- controlling how long they run for from here.
 
        util_g: if tb_util_on generate uut_util: work.util.util_tb     generic map(g => g); end generate;
        -- The "io_pins_tb" works correctly, however GHDL 0.29, compiled under
        vga_g:  if tb_vga_on  generate uut_vga:  work.vga_pkg.vt100_tb generic map(g => g); end generate;
        -- Windows, cannot fails to simulate this component correctly, and it
        uart_g: if tb_uart_on generate uut_uart: work.uart_pkg.uart_tb generic map(g => g); end generate;
        -- crashes. This does not affect the Linux build of GHDL. It has
 
        -- something to do with 'Z' values for std_ulogic types.
        uart_0_blk: block
        --
                signal uart_clock_rx_we, uart_clock_tx_we, uart_control_we: std_ulogic := '0';
 
                signal uart_reg: std_ulogic_vector(15 downto 0);
        uut_io_pins: work.util.io_pins_tb      generic map(clock_frequency => clock_frequency);
        begin
 
                uart_0: work.uart_pkg.uart_core
        uut_uart: work.uart_pkg.uart_core
                        generic map (g => g, baud => uart_baud)
                generic map(
 
                        baud_rate            =>  uart_baud_rate,
 
                        clock_frequency      =>  clock_frequency)
 
                port map(
                port map(
                        clk       =>  clk,
                        clk       =>  clk,
                        rst       =>  rst,
                        rst       =>  rst,
                        din       =>  din,
                                tx_di => din,
                        din_stb   =>  din_stb,
                                tx_we => din_stb,
                        din_ack   =>  din_ack,
                                tx_ok => din_ack,
                        tx        =>  rx,
                        tx        =>  rx,
 
 
                        rx        =>  tx,
                        rx        =>  tx,
                        dout_ack  =>  dout_ack,
                                rx_ok => open,
                        dout_stb  =>  dout_stb,
                                rx_nd => dout_stb,
                        dout      =>  dout);
                                rx_do => dout,
 
                                rx_re => dout_ack,
 
 
 
                                reg             => uart_reg,
 
                                clock_reg_tx_we => uart_clock_tx_we,
 
                                clock_reg_rx_we => uart_clock_rx_we,
 
                                control_reg_we  => uart_control_we);
 
        end block;
 
 
------ Simulation only processes ----------------------------------------------
------ Simulation only processes ----------------------------------------------
        clk_process: process
        clk_process: process
 
                variable seed1, seed2 : positive;
 
                variable r : real;
 
                variable jit_high, jit_low: time  := 0 ns;
        begin
        begin
                while stop = '0' loop
                while not stop loop
 
                        if jitter_on then
 
                                uniform(seed1, seed2, r);
 
                                jit_high := r * g.delay;
 
                                uniform(seed1, seed2, r);
 
                                jit_low := r * g.delay;
 
                                uniform(seed1, seed2, r);
 
                                if r < 0.5 then jit_high := -jit_high; end if;
 
                                uniform(seed1, seed2, r);
 
                                if r < 0.5 then jit_low := -jit_low; end if;
 
                        else
 
                                jit_high := 0 ns;
 
                                jit_low  := 0 ns;
 
                        end if;
                        clk <= '1';
                        clk <= '1';
                        wait for clk_period / 2;
                        wait for (clock_period / 2) + jit_high;
                        clk <= '0';
                        clk <= '0';
                        wait for clk_period / 2;
                        wait for (clock_period / 2) + jit_low;
                end loop;
                end loop;
 
                report "clk_process end";
                wait;
                wait;
        end process;
        end process;
 
 
        output_process: process
        output_process: process
                variable oline: line;
                variable oline: line;
Line 202... Line 235...
                variable have_char: boolean := true;
                variable have_char: boolean := true;
        begin
        begin
                wait until configured;
                wait until configured;
 
 
                if not cfg.interactive then
                if not cfg.interactive then
 
                        report "Output turned off";
 
                        report "output_process end";
                        wait;
                        wait;
                end if;
                end if;
 
 
                report "WRITING TO STDOUT";
                report "Writing to STDOUT";
                while stop = '0' loop
                while not stop loop
                        wait until (dout_stb = '1' or stop = '1');
                        wait until (dout_stb = '1' or stop);
                        if stop = '0' then
                        if not stop then
                                c := character'val(to_integer(unsigned(dout)));
                                c := character'val(to_integer(unsigned(dout)));
                                write(oline, c);
                                write(oline, c);
                                have_char := true;
                                have_char := true;
                                if dout = x"0d" then
                                if dout = x"0d" then
                                        writeline(output, oline);
                                        writeline(output, oline);
                                        have_char := false;
                                        have_char := false;
                                end if;
                                end if;
                                wait for clk_period;
                                wait for clock_period;
                                dout_ack <= '1';
                                dout_ack <= '1';
                                wait for clk_period;
                                wait for clock_period;
                                dout_ack <= '0';
                                dout_ack <= '0';
                        end if;
                        end if;
                end loop;
                end loop;
                if have_char then
                if have_char then
                        writeline(output, oline);
                        writeline(output, oline);
                end if;
                end if;
 
                report "output_process end";
                wait;
                wait;
        end process;
        end process;
 
 
 
 
        -- @note The Input and Output mechanism that allows the tester to
        -- The Input and Output mechanism that allows the tester to
        -- interact with the running simulation needs more work, it is buggy
        -- interact with the running simulation needs more work, it is buggy
        -- and experimental, but demonstrates the principle - that a VHDL
        -- and experimental, but demonstrates the principle - that a VHDL
        -- test bench can be interacted with at run time.
        -- test bench can be interacted with at run time.
        input_process: process
        input_process: process
                variable c: character := ' ';
                variable c: character := ' ';
                variable iline: line;
                variable iline: line;
                -- variable oline: line;
                -- variable oline: line;
                variable good: boolean := true;
                variable good: boolean := true;
 
                variable eoi:  boolean := false;
        begin
        begin
                din_stb <= '0';
                din_stb <= '0';
                din     <= x"00";
                din     <= x"00";
                wait until configured;
                wait until configured;
                if not cfg.interactive then
                if not cfg.interactive then
                        din_stb <= '1';
                        din_stb <= '1';
                        din     <= x"AA";
                        din     <= uart_default_input;
 
                        report "input process non-interactive";
 
                        report "input_process end";
                        wait;
                        wait;
                end if;
                end if;
 
 
                report "READING FROM STDIN";
                report "Waiting for " & time'image(cfg.input_wait_for) & " (before reading from STDIN)";
                while (not endfile(input)) and stop = '0' loop
                wait for cfg.input_wait_for;
 
                report "Reading from STDIN (Hit EOF/CTRL-D/CTRL-Z After entering a line)";
 
                while (not endfile(input)) and not stop and eoi = false loop
 
                        report "readline...";
                        readline(input, iline);
                        readline(input, iline);
                        good := true;
                        good := true;
                        while good and stop = '0' loop
                        while good and not stop loop
                                read(iline, c, good);
                                read(iline, c, good);
                                if good then
                                if good then
                                        report "" & c;
                                        report "" & c;
 
                                else
 
                                        report "EOL/EOI";
 
                                        c   := LF;
 
                                        eoi := true;
                                end if;
                                end if;
                                din <=
                                din <= std_ulogic_vector(to_unsigned(character'pos(c), din'length));
                                std_ulogic_vector(to_unsigned(character'pos(c), din'length));
 
                                din_stb <= '1';
                                din_stb <= '1';
                                wait for clk_period;
                                wait for clock_period;
                                din_stb <= '0';
                                din_stb <= '0';
                                assert din_ack = '1' severity warning;
                                wait for 100 us;
                                -- wait for 100 us;
 
                                wait for 10 ms;
 
                        end loop;
                        end loop;
                end loop;
                end loop;
                -- stop <= '1';
                report "input_process end";
                wait;
                wait;
        end process;
        end process;
 
 
        hsync_gone_high <= true when o_vga.hsync = '1' else hsync_gone_high;
        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;
        vsync_gone_high <= true when o_vga.vsync = '1' else vsync_gone_high;
Line 315... Line 358...
                read_configuration_tb(configuration_file_name, configuration_values);
                read_configuration_tb(configuration_file_name, configuration_values);
                cfg := set_configuration_items(configuration_values);
                cfg := set_configuration_items(configuration_values);
                configured <= true;
                configured <= true;
 
 
                rst  <= '1';
                rst  <= '1';
                wait for clk_period * 2;
                wait for clock_period * 2;
                rst  <= '0';
                rst  <= '0';
 
 
 
                if cfg.number_of_iterations = 0 then
 
                        report "RUNNING FOREVER: number of iterations is zero" severity warning;
 
                        report "stimulus_process end";
 
                        wait;
 
                end if;
 
 
                for i in 0 to cfg.number_of_iterations loop
                for i in 0 to cfg.number_of_iterations loop
                        if cfg.verbose then
                        if cfg.verbose then
                                if count < cfg.report_number then
                                if count < cfg.report_number then
                                        w := reportln(debug, count);
                                        w := reportln(dbgi, count);
                                        writeline(OUTPUT, w);
                                        writeline(OUTPUT, w);
                                        count := count + 1;
                                        count := count + 1;
                                elsif count < cfg.report_number + 1 then
                                elsif count < cfg.report_number + 1 then
                                        report "Simulation continuing: Reporting turned off";
                                        report "Simulation continuing: Reporting turned off";
                                        count := count + 1;
                                        count := count + 1;
                                end if;
                                end if;
                        end if;
                        end if;
                        wait for clk_period * 1;
                        wait for clock_period * 1;
                end loop;
                end loop;
 
 
 
                -- These HSYNC and VSYNC asserts are included under the assumption
 
                -- that the image running on the H2 CPU will initiate the VGA, if
 
                -- it does not (perhaps because it is running it's own initialization
 
                -- routines), then the HSYNC or VSYNC will never go high - so this is
 
                -- not necessarily an error.
 
                --
                -- It would be nice to test the other peripherals as
                -- It would be nice to test the other peripherals as
                -- well, the CPU-ID should be written to the LED 7 Segment
                -- well, the CPU-ID should be written to the LED 7 Segment
                -- displays, however we only get the cathode and anode
                -- displays, however we only get the cathode and anode
                -- values out of the unit.
                -- values out of the unit.
 
 
                assert hsync_gone_high report "HSYNC not active - H2 failed to initialize VGA module";
                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";
                assert vsync_gone_high report "VSYNC not active - H2 failed to initialize VGA module";
 
 
                stop   <=  '1';
                stop   <=  true;
 
                report "stimulus_process end";
                wait;
                wait;
        end process;
        end process;
 
 
end architecture;
end architecture;
------ END ---------------------------------------------------------------------
------ END ---------------------------------------------------------------------

powered by: WebSVN 2.1.0

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