Progetto di Reti Logiche Prof. Fornaciari, Prof. Palermo e Prof. Salice Anno Accademico 2025 - 2026 SPECIFICA per lo svolgimento del progetto Revisione del 24 Febbraio 2026 Descrizione generale La specifica della “Prova Finale (Progetto di Reti Logiche)” per l’Anno Accademico 2025/2026 chiede di implementare un modulo HW (descritto in VHDL) che si interfacci con una memoria e che rispetti le indicazioni riportate nella seguente specifica. Si richiede di progettare e implementare in VHDL un modulo hardware che gestisce una lista ordinata di task memorizzati in una memoria esterna. Ogni task è rappresentato da una coppia di campi: ID_TASK (6 bit) e PRIORITY (2 bit). Ad esempio, 00100111 indica il task con ID 001001 che ha priorità 11. Le priorità vanno da 0 (più alta) a 3 (più bassa). Non possono esistere due task con lo stesso ID_TASK (questo implica che non possono esistere più di 63 task nella lista). L’ID_TASK è sempre un numero positivo e 0 rappresenta una condizione di errore (lista vuota). La lista dei task è memorizzata in una memoria con la seguente struttura: ● All’indirizzo 0 è memorizzato il numero di task attualmente presenti nella lista. ● A partire dall’indirizzo 1 sono memorizzati i task all’interno di un byte di memoria (ID_TASK & PRIORITY), che devono essere sempre mantenuti ordinati in base alla priorità (priorità più bassa numericamente = più alta gerarchicamente, e quindi prima nella lista). All’interno del byte, ID_TASK occupa i 6 bit più alti e PRIORITY i 2 bit più bassi. Ad esempio, 0x00001100 è il task con ID_TASK 3 e PRIORITY 0. Il modulo deve supportare quattro operazioni, selezionate tramite un ingresso di controllo a 2 bit denominato OP: ● OP = 00: decrementa la priorità di tutti i task presenti nella lista. Ogni indicatore di priorità deve essere incrementato di 1, senza superare il valore numerico massimo (3 - priorità più bassa). Il valore di priorità satura a 3 (priorità minima). Tutti i task mantengono l’ordinamento che avevano prima dell’incremento del valore di priorità. In particolare, la lista dei task a priorità 3 vedrà prima tutti i task che avevano priorità 2 e poi quelli che già erano a priorità 3 (in pratica sarà sufficiente modificare i valori di priorità senza alcun riordino). ● OP = 01: Rimuove dalla lista il primo task (indirizzo 1). Tutti i task successivi devono essere spostati di una posizione, il numero di task deve essere decrementato, e il numero del task estratto deve essere fornito in uscita dal modulo. Il primo task della lista potrebbe avere una priorità qualunque (0, 1, 2 o 3). In caso di lista vuota, deve essere fornito in uscita il valore di ID_TASK 0 (0x000000) . Il valore ID_TASK deve essere valido quando DONE viene portato a 1. ● OP = 10: Aggiunge un nuovo task alla lista, inserendolo in coda ai task a pari priorità, preservando l’ordine di tutti gli altri task. Se la lista è vuota, il task deve essere inserito in prima posizione. ● OP = 11: Svuota completamente la lista. Il valore in memoria all’indirizzo 0 deve essere posto a zero; il contenuto degli altri indirizzi può essere ignorato (quello che è stato scritto in passato riamane invariato) o resettato (tutti i valori sono posti a zero). Il modulo utilizza un protocollo di hand-shake START-DONE per la sincronizzazione con la logica esterna. Il comportamento richiesto è il seguente: ● Il segnale START, generato dall’esterno, viene posto a 1 per avviare l’operazione selezionata tramite OP. ● START deve rimanere a 1 fino a quando il modulo non porta il segnale DONE a 1, indicando che l’operazione è stata completata. ● Quando DONE è a 1, la logica esterna deve riportare START a 0. ● Quando START torna a 0, il modulo può riportare DONE a 0 e prepararsi a ricevere una nuova operazione. ● Una nuova operazione può essere avviata solo quando DONE è a 0. Dopo che il modulo viene resettato (quindi subito dopo la transizione RESET 1 -> 0), esso deve comportarsi come segue: ● Dopo un reset, la lista deve essere considerata vuota. Il modulo deve quindi scrivere il valore zero all’indirizzo 0 della memoria. ● Durante questa fase di inizializzazione, il segnale DONE deve essere mantenuto a 1, indicando che il modulo non è ancora pronto a ricevere operazioni, e solo dopo che l’azzeramento è stato effettuato, il modulo può riportare DONE a 0 e rendersi disponibile a nuove operazioni. Il modulo deve garantire: Il corretto aggiornamento della memoria in seguito a ogni operazione. Il mantenimento dell’ordine dei task nella lista. ● ● ● La gestione appropriata dei casi limite, ad esempio lista vuota. ● Il rispetto del protocollo START-DONE come descritto. Si precisa che la presente specifica descrive un comportamento completamente deterministico: a parità di sequenze di ingresso, le uscite generate e il contenuto della memoria nella parte valida (lista dei task) risultano invariati. Qualsiasi eventuale scenario che presenti ambiguità o comportamenti non univocamente determinati dovrà essere identificato e prontamente segnalato. Interfaccia del Componente Il modulo da implementare ha 4 ingressi primari, uno ad 1 bit (i_start), uno a 6 bit (i_task_id), uno a 2 bit (i_task_priority) e uno da 2 bit (i_op), e due uscite primarie, una da 1 bit (o_done) e una da 6 bit (o_task_id). Inoltre, il modulo ha un segnale di clock CLK, unico per tutto il sistema e un segnale di reset RESET anch’esso unico per tutto il sistema. Tutti i segnali sono sincroni e devono essere interpretati sul fronte di salita del clock. L’unica eccezione è RESET che, invece, è asincrono. RESET può essere generato in qualsiasi momento dell’esecuzione. Il componente da descrivere deve avere la seguente interfaccia. entity 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 project_reti_logiche; In particolare: ● ● ● ● ● il nome del modulo deve essere project_reti_logiche e deve essere presente una sola architettura per ogni entità; la violazione di queste indicazioni comporta il Test Bench e una l’impossibilità di eseguire conseguente valutazione di zero; i_clk è il segnale di CLOCK in ingresso generato dal Test Bench; i_rst è il segnale di RESET che inizializza la macchina pronta per ricevere il primo segnale di START; i_start è il segnale di START generato dal Test Bench; i_task_id è il vettore di bit rappresentante il ID_TASK generato dal Test Bench; ● ● i_task_priority è il vettore di bit rappresentante il PRIORITY generato dal Test Bench; i_op è il vettore di 2 bit rappresentante l’operazione da dover effettuare sulla lista di task; ● o_done è il segnale DONE di uscita che comunica la fine dell’elaborazione; ● o_task_id è il vettore di bit rappresentante il ID_TASK del task a priorità più alta estratto dalla memoria; ● o_mem_addr è il segnale (vettore) di uscita che manda l’indirizzo alla ● memoria; i_mem_data è il segnale (vettore) che arriva dalla memoria e contiene il dato in seguito ad una richiesta di lettura; ● o_mem_data è il segnale (vettore) che va verso la memoria e contiene il dato che verrà successivamente scritto; ● o_mem_en è il segnale di ENABLE da dover mandare alla memoria per poter comunicare (sia in lettura che in scrittura); ● o_mem_we è il segnale di WRITE ENABLE da dover mandare alla memoria (=1) per poter scriverci. Per leggere da memoria, esso deve essere 0. APPENDICE: Descrizione Memoria NOTA: La memoria è già istanziata all’interno del Test Bench e non va sintetizzata La memoria e il suo protocollo può essere estratto dalla seguente descrizione VHDL che fa parte del test bench e che è derivata dalla User guide di VIVADO disponibile al seguente link: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_3/ug901-vivado-synth esis.pdf -- Single-Port Block RAM Write-First Mode (recommended template) -- -- File: rams_02.vhd -- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity rams_sp_wf is port( clk : in std_logic; we : in std_logic; en : in std_logic; addr : in std_logic_vector(15 downto 0); di : in std_logic_vector(7 downto 0); do : out std_logic_vector(7 downto 0) ); end rams_sp_wf; architecture syn of rams_sp_wf is type ram_type is array (65535 downto 0) of std_logic_vector(7 downto 0); signal RAM : ram_type; begin process(clk) begin if clk'event and clk = '1' then if en = '1' then if we = '1' then RAM(conv_integer(addr)) <= di; do <= di after 2 ns; else do <= RAM(conv_integer(addr)) after 2 ns; end if; end if; end if; end process; end syn; ESEMPIO L’esempio qui di seguito mostra il comportamento a seguito dei segnali di ingresso. Qui di seguito è presente la situazione della memoria a seguito dell’inserimento di diversi task (fase non mostrata nell’esempio). I valori non espliciti sono valori di memoria che non vengono considerati per il normale funzionamento. SITUAZIONE INIZIALE (6 task già in tabella) MEMORIA INDIRIZZO VALORE ID_TASK PRIORITY 0x00000110 0x01000000 0x01011000 0x01011100 0x01010101 0x01110010 0x00010011 16 22 23 21 28 4 0 0 0 1 2 3 0 1 2 3 4 5 6 7 OPERAZIONE: 00 (incremento valore di priorità) MEMORIA INDIRIZZO VALORE ID_TASK PRIORITY 0x00000110 0x01000001 0x01011001 0x01011101 0x01010110 0x01110011 0x00010011 16 22 23 21 28 4 1 1 1 2 3 3 0 1 2 3 4 5 6 7 OPERAZIONE: 10 (aggiunge un task) - ID_TASK: 19 - PRIORITY: 2 MEMORIA INDIRIZZO VALORE ID_TASK PRIORITY 0x00000111 0x01000001 0x01011001 0x01011101 0x01010110 0x01001110 0x01110011 0x00010011 16 22 23 21 19 28 4 1 1 1 2 2 3 3 0 1 2 3 4 5 6 7 8 OPERAZIONE: 01 (rimuove il primo task) MEMORIA INDIRIZZO VALORE ID_TASK PRIORITY 0x00000110 0x01011001 0x01011101 0x01010110 0x01001110 0x01110011 0x00010011 22 23 21 19 28 4 1 1 2 2 3 3 0 1 2 3 4 5 6 7 OPERAZIONE: 11 (svuota la lista) MEMORIA INDIRIZZO VALORE ID_TASK PRIORITY 0x00000000 0 1 OPERAZIONE: 10 (aggiunge un task) - ID_TASK: 31 - PRIORITY: 3 MEMORIA INDIRIZZO VALORE ID_TASK PRIORITY 0x00000001 0x01111111 0 1 2 OPERAZIONE: 10 (aggiunge un task) - ID_TASK: 15 - PRIORITY: 0 MEMORIA INDIRIZZO VALORE ID_TASK PRIORITY 0x00000010 0x00111100 0x01111111 15 31 0 3 0 1 2 3 OPERAZIONE: 10 (aggiunge un task) - ID_TASK: 20 - PRIORITY: 0 MEMORIA INDIRIZZO VALORE ID_TASK PRIORITY 0 1 2 3 0x000000011 0x00111100 0x01010000 0x01111111 15 20 31 0 0 3 Progetto di Reti Logiche Prof. Fornaciari, Prof. Palermo e Prof. Salice Anno Accademico 2025 - 2026 NOTE DI AGGIORNAMENTO DELLA SPECIFICA In questa pagina potete trovare le modifiche fatte alla specifica del progetto dal suo primo rilascio. Tutti i cambiamenti con data annessa saranno riportati qui sotto e sono mantenuti in rosso nel testo. Errata Corrige: - Aggiornamento 24.02.2026: - Il numero massimo di task nella lista non è 31 come nella versione originale ma 63. Questo è derivato dal fatto che il numero di bit per il task_id è 6.