351 lines
13 KiB
VHDL
351 lines
13 KiB
VHDL
-- ============================================================
|
|
-- TESTBENCH TIMING - Progetto Reti Logiche 2025/2026
|
|
-- ============================================================
|
|
-- Verifica il numero di cicli di clock per ciascuna operazione.
|
|
--
|
|
-- Formule attese (calibrate sull'FSM con stato S_DONE, che aggiunge
|
|
-- 1 ciclo a fine operazione per garantire DONE dopo il commit in memoria):
|
|
-- OP=10 inserimento: stati = 6 + 2*max(N,1) + 3k
|
|
-- (N = task gia' in lista, scanditi dal controllo
|
|
-- duplicati; k = task spostati per fare posto)
|
|
-- OP=01 rimozione: stati = 6 + 3k (k = task spostati, lista vuota = 2)
|
|
-- OP=00 decremento: stati = 4 + 3n (n = task in lista)
|
|
--
|
|
-- Per ogni test viene stampato:
|
|
-- - il numero di cicli misurati
|
|
-- - il numero di cicli attesi
|
|
-- - PASS o FAIL
|
|
-- ============================================================
|
|
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
entity project_tb_timing is
|
|
end project_tb_timing;
|
|
|
|
architecture timing_arch of project_tb_timing is
|
|
|
|
constant CLOCK_PERIOD : time := 20 ns;
|
|
|
|
signal tb_clk : std_logic := '0';
|
|
signal tb_rst : std_logic := '0';
|
|
signal tb_start : std_logic := '0';
|
|
signal tb_done : std_logic;
|
|
signal tb_o_task_id : std_logic_vector(5 downto 0);
|
|
signal tb_task_priority : std_logic_vector(1 downto 0) := "00";
|
|
signal tb_op : std_logic_vector(1 downto 0) := "00";
|
|
signal tb_i_task_id : std_logic_vector(5 downto 0) := "000000";
|
|
|
|
signal exc_o_mem_addr : std_logic_vector(15 downto 0);
|
|
signal exc_o_mem_data : std_logic_vector(7 downto 0);
|
|
signal exc_o_mem_we : std_logic;
|
|
signal exc_o_mem_en : std_logic;
|
|
|
|
signal init_o_mem_addr : std_logic_vector(15 downto 0) := (others => '0');
|
|
signal init_o_mem_data : std_logic_vector(7 downto 0) := (others => '0');
|
|
signal init_o_mem_we : std_logic := '0';
|
|
signal init_o_mem_en : std_logic := '0';
|
|
|
|
signal tb_o_mem_addr : std_logic_vector(15 downto 0);
|
|
signal tb_o_mem_data : std_logic_vector(7 downto 0);
|
|
signal tb_o_mem_we : std_logic;
|
|
signal tb_o_mem_en : std_logic;
|
|
signal tb_i_mem_data : std_logic_vector(7 downto 0);
|
|
|
|
signal memory_control : std_logic := '0';
|
|
|
|
type ram_type is array (65535 downto 0) of std_logic_vector(7 downto 0);
|
|
signal RAM : ram_type := (others => "00000000");
|
|
|
|
component project_reti_logiche is
|
|
port (
|
|
i_clk : in std_logic;
|
|
i_rst : in std_logic;
|
|
i_start : in std_logic;
|
|
i_task_id : in std_logic_vector(5 downto 0);
|
|
i_task_priority : in std_logic_vector(1 downto 0);
|
|
i_op : in std_logic_vector(1 downto 0);
|
|
o_done : out std_logic;
|
|
o_task_id : out std_logic_vector(5 downto 0);
|
|
o_mem_addr : out std_logic_vector(15 downto 0);
|
|
i_mem_data : in std_logic_vector(7 downto 0);
|
|
o_mem_data : out std_logic_vector(7 downto 0);
|
|
o_mem_we : out std_logic;
|
|
o_mem_en : out std_logic
|
|
);
|
|
end component;
|
|
|
|
begin
|
|
|
|
UUT : project_reti_logiche
|
|
port map (
|
|
i_clk => tb_clk,
|
|
i_rst => tb_rst,
|
|
i_start => tb_start,
|
|
i_task_id => tb_i_task_id,
|
|
i_task_priority => tb_task_priority,
|
|
i_op => tb_op,
|
|
o_done => tb_done,
|
|
o_task_id => tb_o_task_id,
|
|
o_mem_addr => exc_o_mem_addr,
|
|
i_mem_data => tb_i_mem_data,
|
|
o_mem_data => exc_o_mem_data,
|
|
o_mem_we => exc_o_mem_we,
|
|
o_mem_en => exc_o_mem_en
|
|
);
|
|
|
|
tb_clk <= not tb_clk after CLOCK_PERIOD / 2;
|
|
|
|
MEM : process (tb_clk)
|
|
begin
|
|
if tb_clk'event and tb_clk = '1' then
|
|
if tb_o_mem_en = '1' then
|
|
if tb_o_mem_we = '1' then
|
|
RAM(to_integer(unsigned(tb_o_mem_addr))) <= tb_o_mem_data after 1 ns;
|
|
tb_i_mem_data <= tb_o_mem_data after 1 ns;
|
|
else
|
|
tb_i_mem_data <= RAM(to_integer(unsigned(tb_o_mem_addr))) after 1 ns;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
memory_signal_swapper : process (memory_control,
|
|
init_o_mem_addr, init_o_mem_data, init_o_mem_en, init_o_mem_we,
|
|
exc_o_mem_addr, exc_o_mem_data, exc_o_mem_en, exc_o_mem_we)
|
|
begin
|
|
tb_o_mem_addr <= init_o_mem_addr;
|
|
tb_o_mem_data <= init_o_mem_data;
|
|
tb_o_mem_en <= init_o_mem_en;
|
|
tb_o_mem_we <= init_o_mem_we;
|
|
if memory_control = '1' then
|
|
tb_o_mem_addr <= exc_o_mem_addr;
|
|
tb_o_mem_data <= exc_o_mem_data;
|
|
tb_o_mem_en <= exc_o_mem_en;
|
|
tb_o_mem_we <= exc_o_mem_we;
|
|
end if;
|
|
end process;
|
|
|
|
-- ============================================================
|
|
-- Processo principale
|
|
-- ============================================================
|
|
main : process
|
|
|
|
-- Cicli misurati e attesi
|
|
variable t_start : time;
|
|
variable cycles : integer;
|
|
variable expected : integer;
|
|
|
|
-- --------------------------------------------------------
|
|
-- Reset
|
|
-- --------------------------------------------------------
|
|
procedure do_reset is
|
|
begin
|
|
tb_start <= '0';
|
|
tb_rst <= '1';
|
|
wait for 100 ns;
|
|
tb_rst <= '0';
|
|
wait until tb_done = '0';
|
|
wait until falling_edge(tb_clk);
|
|
end procedure;
|
|
|
|
-- --------------------------------------------------------
|
|
-- Esegue un'operazione e misura i cicli dal primo fronte
|
|
-- di clock dopo START=1 fino al fronte che porta DONE=1
|
|
-- --------------------------------------------------------
|
|
procedure run_and_measure (
|
|
op : std_logic_vector(1 downto 0);
|
|
task_id : std_logic_vector(5 downto 0);
|
|
priority : std_logic_vector(1 downto 0);
|
|
exp : integer;
|
|
test_num : integer
|
|
) is
|
|
begin
|
|
wait until falling_edge(tb_clk);
|
|
tb_op <= op;
|
|
tb_i_task_id <= task_id;
|
|
tb_task_priority <= priority;
|
|
tb_start <= '1';
|
|
|
|
-- Il primo fronte di clock dopo START campiona l'ingresso
|
|
-- ed entra nel primo stato dell'operazione: inizia il conteggio
|
|
wait until rising_edge(tb_clk);
|
|
t_start := now;
|
|
|
|
wait until rising_edge(tb_done);
|
|
-- DONE viene registrato sul fronte: questo è l'ultimo stato
|
|
cycles := (now - t_start) / CLOCK_PERIOD;
|
|
expected := exp;
|
|
|
|
if cycles = expected then
|
|
report "[PASS] test=" & integer'image(test_num)
|
|
& " | cicli misurati=" & integer'image(cycles)
|
|
& " attesi=" & integer'image(expected);
|
|
else
|
|
report "[FAIL] test=" & integer'image(test_num)
|
|
& " | cicli misurati=" & integer'image(cycles)
|
|
& " attesi=" & integer'image(expected)
|
|
severity failure;
|
|
end if;
|
|
|
|
tb_start <= '0';
|
|
wait until falling_edge(tb_done);
|
|
end procedure;
|
|
|
|
-- --------------------------------------------------------
|
|
-- Inserisce un task senza misurarlo (solo per preparare la lista)
|
|
-- --------------------------------------------------------
|
|
procedure insert_silent (
|
|
task_id : std_logic_vector(5 downto 0);
|
|
priority : std_logic_vector(1 downto 0)
|
|
) is
|
|
begin
|
|
wait until falling_edge(tb_clk);
|
|
tb_op <= "10";
|
|
tb_i_task_id <= task_id;
|
|
tb_task_priority <= priority;
|
|
tb_start <= '1';
|
|
wait until rising_edge(tb_done);
|
|
tb_start <= '0';
|
|
wait until falling_edge(tb_done);
|
|
end procedure;
|
|
|
|
begin
|
|
memory_control <= '1';
|
|
wait for 50 ns;
|
|
|
|
-- ============================================================
|
|
-- OP=10: Inserimento -> stati attesi = 6 + 4k
|
|
-- ============================================================
|
|
report "==============================";
|
|
report "OP=10 Inserimento: 6 + 2*max(N,1) + 3k stati";
|
|
report "==============================";
|
|
|
|
-- N=0, k=0: lista vuota -> 6 + 2 + 0 = 8 stati
|
|
-- OP=10 N=0 k=0 (lista vuota)
|
|
do_reset;
|
|
run_and_measure("10", "000001", "01", 8, 1);
|
|
|
|
-- N=1, k=1: 1 task con priorità minore -> spostato -> 6 + 2 + 3 = 11
|
|
-- OP=10 N=1 k=1 (1 task spostato)
|
|
do_reset;
|
|
insert_silent("000001", "10");
|
|
run_and_measure("10", "000010", "01", 11, 2);
|
|
|
|
-- N=2, k=2: 2 task da spostare -> 6 + 4 + 6 = 16
|
|
-- OP=10 N=2 k=2 (2 task spostati)
|
|
do_reset;
|
|
insert_silent("000001", "10");
|
|
insert_silent("000010", "10");
|
|
run_and_measure("10", "000011", "01", 16, 3);
|
|
|
|
-- N=3, k=3: 3 task da spostare -> 6 + 6 + 9 = 21
|
|
-- OP=10 N=3 k=3 (3 task spostati)
|
|
do_reset;
|
|
insert_silent("000001", "10");
|
|
insert_silent("000010", "10");
|
|
insert_silent("000011", "10");
|
|
run_and_measure("10", "000100", "01", 21, 4);
|
|
|
|
-- N=2, k=0: inserimento in fondo, lista non vuota -> 6 + 4 + 0 = 10
|
|
-- OP=10 N=2 k=0 (inserimento in fondo)
|
|
do_reset;
|
|
insert_silent("000001", "00");
|
|
insert_silent("000010", "01");
|
|
run_and_measure("10", "000011", "11", 10, 5);
|
|
|
|
-- ============================================================
|
|
-- OP=01: Rimozione -> stati attesi = 5 + 3k (lista vuota = 1)
|
|
-- ============================================================
|
|
report "==============================";
|
|
report "OP=01 Rimozione: 6 + 3k stati (lista vuota = 2)";
|
|
report "==============================";
|
|
|
|
-- Lista vuota -> 2 stati (CHECK_NUMBER + S_DONE)
|
|
-- OP=01 lista vuota
|
|
do_reset;
|
|
run_and_measure("01", "000000", "00", 2, 6);
|
|
|
|
-- k=0: 1 solo task, nessuno spostamento -> 6 stati
|
|
-- OP=01 k=0 (1 task, nessuno spostamento)
|
|
do_reset;
|
|
insert_silent("000001", "01");
|
|
run_and_measure("01", "000000", "00", 6, 7);
|
|
|
|
-- k=1: 2 task, 1 da spostare -> 9 stati
|
|
-- OP=01 k=1 (1 task spostato)
|
|
do_reset;
|
|
insert_silent("000001", "01");
|
|
insert_silent("000010", "01");
|
|
run_and_measure("01", "000000", "00", 9, 8);
|
|
|
|
-- k=2: 3 task, 2 da spostare -> 12 stati
|
|
-- OP=01 k=2 (2 task spostati)
|
|
do_reset;
|
|
insert_silent("000001", "01");
|
|
insert_silent("000010", "01");
|
|
insert_silent("000011", "01");
|
|
run_and_measure("01", "000000", "00", 12, 9);
|
|
|
|
-- k=3: 4 task, 3 da spostare -> 15 stati
|
|
-- OP=01 k=3 (3 task spostati)
|
|
do_reset;
|
|
insert_silent("000001", "01");
|
|
insert_silent("000010", "01");
|
|
insert_silent("000011", "01");
|
|
insert_silent("000100", "01");
|
|
run_and_measure("01", "000000", "00", 15, 10);
|
|
|
|
-- ============================================================
|
|
-- OP=00: Decremento -> stati attesi = 3 + 3n
|
|
-- ============================================================
|
|
report "==============================";
|
|
report "OP=00 Decremento: 4 + 3n stati";
|
|
report "==============================";
|
|
|
|
-- n=0: lista vuota -> 4 stati
|
|
-- OP=00 n=0 (lista vuota)
|
|
do_reset;
|
|
run_and_measure("00", "000000", "00", 4, 11);
|
|
|
|
-- n=1 -> 7 stati
|
|
-- OP=00 n=1
|
|
do_reset;
|
|
insert_silent("000001", "01");
|
|
run_and_measure("00", "000000", "00", 7, 12);
|
|
|
|
-- n=2 -> 10 stati
|
|
-- OP=00 n=2
|
|
do_reset;
|
|
insert_silent("000001", "01");
|
|
insert_silent("000010", "10");
|
|
run_and_measure("00", "000000", "00", 10, 13);
|
|
|
|
-- n=3 -> 13 stati
|
|
-- OP=00 n=3
|
|
do_reset;
|
|
insert_silent("000001", "01");
|
|
insert_silent("000010", "10");
|
|
insert_silent("000011", "11");
|
|
run_and_measure("00", "000000", "00", 13, 14);
|
|
|
|
-- n=4 con saturazione (tutti prio=3) -> 4 + 3*4 = 16 stati
|
|
-- OP=00 n=4 (tutti gia prio=3, saturazione)
|
|
do_reset;
|
|
insert_silent("000001", "11");
|
|
insert_silent("000010", "11");
|
|
insert_silent("000011", "11");
|
|
insert_silent("000100", "11");
|
|
run_and_measure("00", "000000", "00", 16, 15);
|
|
|
|
-- ============================================================
|
|
-- Fine
|
|
-- ============================================================
|
|
assert false
|
|
report "Tutti i test di timing sono PASSATI"
|
|
severity failure;
|
|
|
|
end process;
|
|
|
|
end architecture; |