Initial commit

This commit is contained in:
2026-06-12 20:37:03 +02:00
commit 259f6d5803
305 changed files with 32830 additions and 0 deletions
@@ -0,0 +1,620 @@
-- ============================================================
-- TESTBENCH EDGE CASES - Progetto Reti Logiche 2025/2026
-- ============================================================
-- Copre i seguenti gruppi di test:
--
-- GRUPPO 0: Reset e inizializzazione
-- 0.0 Reset -> addr 0 = 0, DONE = 1 durante reset poi torna 0
-- 0.1 Reset mentre operazione in corso (START=1)
--
-- GRUPPO 1: OP=10 - Inserimento
-- 1.0 Insert in lista vuota
-- 1.1 Insert con priorità più alta di tutti (va in testa)
-- 1.2 Insert con priorità più bassa di tutti (va in fondo)
-- 1.3 Insert con priorità uguale -> va in CODA agli uguali
-- 1.4 Insert con tutti i task alla stessa priorità -> sempre in fondo
-- 1.5 Insert in lista piena (63 task) -> operazione ignorata
--
-- GRUPPO 2: OP=01 - Rimozione
-- 2.0 Rimozione da lista vuota -> o_task_id = 000000
-- 2.1 Rimozione con un solo task -> lista diventa vuota
-- 2.2 Rimozione da lista con tutti task alla stessa priorità
--
-- GRUPPO 3: OP=00 - Decremento priorità
-- 3.0 Decremento con lista vuota -> nessuna scrittura, no crash
-- 3.1 Saturazione: task a priorità 3 restano a 3
-- 3.2 Lista con TUTTI i task già a priorità 3 -> nessuna modifica
-- 3.3 Mix priorità 2 e 3: i "nuovi 3" (ex-2) vengono PRIMA dei "vecchi 3"
--
-- GRUPPO 4: OP=11 - Svuota lista
-- 4.0 Svuota lista popolata -> addr 0 = 0
-- 4.1 Svuota lista già vuota -> addr 0 rimane 0
-- 4.2 Svuota poi rimuovi -> o_task_id = 000000
-- 4.3 Svuota poi decrementa -> nessun effetto
--
-- GRUPPO 5: Sequenze composite
-- 5.0 Insert -> Decremento -> Rimozione: verifica ID estratto corretto
-- 5.1 Sequenza di insert con priorità miste -> verifica ordinamento completo
--
-- ============================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
entity project_tb_edge is
end project_tb_edge;
architecture project_tb_edge_arch of project_tb_edge is
constant CLOCK_PERIOD : time := 20 ns;
signal tb_clk : std_logic := '0';
signal tb_rst : std_logic;
signal tb_start : std_logic;
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);
signal tb_op : std_logic_vector(1 downto 0);
signal tb_i_task_id : std_logic_vector(5 downto 0);
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");
-- --------------------------------------------------------
-- Utility: tipo per verifiche memoria
-- --------------------------------------------------------
type mem_check_t is record
addr : integer;
expected : std_logic_vector(7 downto 0);
end record;
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 project_reti_logiche;
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
);
-- Clock
tb_clk <= not tb_clk after CLOCK_PERIOD / 2;
-- Memoria
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;
-- Mux memoria: init_o / exc_o
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 di test
-- ============================================================
main_test : process
-- --------------------------------------------------------
-- Procedure di supporto
-- --------------------------------------------------------
-- Reset del componente (attende DONE=1 durante reset poi DONE=0)
procedure do_reset is
begin
tb_start <= '0';
tb_rst <= '1';
wait for 100 ns;
-- DONE deve essere 1 durante il reset (modulo non pronto)
assert tb_done = '1'
report "FAIL: DONE dovrebbe essere 1 durante reset"
severity failure;
tb_rst <= '0';
-- Attende che il modulo completi l'inizializzazione (DONE->0)
wait until tb_done = '0';
wait until falling_edge(tb_clk);
end procedure;
-- Lancia un'operazione e attende DONE=1
procedure do_op (
op : std_logic_vector(1 downto 0);
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 <= op;
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;
-- Verifica un singolo indirizzo di memoria
procedure check_mem (
step : string;
addr : integer;
expected : std_logic_vector(7 downto 0)
) is
begin
assert RAM(addr) = expected
report "FAIL [" & step & "] addr=" & integer'image(addr)
& " expected=0x" & integer'image(to_integer(unsigned(expected)))
& " actual=0x" & integer'image(to_integer(unsigned(RAM(addr))))
severity failure;
end procedure;
-- Verifica o_task_id
procedure check_task_id (
step : string;
expected : std_logic_vector(5 downto 0)
) is
begin
assert tb_o_task_id = expected
report "FAIL [" & step & "] o_task_id expected="
& integer'image(to_integer(unsigned(expected)))
& " actual="
& integer'image(to_integer(unsigned(tb_o_task_id)))
severity failure;
end procedure;
-- Azzera la RAM (usato per isolare i gruppi di test)
procedure clear_ram is
begin
memory_control <= '0';
for i in 0 to 70 loop
init_o_mem_addr <= std_logic_vector(to_unsigned(i, 16));
init_o_mem_data <= "00000000";
init_o_mem_en <= '1';
init_o_mem_we <= '1';
wait until rising_edge(tb_clk);
end loop;
init_o_mem_en <= '0';
init_o_mem_we <= '0';
memory_control <= '1';
end procedure;
-- Inserisce N task nella lista (usato per riempire la lista)
-- I task avranno ID da start_id a start_id+n-1, tutti con la priorità indicata
procedure fill_list (n : integer; base_id : integer; prio : std_logic_vector(1 downto 0)) is
begin
for k in 0 to n-1 loop
do_op("10",
std_logic_vector(to_unsigned(base_id + k, 6)),
prio);
end loop;
end procedure;
begin
-- Inizializzazione segnali
tb_start <= '0';
tb_rst <= '0';
tb_op <= "00";
tb_i_task_id <= "000000";
tb_task_priority <= "00";
memory_control <= '1';
wait for 50 ns;
-- ============================================================
-- GRUPPO 0: Reset e inizializzazione
-- ============================================================
-- 0.0: Reset base -> addr 0 deve essere 0, DONE=1 durante reset
report "=== GRUPPO 0: Reset ===";
memory_control <= '0';
tb_rst <= '1';
wait for 100 ns;
assert tb_done = '1'
report "FAIL [0.0] DONE deve essere 1 durante reset"
severity failure;
tb_rst <= '0';
wait until tb_done = '0';
wait until falling_edge(tb_clk);
check_mem("0.0 reset-addr0", 0, "00000000");
memory_control <= '1';
report "Test 0.0 OK: reset base";
-- 0.1: Reset mentre operazione in corso
-- Prima inseriamo un task, poi resettiamo a metà
clear_ram;
do_reset;
-- Avviamo un inserimento...
wait until falling_edge(tb_clk);
tb_op <= "10";
tb_i_task_id <= "000001";
tb_task_priority <= "01";
tb_start <= '1';
-- Aspettiamo 2 cicli (operazione non ancora completata)
wait until rising_edge(tb_clk);
wait until rising_edge(tb_clk);
-- Reset asincrono!
tb_rst <= '1';
tb_start <= '0';
wait for 50 ns;
assert tb_done = '1'
report "FAIL [0.1] DONE deve essere 1 durante reset asincrono"
severity failure;
tb_rst <= '0';
wait until tb_done = '0';
wait until falling_edge(tb_clk);
check_mem("0.1 reset-async", 0, "00000000");
report "Test 0.1 OK: reset asincrono durante operazione";
-- ============================================================
-- GRUPPO 1: OP=10 - Inserimento
-- ============================================================
report "=== GRUPPO 1: Inserimento ===";
-- 1.0: Insert in lista vuota
clear_ram;
do_reset;
do_op("10", "000001", "10"); -- task_id=1, priority=2
-- Memoria attesa: [0x01]=1, [1]=0b00000110 = task_id=1,prio=2
check_mem("1.0 count", 0, "00000001");
check_mem("1.0 task", 1, "00000110"); -- 000001 & 10
report "Test 1.0 OK: insert in lista vuota";
-- 1.1: Insert con priorità più alta di tutti (va in testa)
clear_ram;
do_reset;
do_op("10", "000010", "10"); -- id=2, prio=2
do_op("10", "000011", "10"); -- id=3, prio=2
do_op("10", "000001", "00"); -- id=1, prio=0 -> deve andare in testa
-- Atteso: [1]=id1,prio0 [2]=id2,prio2 [3]=id3,prio2
check_mem("1.1 count", 0, "00000011");
check_mem("1.1 pos1", 1, "00000100"); -- 000001 & 00
check_mem("1.1 pos2", 2, "00001010"); -- 000010 & 10
check_mem("1.1 pos3", 3, "00001110"); -- 000011 & 10
report "Test 1.1 OK: insert con priorità massima in testa";
-- 1.2: Insert con priorità più bassa di tutti (va in fondo)
clear_ram;
do_reset;
do_op("10", "000001", "00"); -- id=1, prio=0
do_op("10", "000010", "01"); -- id=2, prio=1
do_op("10", "000011", "11"); -- id=3, prio=3 -> deve andare in fondo
-- Atteso: [1]=id1,prio0 [2]=id2,prio1 [3]=id3,prio3
check_mem("1.2 count", 0, "00000011");
check_mem("1.2 pos1", 1, "00000100"); -- 000001 & 00
check_mem("1.2 pos2", 2, "00001001"); -- 000010 & 01
check_mem("1.2 pos3", 3, "00001111"); -- 000011 & 11
report "Test 1.2 OK: insert con priorità minima in fondo";
-- 1.3: Insert con priorità uguale -> va in CODA agli uguali
clear_ram;
do_reset;
do_op("10", "000001", "01"); -- id=1, prio=1
do_op("10", "000010", "01"); -- id=2, prio=1
do_op("10", "000011", "01"); -- id=3, prio=1 -> va dopo id=2
-- Atteso: [1]=id1,prio1 [2]=id2,prio1 [3]=id3,prio1
check_mem("1.3 count", 0, "00000011");
check_mem("1.3 pos1", 1, "00000101"); -- 000001 & 01
check_mem("1.3 pos2", 2, "00001001"); -- 000010 & 01
check_mem("1.3 pos3", 3, "00001101"); -- 000011 & 01
report "Test 1.3 OK: insert stesso prio -> va in coda agli uguali";
-- 1.4: Insert con tutti task stessa priorità -> sempre in fondo
clear_ram;
do_reset;
do_op("10", "000001", "10");
do_op("10", "000010", "10");
do_op("10", "000011", "10");
do_op("10", "000100", "10"); -- sempre in fondo
check_mem("1.4 count", 0, "00000100");
check_mem("1.4 pos1", 1, "00000110"); -- id=1, prio=2
check_mem("1.4 pos2", 2, "00001010"); -- id=2, prio=2
check_mem("1.4 pos3", 3, "00001110"); -- id=3, prio=2
check_mem("1.4 pos4", 4, "00010010"); -- id=4, prio=2
report "Test 1.4 OK: insert con tutti uguale prio -> sempre in fondo";
-- 1.5: Insert in lista piena (63 task) -> operazione ignorata
-- Riempiamo la lista con 63 task (ID da 1 a 63, tutti prio=01)
clear_ram;
do_reset;
fill_list(63, 1, "01");
check_mem("1.5 count-pre", 0, "00111111"); -- 63 task
check_mem("1.5 first-pre", 1, "00000101"); -- id=1, prio=1
check_mem("1.5 last-pre", 63, "11111101"); -- id=63, prio=1
-- Tentiamo un inserimento aggiuntivo (deve essere ignorato)
do_op("10", "000000", "00"); -- id=0 sarebbe errore, ma la lista è piena
-- NB: id=0 non può esistere per specifica, ma qui verifichiamo solo
-- che il count rimanga 63 e la memoria non cambi
check_mem("1.5 count-post", 0, "00111111"); -- ancora 63
check_mem("1.5 pos64", 64, "00000000"); -- nessuna scrittura oltre il limite
report "Test 1.5 OK: insert in lista piena ignorato";
-- ============================================================
-- GRUPPO 2: OP=01 - Rimozione
-- ============================================================
report "=== GRUPPO 2: Rimozione ===";
-- 2.0: Rimozione da lista vuota -> o_task_id = 000000
clear_ram;
do_reset;
wait until falling_edge(tb_clk);
tb_op <= "01";
tb_i_task_id <= "000000";
tb_task_priority <= "00";
tb_start <= '1';
wait until rising_edge(tb_done);
check_task_id("2.0 empty-remove", "000000");
tb_start <= '0';
wait until falling_edge(tb_done);
check_mem("2.0 count", 0, "00000000");
report "Test 2.0 OK: rimozione da lista vuota -> o_task_id=0";
-- 2.1: Rimozione con un solo task -> lista diventa vuota
clear_ram;
do_reset;
do_op("10", "000101", "01"); -- inserisce id=5, prio=1
check_mem("2.1 pre-count", 0, "00000001");
wait until falling_edge(tb_clk);
tb_op <= "01";
tb_i_task_id <= "000000";
tb_task_priority <= "00";
tb_start <= '1';
wait until rising_edge(tb_done);
check_task_id("2.1 single-remove", "000101"); -- deve restituire id=5
tb_start <= '0';
wait until falling_edge(tb_done);
check_mem("2.1 post-count", 0, "00000000"); -- lista vuota
report "Test 2.1 OK: rimozione unico task -> lista vuota, task_id corretto";
-- 2.2: Rimozione da lista con tutti task alla stessa priorità
-- -> rimuove il primo in ordine d'inserimento (FIFO tra pari priorità)
clear_ram;
do_reset;
do_op("10", "000001", "10"); -- id=1
do_op("10", "000010", "10"); -- id=2
do_op("10", "000011", "10"); -- id=3
wait until falling_edge(tb_clk);
tb_op <= "01";
tb_i_task_id <= "000000";
tb_task_priority <= "00";
tb_start <= '1';
wait until rising_edge(tb_done);
check_task_id("2.2 same-prio-remove", "000001"); -- deve restituire id=1 (primo inserito)
tb_start <= '0';
wait until falling_edge(tb_done);
check_mem("2.2 count", 0, "00000010");
check_mem("2.2 pos1", 1, "00001010"); -- id=2 ora in prima posizione
check_mem("2.2 pos2", 2, "00001110"); -- id=3
report "Test 2.2 OK: rimozione con prio uguali -> FIFO rispettato";
-- ============================================================
-- GRUPPO 3: OP=00 - Decremento priorità
-- ============================================================
report "=== GRUPPO 3: Decremento priorità ===";
-- 3.0: Decremento con lista vuota -> nessun crash
clear_ram;
do_reset;
do_op("00", "000000", "00"); -- decremento su lista vuota
check_mem("3.0 count", 0, "00000000"); -- invariato
report "Test 3.0 OK: decremento su lista vuota";
-- 3.1: Saturazione: task a priorità 3 restano a 3
clear_ram;
do_reset;
do_op("10", "000001", "01"); -- id=1, prio=1
do_op("10", "000010", "11"); -- id=2, prio=3 (già al minimo gerarchico)
do_op("00", "000000", "00"); -- decremento
-- id=1: 1->2 id=2: 3->3 (satura)
check_mem("3.1 count", 0, "00000010");
check_mem("3.1 pos1", 1, "00000110"); -- id=1, prio=2
check_mem("3.1 pos2", 2, "00001011"); -- id=2, prio=3 (saturato)
report "Test 3.1 OK: saturazione a priorità 3";
-- 3.2: Lista con TUTTI i task già a priorità 3 -> nessuna modifica dei valori
clear_ram;
do_reset;
do_op("10", "000001", "11");
do_op("10", "000010", "11");
do_op("10", "000011", "11");
do_op("00", "000000", "00"); -- decremento: tutti saturano a 3
check_mem("3.2 count", 0, "00000011");
check_mem("3.2 pos1", 1, "00000111"); -- id=1, prio=3 (invariato)
check_mem("3.2 pos2", 2, "00001011"); -- id=2, prio=3
check_mem("3.2 pos3", 3, "00001111"); -- id=3, prio=3
report "Test 3.2 OK: tutti a prio 3 -> nessuna modifica";
-- 3.3: Mix priorità 2 e 3 dopo decremento:
-- i "nuovi 3" (ex-2) vengono PRIMA dei "vecchi 3"
-- (nessun riordino, basta modificare i bit di priorità)
clear_ram;
do_reset;
do_op("10", "000001", "10"); -- id=1, prio=2 -> diventa 3 (nuovo 3)
do_op("10", "000010", "10"); -- id=2, prio=2 -> diventa 3 (nuovo 3)
do_op("10", "000011", "11"); -- id=3, prio=3 -> resta 3 (vecchio 3)
do_op("10", "000100", "11"); -- id=4, prio=3 -> resta 3 (vecchio 3)
do_op("00", "000000", "00"); -- decremento
-- Dopo: ordine invariato, id=1 e id=2 prima di id=3 e id=4
-- tutti con prio=3 nei bit, ma ordine fisico preservato
check_mem("3.3 count", 0, "00000100");
check_mem("3.3 pos1", 1, "00000111"); -- id=1, prio=3 (ex-2)
check_mem("3.3 pos2", 2, "00001011"); -- id=2, prio=3 (ex-2)
check_mem("3.3 pos3", 3, "00001111"); -- id=3, prio=3 (vecchio)
check_mem("3.3 pos4", 4, "00010011"); -- id=4, prio=3 (vecchio)
report "Test 3.3 OK: ex-prio2 vengono prima di ex-prio3 (no riordino)";
-- ============================================================
-- GRUPPO 4: OP=11 - Svuota lista
-- ============================================================
report "=== GRUPPO 4: Svuota lista ===";
-- 4.0: Svuota lista popolata -> addr 0 = 0
clear_ram;
do_reset;
do_op("10", "000001", "00");
do_op("10", "000010", "01");
do_op("10", "000011", "10");
do_op("11", "000000", "00"); -- svuota
check_mem("4.0 count", 0, "00000000");
report "Test 4.0 OK: svuota lista popolata";
-- 4.1: Svuota lista già vuota -> addr 0 rimane 0, nessun crash
clear_ram;
do_reset;
do_op("11", "000000", "00");
check_mem("4.1 count", 0, "00000000");
report "Test 4.1 OK: svuota lista già vuota";
-- 4.2: Svuota poi rimuovi -> o_task_id = 000000
clear_ram;
do_reset;
do_op("10", "000001", "00");
do_op("11", "000000", "00"); -- svuota
wait until falling_edge(tb_clk);
tb_op <= "01";
tb_i_task_id <= "000000";
tb_task_priority <= "00";
tb_start <= '1';
wait until rising_edge(tb_done);
check_task_id("4.2 remove-after-clear", "000000");
tb_start <= '0';
wait until falling_edge(tb_done);
report "Test 4.2 OK: svuota poi rimozione -> o_task_id=0";
-- 4.3: Svuota poi decrementa -> nessun effetto
clear_ram;
do_reset;
do_op("10", "000001", "01");
do_op("11", "000000", "00"); -- svuota
do_op("00", "000000", "00"); -- decremento su lista vuota
check_mem("4.3 count", 0, "00000000");
report "Test 4.3 OK: svuota poi decrementa -> nessun effetto";
-- ============================================================
-- GRUPPO 5: Sequenze composite
-- ============================================================
report "=== GRUPPO 5: Sequenze composite ===";
-- 5.0: Insert -> Decremento -> Rimozione: verifica ID estratto
-- Inseriamo: id=10 prio=0, id=20 prio=1, id=30 prio=2
-- Decrementiamo: id=10 prio=1, id=20 prio=2, id=30 prio=3
-- Rimuoviamo: deve uscire id=10 (ora ha prio=1, è il primo)
clear_ram;
do_reset;
do_op("10", "001010", "00"); -- id=10, prio=0
do_op("10", "010100", "01"); -- id=20, prio=1
do_op("10", "011110", "10"); -- id=30, prio=2
do_op("00", "000000", "00"); -- decremento
check_mem("5.0 after-dec pos1", 1, "00101001"); -- id=10, prio=1
check_mem("5.0 after-dec pos2", 2, "01010010"); -- id=20, prio=2
check_mem("5.0 after-dec pos3", 3, "01111011"); -- id=30, prio=3
wait until falling_edge(tb_clk);
tb_op <= "01";
tb_i_task_id <= "000000";
tb_task_priority <= "00";
tb_start <= '1';
wait until rising_edge(tb_done);
check_task_id("5.0 remove-after-dec", "001010"); -- id=10
tb_start <= '0';
wait until falling_edge(tb_done);
check_mem("5.0 count", 0, "00000010");
check_mem("5.0 pos1", 1, "01010010"); -- id=20, prio=2
check_mem("5.0 pos2", 2, "01111011"); -- id=30, prio=3
report "Test 5.0 OK: insert->dec->remove, ID estratto corretto";
-- 5.1: Sequenza con priorità miste -> verifica ordinamento completo
-- id=5 prio=3, id=3 prio=1, id=7 prio=2, id=1 prio=0, id=9 prio=1
-- Ordine atteso: id=1(p0), id=3(p1), id=9(p1), id=7(p2), id=5(p3)
clear_ram;
do_reset;
do_op("10", "000101", "11"); -- id=5, prio=3
do_op("10", "000011", "01"); -- id=3, prio=1
do_op("10", "000111", "10"); -- id=7, prio=2
do_op("10", "000001", "00"); -- id=1, prio=0
do_op("10", "001001", "01"); -- id=9, prio=1
check_mem("5.1 count", 0, "00000101");
check_mem("5.1 pos1", 1, "00000100"); -- id=1, prio=0
check_mem("5.1 pos2", 2, "00001101"); -- id=3, prio=1
check_mem("5.1 pos3", 3, "00100101"); -- id=9, prio=1
check_mem("5.1 pos4", 4, "00011110"); -- id=7, prio=2
check_mem("5.1 pos5", 5, "00010111"); -- id=5, prio=3
report "Test 5.1 OK: ordinamento completo con priorità miste";
-- ============================================================
-- Fine
-- ============================================================
assert false
report "======================================" & LF
& " Tutti i test edge case sono PASSATI " & LF
& "======================================"
severity failure;
end process;
end architecture;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,351 @@
-- ============================================================
-- 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;
@@ -0,0 +1,207 @@
-- TB EXAMPLE PFRL 2023-2024
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
entity project_tb is
end project_tb;
architecture project_tb_arch of project_tb is
constant CLOCK_PERIOD : time := 20 ns;
signal tb_clk : std_logic := '0';
signal tb_rst, tb_start, tb_done : std_logic;
signal tb_o_task_id : std_logic_vector(5 downto 0);
signal tb_task_priority, tb_op : std_logic_vector(1 downto 0);
signal tb_i_task_id : std_logic_vector(5 downto 0);
signal tb_o_mem_addr, exc_o_mem_addr, init_o_mem_addr : std_logic_vector(15 downto 0);
signal tb_o_mem_data, exc_o_mem_data, init_o_mem_data : std_logic_vector(7 downto 0);
signal tb_i_mem_data : std_logic_vector(7 downto 0);
signal tb_o_mem_we, tb_o_mem_en, exc_o_mem_we, exc_o_mem_en, init_o_mem_we, init_o_mem_en : std_logic;
type ram_type is array (65535 downto 0) of std_logic_vector(7 downto 0);
signal RAM : ram_type := (OTHERS => "00000000");
type scenario_config_type_t is record
task_id : std_logic_vector(5 downto 0);
task_priority : std_logic_vector(1 downto 0);
op : std_logic_vector(1 downto 0);
end record scenario_config_type_t;
constant SCENARIO_SIZE : integer := 9;
type scenario_config_type is array (0 to SCENARIO_SIZE-1) of scenario_config_type_t;
signal scenario_config : scenario_config_type := (
(task_id => "000001", task_priority => "01", op => "10"), -- Post memory: [00000001,00000101]
(task_id => "000000", task_priority => "00", op => "11"), -- Post memory: [00000000]
(task_id => "000001", task_priority => "01", op => "10"), -- Post memory: [00000001,00000101]
(task_id => "000010", task_priority => "01", op => "10"), -- Post memory: [00000010,00000101,00001001]
(task_id => "000011", task_priority => "10", op => "10"), -- Post memory: [00000011,00000101,00001001,00001110]
(task_id => "000100", task_priority => "00", op => "10"), -- Post memory: [00000100,00010000,00000101,00001001,00001110]
(task_id => "000000", task_priority => "00", op => "01"), -- Post memory: [00000011,00000101,00001001,00001110]
(task_id => "000000", task_priority => "00", op => "00"), -- Post memory: [00000011,00000110,00001010,00001111]
(task_id => "000000", task_priority => "00", op => "00") -- Post memory: [00000011,00000111,00001011,00001111]
);
type scenario_single_result_type is array (0 to 32) of std_logic_vector(7 downto 0);
type scenario_result_type is array (0 to 100) of scenario_single_result_type;
type int_array_t is array (0 to SCENARIO_SIZE - 1) of integer;
constant CHECK_SIZE_ARRAY : int_array_t := (
2,1,2,3,4,5,4,4,4
);
signal scenario_result : scenario_result_type := (
( "00000001", "00000101", others => "00000000"),
( "00000000", others => "00000000"),
( "00000001", "00000101", others => "00000000"),
( "00000010", "00000101", "00001001", others => "00000000"),
( "00000011", "00000101", "00001001", "00001110", others => "00000000"),
( "00000100", "00010000", "00000101", "00001001", "00001110", others => "00000000"),
( "00000011", "00000101", "00001001", "00001110", others => "00000000"),
( "00000011", "00000110", "00001010", "00001111", others => "00000000"),
( "00000011", "00000111", "00001011", "00001111", others => "00000000"),
others => (others => "00000000")
);
signal memory_control : std_logic := '0';
signal first_task_queue : std_logic_vector(5 downto 0);
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 project_reti_logiche;
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
);
-- Clock generation
tb_clk <= not tb_clk after CLOCK_PERIOD/2;
-- Process related to the memory
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
-- This is necessary for the testbench to work: we swap the memory
-- signals from the component to the testbench when needed.
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;
-- This process provides the correct scenario on the signal controlled by the TB
create_scenario : process
begin
wait for 50 ns;
-- Signal initialization and reset of the component
tb_start <= '0';
tb_rst <= '1';
-- Wait some time for the component to reset...
wait for 100 ns;
--assert tb_done = '1' report "TEST FALLITO o_done !=1 during reset" severity failure;
tb_rst <= '0';
memory_control <= '1'; -- Memory controlled by the component
wait until tb_done = '0';
assert RAM(0) = "00000000" report "TEST FALLITO @ OFFSET=0 expected=0 actual=" & integer'image(to_integer(unsigned(RAM(0)))) severity failure;
wait until falling_edge(tb_clk);
for i in 0 to SCENARIO_SIZE - 1 loop
if i > 0 then
-- Save top of the queue for later use
first_task_queue <= scenario_result(i-1)(1)(7 downto 2);
end if;
tb_op <= scenario_config(i).op;
tb_i_task_id <= scenario_config(i).task_id;
tb_task_priority <= scenario_config(i).task_priority;
tb_start <= '1';
wait until rising_edge(tb_done);
if scenario_config(i).op = "01" then
-- Check output task only if the operation was the task removal
assert first_task_queue = tb_o_task_id report "TEST FALLITO @ STEP=" & integer'image(i) & " expected task_id=" & integer'image(to_integer(unsigned(first_task_queue))) & " actual task_id=" & integer'image(to_integer(unsigned(tb_o_task_id))) ;
end if;
-- Check memory contents
for j in 0 to CHECK_SIZE_ARRAY(i) - 1 loop
assert RAM(j) = scenario_result(i)(j) report "TEST FALLITO @ STEP=" & integer'image(i) & " OFFSET=" & integer'image(j) & " expected=" & integer'image(to_integer(unsigned(scenario_result(i)(j)))) & " actual=" & integer'image(to_integer(unsigned(RAM(j)))) ;
end loop;
tb_start <= '0';
wait until falling_edge(tb_done);
wait until falling_edge(tb_clk);
report "Test step " & integer'image(i) & " OK.";
end loop;
assert false report "Simulation Ended! TEST PASSATO (EXAMPLE)" severity failure;
end process;
end architecture;