From 297d340d6a8caad49f6aaab4fad728c7171f2364 Mon Sep 17 00:00:00 2001 From: Markus Koch Date: Fri, 27 Sep 2024 14:45:07 +0200 Subject: [PATCH] fpga: bench: Add self-checking test bench for bootrom --- fpga/hdl/bench/bench_top_neorv32.vhd | 239 +++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 fpga/hdl/bench/bench_top_neorv32.vhd diff --git a/fpga/hdl/bench/bench_top_neorv32.vhd b/fpga/hdl/bench/bench_top_neorv32.vhd new file mode 100644 index 0000000..f295760 --- /dev/null +++ b/fpga/hdl/bench/bench_top_neorv32.vhd @@ -0,0 +1,239 @@ +-- -------------------------------------------------------------------------- -- +-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs -- +-- -------------------------------------------------------------------------- -- +-- VUnit test bench for the aps6404l Wishbone IF +-- -------------------------------------------------------------------------- -- +-- Author : Markus Koch +-- Contributors : None +-- License : Mozilla Public License (MPL) Version 2 +-- -------------------------------------------------------------------------- -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use std.textio.all; + +library design; +use design.all; + +library generics; +use generics.wishbone_pkg.all; + +library device_models; +use device_models.all; + +library vunit_lib; +context vunit_lib.vunit_context; + +library osvvm; +context osvvm.osvvmContext; +use osvvm.ScoreboardPkg_slv.all; + +entity bench_top_neorv32_wb is + generic( + runner_cfg : string := runner_cfg_default + ); +end entity bench_top_neorv32_wb; + +architecture RTL of bench_top_neorv32_wb is + constant UART_BAUD : integer := 250000; + signal clk_in : std_logic; + signal uart_tx : std_logic; + signal uart_rx : std_logic; + signal eth_rx_p : std_logic; + signal eth_tx_p : std_logic_vector(3 downto 0); + signal eth_tx_n : std_logic_vector(3 downto 0); + signal eth_led_green_n : std_logic; + signal eth_led_orange_n : std_logic; + signal led_user : std_logic; + signal psram_ce_n : std_logic; + signal psram_sclk : std_logic; + signal psram_sio : std_logic_vector(3 downto 0); + signal flash_ce_n : std_logic; + signal flash_sclk : std_logic; + signal flash_sio : std_logic_vector(3 downto 0); + signal pmod : std_logic_vector(7 downto 0); + + signal SB : ScoreboardIDType; + +begin + top_inst : entity design.top + generic map( + F_IN => 50000000, + F_CLK => 25000000, + F_CLK_PHY => 50000000, + UART_BAUD => UART_BAUD, + CPU => "neorv32" + ) + port map( + clk_in => clk_in, + uart_tx => uart_tx, + uart_rx => uart_rx, + eth_rx_p => eth_rx_p, + eth_tx_p => eth_tx_p, + eth_tx_n => eth_tx_n, + eth_led_green_n => eth_led_green_n, + eth_led_orange_n => eth_led_orange_n, + led_user => led_user, + psram_ce_n => psram_ce_n, + psram_sclk => psram_sclk, + psram_sio => psram_sio, + flash_ce_n => flash_ce_n, + flash_sclk => flash_sclk, + flash_sio => flash_sio, + pmod => pmod + ); + + aps6404l_inst : entity device_models.aps6404l + generic map( + LOG_EN => false + ) + port map( + ce_n => psram_ce_n, + sclk => psram_sclk, + sio => psram_sio + ); + + uart_decoder : process is + constant DELAY : time := (1 sec / UART_BAUD); + variable d : std_logic_vector(7 downto 0); + begin + wait until falling_edge(uart_tx); + wait for 0.5 * DELAY; + for i in 0 to 7 loop + wait for DELAY; + d(i) := uart_tx; + end loop; + wait for 1.0 * DELAY; + Check(SB, d); + end process uart_decoder; + + test : process is + procedure uart_tx(d : std_logic_vector(7 downto 0)) is + constant DELAY : time := (1 sec / UART_BAUD); + begin + uart_rx <= '0'; + wait for DELAY; + for i in d'low to d'high loop + uart_rx <= d(i); + wait for DELAY; + end loop; + uart_rx <= '1'; + wait for DELAY; + end procedure uart_tx; + + begin + test_runner_setup(runner, runner_cfg); + + SB <= NewID("UART RX"); + + report "Waiting for internal reset to be complete..."; + wait for 10 us; + report "Starting tests..."; + + while test_suite loop + if run("bootloader") then + uart_rx <= '1'; + wait for (1 sec / UART_BAUD) * 10; + + report ("Writing ABCD+jalr0 to RAM..."); + -- WRITE + uart_tx(x"01"); + + -- to RAM + uart_tx(x"40"); + uart_tx(x"00"); + uart_tx(x"00"); + uart_tx(x"00"); + + -- 8 bytes + uart_tx(x"00"); + uart_tx(x"00"); + uart_tx(x"00"); + uart_tx(x"08"); + + -- with this data ("ABCD", jalr zero) + uart_tx(x"41"); + uart_tx(x"42"); + uart_tx(x"43"); + uart_tx(x"44"); + uart_tx(x"e7"); + uart_tx(x"00"); + uart_tx(x"00"); + uart_tx(x"00"); + + report ("Reading back from RAM..."); + -- READ + uart_tx(x"02"); + + -- from RAM + uart_tx(x"40"); + uart_tx(x"00"); + uart_tx(x"00"); + uart_tx(x"00"); + + -- 4 bytes ("ABCD") + uart_tx(x"00"); + uart_tx(x"00"); + uart_tx(x"00"); + uart_tx(x"04"); + + Push(SB, x"41"); + Push(SB, x"42"); + Push(SB, x"43"); + Push(SB, x"44"); + + wait for (1 sec / UART_BAUD) * 10 * 5; + + report ("Jumping to RAM+4..."); + -- JUMP + uart_tx(x"03"); + + -- to RAM (+4, jalr zero) + uart_tx(x"40"); + uart_tx(x"00"); + uart_tx(x"00"); + uart_tx(x"04"); + + -- The program will jump back to the loader, so we should be able to read again + wait for 100 us; + + report ("Reading from RAM again..."); + -- READ + uart_tx(x"02"); + + -- from RAM + uart_tx(x"40"); + uart_tx(x"00"); + uart_tx(x"00"); + uart_tx(x"00"); + + -- 4 bytes + uart_tx(x"00"); + uart_tx(x"00"); + uart_tx(x"00"); + uart_tx(x"04"); + + Push(SB, x"41"); + Push(SB, x"42"); + Push(SB, x"43"); + Push(SB, x"44"); + wait for (1 sec / UART_BAUD) * 10 * 5; + + assert ScoreboardEmpty(SB) report "UART RX Scoreboard not empty at end of test!" severity error; + end if; + end loop; + test_runner_cleanup(runner); + end process test; + + test_runner_watchdog(runner, 50 ms); + + clock_driver : process + constant period : time := 20 ns; + begin + clk_in <= '0'; + wait for period / 2; + clk_in <= '1'; + wait for period - (period / 2); + end process clock_driver; +end architecture RTL;