Initial commit
This commit is contained in:
@@ -0,0 +1,793 @@
|
||||
\documentclass[12pt,a4paper]{article}
|
||||
|
||||
% --- Preambolo ---
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage[italian]{babel}
|
||||
\usepackage{amsmath, amsfonts, amssymb}
|
||||
\usepackage{geometry}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{listings}
|
||||
\usepackage{xcolor}
|
||||
\usepackage{lstautogobble}
|
||||
|
||||
\usepackage{booktabs}
|
||||
\usepackage{xcolor}
|
||||
\usepackage{colortbl}
|
||||
\usepackage{float}
|
||||
|
||||
\usepackage{caption}
|
||||
|
||||
\usepackage{hyperref}
|
||||
\hypersetup{
|
||||
colorlinks=false,
|
||||
pdfborder={0 0 0}
|
||||
}
|
||||
|
||||
|
||||
\geometry{a4paper, margin=3cm}
|
||||
|
||||
% Configurazione professionale per il codice VHDL
|
||||
\lstset{
|
||||
language=VHDL,
|
||||
basicstyle=\ttfamily\small, % Font monospaziato piccolo
|
||||
keywordstyle=\color{blue}, % Parole chiave in blu
|
||||
commentstyle=\color{gray}, % Commenti in grigio
|
||||
breaklines=true, % VA A CAPO AUTOMATICAMENTE
|
||||
frame=single, % Bordo attorno al codice
|
||||
numbers=left, % Numeri di riga a sinistra
|
||||
numberstyle=\tiny\color{gray},
|
||||
xleftmargin=10pt, % Margine per far rientrare i numeri di riga
|
||||
showstringspaces=false,
|
||||
autogobble=true,
|
||||
tabsize=2,
|
||||
}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\begin{titlepage}
|
||||
\centering
|
||||
{\large \textbf{POLITECNICO DI MILANO 1863}} \\
|
||||
\vspace{1cm}
|
||||
\includegraphics[width=0.4\textwidth]{logo_polimi.jpg} \\
|
||||
\vspace{2cm}
|
||||
|
||||
{\Large \textbf{Relazione Progetto Reti Logiche}} \\
|
||||
\vspace{1cm}
|
||||
|
||||
{\large Aleandro Pagani} \\
|
||||
\vspace{0.5cm}
|
||||
{\large Giugno 2026} \\
|
||||
|
||||
\vfill
|
||||
|
||||
{\large Matricola: 236992} \\
|
||||
{\large Codice persona: 10893566} \\
|
||||
\vspace{1cm}
|
||||
{\large Professore: Fabio Salice}
|
||||
\end{titlepage}
|
||||
|
||||
\newpage
|
||||
|
||||
\pagenumbering{roman}
|
||||
\tableofcontents
|
||||
\newpage
|
||||
|
||||
|
||||
|
||||
\pagenumbering{arabic}
|
||||
\section{Introduzione}
|
||||
\subsection{Specifiche generali}
|
||||
\subsubsection{Descrizione}
|
||||
|
||||
Il progetto consiste nel descrivere un modulo hardware che si interfaccia con una memoria in cui la prima cella contiene il contatore dei task e le celle successive la lista ordinata. Il modulo deve supportare quattro tipi di operazioni il cui codice identificativo è fornito in ingresso:
|
||||
\begin{itemize}
|
||||
\item \textbf{00}: Decrementa la priorità di tutti i task
|
||||
\item \textbf{01}: Rimuove il primo task della lista
|
||||
\item \textbf{10}: Aggiunge un nuovo task in lista
|
||||
\item \textbf{11}: Svuota completamente la lista
|
||||
\end{itemize}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\begin{minipage}{0.45\textwidth}
|
||||
\centering
|
||||
\includegraphics[width=\textwidth]{INTRODUZIONE/OP_00.png}
|
||||
\caption*{OP 00.}
|
||||
\label{fig:00}
|
||||
\end{minipage}
|
||||
\hfill
|
||||
\begin{minipage}{0.45\textwidth}
|
||||
\centering
|
||||
\includegraphics[width=\textwidth]{INTRODUZIONE/OP_01.png}
|
||||
\caption*{OP 01.}
|
||||
\label{fig:01}
|
||||
\end{minipage}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\begin{minipage}{0.45\textwidth}
|
||||
\centering
|
||||
\includegraphics[width=\textwidth]{INTRODUZIONE/OP_10.png}
|
||||
\caption*{OP 10 (inserisco task 000000 01).}
|
||||
\label{fig:10}
|
||||
\end{minipage}
|
||||
\hfill
|
||||
\begin{minipage}{0.45\textwidth}
|
||||
\centering
|
||||
\includegraphics[width=\textwidth]{INTRODUZIONE/OP_11.png}
|
||||
\caption*{OP 11.}
|
||||
\label{fig:11}
|
||||
\end{minipage}
|
||||
\end{figure}
|
||||
|
||||
\newpage
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\subsubsection{Funzionamento}
|
||||
La sincronizzazione tra la logica esterna e il modulo hardware avviene tramite un protocollo di handshake \textbf{START-DONE}.
|
||||
Il funzionamento del modulo è scandito attraverso 5 fasi:
|
||||
\begin{itemize}
|
||||
\item \textbf{Inizializzazione:} Vengono forniti i dati e posto il segnale \textbf{START} a 1.
|
||||
\item \textbf{Elaborazione:} Il modulo avvia le operazioni e interagisce con la memoria.
|
||||
\item \textbf{Completamento:} Terminate le operazioni, il modulo imposta il segnale \textbf{DONE} a 1.
|
||||
\item \textbf{Riconoscimento:} La logica esterna pone il segnale \textbf{START} a 0.
|
||||
\item \textbf{Ripristino:} Il modulo riporta il segnale \textbf{DONE} a 0 e torna in attesa di nuove direttive.
|
||||
\end{itemize}
|
||||
|
||||
\vspace{0.5cm}
|
||||
\centerline{\includegraphics[width=0.6\textwidth]{START-DONE handshake.png}}
|
||||
\newpage
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\subsection{Descrizione modulo}
|
||||
|
||||
\begin{lstlisting}
|
||||
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;
|
||||
\end{lstlisting}
|
||||
|
||||
\begin{itemize}
|
||||
\item \textbf{i\_clk:} Segnale di clock
|
||||
\item \textbf{i\_rst:} Segnale di reset
|
||||
\vspace{0.5cm}
|
||||
\item \textbf{i\_start:} Segnale \textbf{START} di handshake
|
||||
\item \textbf{i\_task\_id:} Codice del task da inserire
|
||||
\item \textbf{i\_task\_priority:} Priorità del task da inserire
|
||||
\item \textbf{i\_op:} ID dell'operazione da eseguire
|
||||
\vspace{0.5cm}
|
||||
\item \textbf{o\_done:} Segnale \textbf{DONE} di handshake
|
||||
\item \textbf{o\_task\_id:} Codice del task restituito dall'eliminazione
|
||||
\vspace{0.5cm}
|
||||
\item \textbf{o\_mem\_addr:} Indirizzo di memoria con cui interagire
|
||||
\item \textbf{i\_mem\_data:} Informazioni lette dalla memoria
|
||||
\item \textbf{o\_mem\_data:} Informazioni da scrivere in memoria
|
||||
\item \textbf{o\_mem\_we:} Flag per abilitare la scrittura in memoria
|
||||
\item \textbf{o\_mem\_en:} Flag per abilitare la lettura in memoria
|
||||
\end{itemize}
|
||||
\newpage
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\subsection{Descrizione memoria}
|
||||
\subsubsection{Implementazione fornita}
|
||||
\begin{lstlisting}
|
||||
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; -- Write-First
|
||||
else
|
||||
do <= RAM(conv_integer(addr));
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
end syn;
|
||||
\end{lstlisting}
|
||||
|
||||
\begin{itemize}
|
||||
\item \textbf{clk:} Segnale di clock
|
||||
\item \textbf{we:} Flag di scrittura
|
||||
\item \textbf{en:} Flag di lettura
|
||||
\item \textbf{addr:} Indirizzo con cui interagire
|
||||
\item \textbf{di:} Dati in ingresso
|
||||
\item \textbf{do:} Dati in uscita
|
||||
\end{itemize}
|
||||
\newpage
|
||||
|
||||
\subsubsection{Layout di memoria}
|
||||
La RAM indirizza 65536 celle da un byte (indirizzi a 16 bit); la lista ne utilizza al più 64: la prima (\textbf{0}) rappresenta il numero di task presenti, le successive contengono i task (al massimo 63, dato che gli ID sono a 6 bit e l'ID 0 è riservato).\\
|
||||
Per ogni task, i primi 6 bit ne identificano il codice, mentre gli ultimi 2 la priorità.
|
||||
\vspace{0.7cm}
|
||||
|
||||
|
||||
\begin{minipage}[c]{0.30\textwidth}
|
||||
\centering
|
||||
\includegraphics[width=\textwidth]{MemoryDiagram.png}
|
||||
\end{minipage}
|
||||
\hfill
|
||||
\begin{minipage}[c]{0.60\textwidth}
|
||||
|
||||
In questo esempio abbiamo 3 task:
|
||||
\begin{itemize}
|
||||
\item \textbf{001111 00:} Task con codice 15 e priorità 0
|
||||
\item \textbf{010100 00:} Task con codice 20 e priorità 0
|
||||
\item \textbf{011011 11:} Task con codice 27 e priorità 3
|
||||
\end{itemize}
|
||||
Tutti gli altri elementi in memoria non vengono considerati validi.
|
||||
\end{minipage}
|
||||
\newpage
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\section{Architettura}
|
||||
Data la dimensione ridotta del progetto, il componente è composto da un unico modulo con due processi: uno sincrono e uno combinatorio.
|
||||
|
||||
Nell'implementazione presentata è stata privilegiata la leggibilità rispetto all'efficienza e alla minimizzazione del numero di segnali.
|
||||
|
||||
\subsection{Segnali interni}
|
||||
\begin{lstlisting}
|
||||
signal state : state_type;
|
||||
signal next_state : state_type;
|
||||
|
||||
signal current_mem_addr : std_logic_vector(15 downto 0);
|
||||
signal next_mem_addr : std_logic_vector(15 downto 0);
|
||||
|
||||
signal current_task_count : std_logic_vector(7 downto 0);
|
||||
signal next_task_count : std_logic_vector(7 downto 0);
|
||||
|
||||
signal current_popped_id : std_logic_vector(5 downto 0);
|
||||
signal next_popped_id : std_logic_vector(5 downto 0);
|
||||
|
||||
signal ctrl_done : std_logic;
|
||||
signal ctrl_mem_en : std_logic;
|
||||
signal ctrl_mem_we : std_logic;
|
||||
signal ctrl_mem_data : std_logic_vector(7 downto 0);
|
||||
signal ctrl_task_id : std_logic_vector(5 downto 0);
|
||||
\end{lstlisting}
|
||||
|
||||
I registri interni sono organizzati in coppie \textbf{current\_*}/\textbf{next\_*}: il processo combinatorio calcola il valore \textbf{next\_*}, il processo sincrono lo registra in \textbf{current\_*} sul fronte di clock.
|
||||
|
||||
\begin{itemize}
|
||||
\item \textbf{state:} Stato attuale dell'FSM
|
||||
\item \textbf{next\_state:} Prossimo stato dell'FSM
|
||||
\vspace{0.5cm}
|
||||
\item \textbf{current\_mem\_addr / next\_mem\_addr:} Indirizzo di memoria su cui la FSM sta lavorando (0 = contatore, 1..N = task)
|
||||
\item \textbf{current\_task\_count / next\_task\_count:} Copia locale del numero di task presenti in lista (cella 0 della memoria)
|
||||
\item \textbf{current\_popped\_id / next\_popped\_id:} ID estratto dall'ultima rimozione, presentato su \textbf{o\_task\_id} quando \textbf{DONE} viene alzato
|
||||
\vspace{0.5cm}
|
||||
\item \textbf{ctrl\_done:} Segnale di controllo di \textbf{DONE}
|
||||
\item \textbf{ctrl\_mem\_en:} Segnale per abilitare la lettura in memoria
|
||||
\item \textbf{ctrl\_mem\_we:} Segnale per abilitare la scrittura in memoria
|
||||
\item \textbf{ctrl\_mem\_data:} Dati da scrivere in memoria
|
||||
\item \textbf{ctrl\_task\_id:} Valore da presentare sull'uscita \textbf{o\_task\_id}
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Processo sincrono}
|
||||
Questo processo registra sul fronte di salita del clock lo stato, i registri e tutte le uscite del modulo.
|
||||
\begin{lstlisting}
|
||||
process(i_clk, i_rst)
|
||||
begin
|
||||
if i_rst = '1' then
|
||||
state <= S_RESET;
|
||||
o_done <= '1';
|
||||
o_mem_en <= '0';
|
||||
o_mem_we <= '0';
|
||||
elsif rising_edge(i_clk) then
|
||||
state <= next_state;
|
||||
current_mem_addr <= next_mem_addr;
|
||||
current_task_count <= next_task_count;
|
||||
current_popped_id <= next_popped_id;
|
||||
|
||||
o_done <= ctrl_done;
|
||||
o_mem_en <= ctrl_mem_en;
|
||||
o_mem_we <= ctrl_mem_we;
|
||||
o_mem_addr <= next_mem_addr;
|
||||
o_mem_data <= ctrl_mem_data;
|
||||
o_task_id <= ctrl_task_id;
|
||||
end if;
|
||||
end process;
|
||||
\end{lstlisting}
|
||||
Sul fronte di salita del clock i registri \textbf{current\_*} vengono aggiornati con i corrispettivi valori \textbf{next\_*} e, contemporaneamente, vengono scritti sui bus di uscita \textbf{o\_*} i valori calcolati dal processo combinatorio.
|
||||
|
||||
Il reset, asincrono, porta la FSM in \textbf{S\_RESET} con \textbf{DONE} a 1 (come richiesto dalla specifica) e disabilita l'interfaccia verso la memoria: in questo modo il modulo non può produrre scritture involontarie mentre il reset è attivo, indipendentemente dall'istante in cui arriva.
|
||||
|
||||
\vspace{0.5cm}
|
||||
Due scelte progettuali meritano attenzione:
|
||||
\begin{itemize}
|
||||
\item \textbf{Uscite registrate:} I segnali interni \textbf{ctrl\_*} vengono assegnati alle uscite \textbf{o\_*} solo nel processo sincrono: oltre a separare la logica di controllo dall'aggiornamento delle uscite, questo garantisce che i segnali verso la memoria siano privi di glitch.
|
||||
\item \textbf{Indirizzo anticipato:} \textbf{o\_mem\_addr} viene registrato da \textbf{next\_mem\_addr} (e non da \textbf{current\_mem\_addr}): l'indirizzo arriva così alla memoria con un ciclo di anticipo rispetto allo stato che ne consumerà il dato. Poiché la memoria ha lettura sincrona con latenza di un ciclo, questa convenzione permette a ogni stato di richiedere una lettura e allo stato successivo (dopo un solo ciclo "cuscinetto") di usarne il risultato.
|
||||
\end{itemize}
|
||||
\newpage
|
||||
|
||||
\subsection{Processo combinatorio}
|
||||
Questo è il processo principale del modulo hardware: esso è responsabile della logica interna e della gestione degli stati FSM.\\
|
||||
Vengono di seguito analizzati tutti gli stati presenti.
|
||||
|
||||
|
||||
\begin{lstlisting}
|
||||
type state_type is (
|
||||
S_IDLE, S_RESET, S_DONE,
|
||||
|
||||
S_00_READ, S_00_WAIT, S_00_CHECK, S_00_GO_NEXT,
|
||||
|
||||
S_01_CHECK_NUMBER, S_01_WAIT, S_01_WRITE, S_01_CHECK_END, S_01_COPY, S_01_GO_NEXT, S_01_WAIT_FOR_COUNT,
|
||||
|
||||
S_10_PLACE_AT_START, S_10_WAIT_FOR_CHECK, S_10_CHECK_ID, S_10_WAIT, S_10_COMPARE, S_10_GO_NEXT, S_10_UPDATE_COUNT, S_10_WAIT_FOR_COUNT,
|
||||
|
||||
S_11_UPDATE_COUNT, S_11_WAIT_FOR_COUNT
|
||||
);
|
||||
\end{lstlisting}
|
||||
|
||||
\subsubsection{Stati di gestione del protocollo}
|
||||
\begin{itemize}
|
||||
\item \textbf{S\_IDLE:} Stato di attesa. Quando viene rilevato il segnale \textbf{START=1}, viene avviata l'operazione indicata dal codice \textbf{i\_op}. Al dispatch viene anche azzerato il registro \textbf{popped\_id}, così \textbf{o\_task\_id} varrà 0 per ogni operazione diversa da una rimozione andata a buon fine.
|
||||
\item \textbf{S\_RESET:} Stato di reset. Imposta il contatore nella prima cella di memoria a 0, invalidando tutte le altre, mentre \textbf{DONE} rimane a 1 come richiesto dalla specifica.
|
||||
\item \textbf{S\_DONE:} Alza \textbf{DONE} e lo tiene a 1 finché \textbf{START} non torna a 0, come richiesto dal protocollo di handshake. Tutte le operazioni raggiungono questo stato un ciclo dopo il proprio stato terminale: \textbf{DONE} sale quindi sempre \emph{dopo} il commit in memoria dell'ultima scrittura, e la logica esterna che campiona la memoria sul fronte di \textbf{DONE} legge dati già aggiornati.
|
||||
\end{itemize}
|
||||
\newpage
|
||||
|
||||
\subsubsection{Operazione 00}
|
||||
Questa operazione decrementa la priorità di tutti i task presenti in lista.
|
||||
Se un task ha già la priorità minima \textbf{11}, questa non viene modificata.
|
||||
\vspace{0.5cm}
|
||||
|
||||
\centerline{\includegraphics[width=0.4\textwidth]{DIAGRAMS/S_00_DIAGRAM.png}}
|
||||
|
||||
\vspace{0.5cm}
|
||||
Gli stati presenti sono 4:
|
||||
\begin{itemize}
|
||||
\item \textbf{S\_00\_READ:} Seleziona il primo elemento in lista
|
||||
\item \textbf{S\_00\_WAIT:} Stato cuscinetto. Serve per dare tempo alla RAM di leggere il contenuto del task selezionato
|
||||
\item \textbf{S\_00\_CHECK:} Controlla se l'indirizzo selezionato è un task valido. In tal caso, se possibile, ne incrementa la priorità numerica di 1.
|
||||
\item \textbf{S\_00\_GO\_NEXT:} Seleziona la cella di memoria successiva
|
||||
\end{itemize}
|
||||
\newpage
|
||||
|
||||
\subsubsection{Operazione 01}
|
||||
Questa operazione rimuove il primo task della lista e sposta in alto tutti i task sottostanti.
|
||||
\vspace{0.5cm}
|
||||
|
||||
\centerline{\includegraphics[width=0.7\textwidth]{DIAGRAMS/S_01_DIAGRAM.png}}
|
||||
|
||||
\vspace{0.5cm}
|
||||
Gli stati presenti sono 7:
|
||||
\begin{itemize}
|
||||
\item \textbf{S\_01\_CHECK\_NUMBER:} Se non ci sono task termina subito (\textbf{o\_task\_id} resterà \textbf{000000}). Altrimenti avvia la lettura del primo task.
|
||||
\item \textbf{S\_01\_WAIT:} Stato cuscinetto. Serve per dare tempo alla RAM di leggere il contenuto del task selezionato
|
||||
\item \textbf{S\_01\_WRITE:} Salva l'ID del primo task nel registro \textbf{popped\_id} (verrà presentato su \textbf{o\_task\_id} in \textbf{S\_DONE}) e avvia la lettura del task successivo.
|
||||
\item \textbf{S\_01\_CHECK\_END:} Controlla se ha raggiunto la fine della lista. In tal caso scrive nella prima cella il valore del contatore decrementato di uno.
|
||||
\item \textbf{S\_01\_COPY:} Copia il contenuto della cella \textbf{n+1} dentro alla cella \textbf{n}.
|
||||
\item \textbf{S\_01\_GO\_NEXT:} Passa al task successivo.
|
||||
\item \textbf{S\_01\_WAIT\_FOR\_COUNT:} Attende il commit della scrittura del contatore, poi transita in \textbf{S\_DONE}.
|
||||
\end{itemize}
|
||||
\newpage
|
||||
|
||||
\subsubsection{Operazione 10}
|
||||
Questa operazione inserisce un nuovo task nella posizione corretta secondo la sua priorità, in coda ai task di pari priorità. L'operazione è divisa in due fasi:
|
||||
\begin{enumerate}
|
||||
\item \textbf{Scansione duplicati:} la lista viene percorsa dall'ultimo task verso il primo; se viene trovato un task con lo stesso ID, l'inserimento viene ignorato (la specifica vieta la presenza di due task con lo stesso ID). Vengono inoltre scartate immediatamente le richieste con ID = 0, valore riservato dalla specifica come condizione di errore.
|
||||
\item \textbf{Inserimento dal fondo:} partendo dall'ultimo task e salendo, viene controllata la priorità del task corrente. Se questa risulta numericamente maggiore (gerarchicamente inferiore) rispetto a quella del task da inserire, la cella viene copiata in quella sottostante e il confronto prosegue verso l'alto. Contrariamente, se la priorità dovesse risultare minore o uguale, il nuovo task viene inserito nella cella sottostante: il confronto "minore o uguale" è ciò che colloca il nuovo task \emph{dopo} quelli di pari priorità, garantendo l'ordine FIFO richiesto.
|
||||
\end{enumerate}
|
||||
|
||||
Si fa notare come il caso limite di lista piena non può verificarsi: con ID a 6 bit e ID = 0 escluso esistono al più 63 task distinti, e un 64-esimo inserimento sarebbe necessariamente un duplicato, quindi ignorato dalla fase di scansione.
|
||||
|
||||
\vspace{0.5cm}
|
||||
Di seguito viene illustrato un esempio di inserimento del task \textbf{011110 01}.
|
||||
|
||||
Nota: la scansione iniziale per identificare i duplicati viene ignorata nell'esempio.
|
||||
|
||||
\begin{itemize}
|
||||
|
||||
\item L’ultimo task presenta una priorità gerarchicamente minore, di conseguenza viene copiato nella cella sottostante.
|
||||
|
||||
\includegraphics[width=0.7\textwidth]{S_10_EXAMPLE/S_10_ITERATION1.png}
|
||||
|
||||
\item Si passa quindi al task soprastante. Anche questo presenta una priorità inferiore e viene pertanto copiato nella cella sottostante.
|
||||
|
||||
\includegraphics[width=0.7\textwidth]{S_10_EXAMPLE/S_10_ITERATION2.png}
|
||||
|
||||
\item Il task nella cella 1 presenta invece una priorità maggiore o uguale: il nuovo task viene quindi inserito nella cella sottostante.
|
||||
|
||||
\includegraphics[width=0.87\textwidth]{S_10_EXAMPLE/S_10_ITERATION3.png}
|
||||
|
||||
\item Infine, viene aggiornato il contatore.
|
||||
|
||||
\end{itemize}
|
||||
\newpage
|
||||
|
||||
|
||||
|
||||
|
||||
\vspace{0.5cm}
|
||||
|
||||
\centerline{\includegraphics[width=0.7\textwidth]{DIAGRAMS/S_10_DIAGRAM.png}}
|
||||
\vspace{0.5cm}
|
||||
Gli stati presenti sono 8:
|
||||
\begin{itemize}
|
||||
\item \textbf{S\_10\_PLACE\_AT\_START:} Scarta le richieste con ID = 0 e avvia la scansione duplicati dall'ultimo task della lista.
|
||||
|
||||
\item \textbf{S\_10\_WAIT\_FOR\_CHECK:} Stato cuscinetto della fase di scansione. Serve per dare tempo alla RAM di leggere il contenuto del task selezionato.
|
||||
|
||||
\item \textbf{S\_10\_CHECK\_ID:} Confronta l'ID del task letto con quello da inserire. Se coincidono, l'operazione termina senza modifiche; se la scansione ha raggiunto la cima della lista, rilegge l'ultimo task e passa alla fase di inserimento; altrimenti prosegue la scansione verso l'alto.
|
||||
|
||||
\item \textbf{S\_10\_WAIT:} Stato cuscinetto della fase di inserimento. Serve per dare tempo alla RAM di leggere il contenuto del task selezionato.
|
||||
|
||||
\item \textbf{S\_10\_COMPARE:} Verifica la condizione di inserimento del nuovo task.
|
||||
Se tutta la lista è stata scorsa (o era vuota), il nuovo task viene scritto in testa.
|
||||
In caso contrario, se il task da inserire presenta una priorità numericamente maggiore o uguale rispetto al task corrente, viene scritto nella cella sottostante;
|
||||
se invece presenta una priorità numericamente minore, è il task corrente a venire copiato nella cella sottostante.
|
||||
|
||||
\item \textbf{S\_10\_GO\_NEXT:} Seleziona il task precedente nella lista, da confrontare al giro successivo.
|
||||
|
||||
\item \textbf{S\_10\_UPDATE\_COUNT:} Aggiorna il contatore con il numero totale di task presenti nella lista.
|
||||
|
||||
\item \textbf{S\_10\_WAIT\_FOR\_COUNT:} Attende il commit della scrittura del contatore, poi transita in \textbf{S\_DONE}.
|
||||
|
||||
\end{itemize}
|
||||
\newpage
|
||||
|
||||
|
||||
\subsubsection{Operazione 11}
|
||||
Questa operazione svuota completamente la lista impostando il contatore dei task a 0 (non è necessario resettare tutti i valori nella memoria).
|
||||
|
||||
\vspace{0.5cm}
|
||||
\centerline{\includegraphics[width=0.7\textwidth]{DIAGRAMS/S_11_DIAGRAM.png}}
|
||||
\vspace{0.5cm}
|
||||
Gli stati presenti sono 2:
|
||||
\begin{itemize}
|
||||
\item \textbf{S\_11\_UPDATE\_COUNT:} Imposta il contatore a 0.
|
||||
|
||||
\item \textbf{S\_11\_WAIT\_FOR\_COUNT:} Attende il commit della scrittura del contatore, poi transita in \textbf{S\_DONE}.
|
||||
|
||||
\end{itemize}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\newpage
|
||||
\section{Risultati sperimentali}
|
||||
\subsection{Report di sintesi}
|
||||
\subsubsection{Risorse utilizzate}
|
||||
La seguente tabella mostra le risorse hardware occupate dal design sul dispositivo target Artix-7 FPGA xc7a200tfbg484-1. L'utilizzo è estremamente contenuto: le Slice LUT occupano solo lo 0.13\% delle risorse disponibili e i registri lo 0.03\%, confermando che il modulo è decisamente leggero. Inoltre, non è stato inferito alcun latch: tutti gli elementi di memoria sono flip-flop, a conferma che il processo combinatorio assegna un valore di default a ogni segnale in ogni ramo.
|
||||
|
||||
\begin{table}[H]
|
||||
\centering
|
||||
\caption{Risorse utilizzate -- Slice Logic}
|
||||
\label{tab:utilization}
|
||||
\begin{tabular}{lrrrrr}
|
||||
\toprule
|
||||
\textbf{Site Type} & \textbf{Used} & \textbf{Fixed} & \textbf{Prohibited} & \textbf{Available} & \textbf{Util\%} \\
|
||||
\midrule
|
||||
Slice LUTs* & 181 & 0 & 0 & 134600 & 0.13 \\
|
||||
\quad LUT as Logic & 181 & 0 & 0 & 134600 & 0.13 \\
|
||||
\quad LUT as Memory & 0 & 0 & 0 & 46200 & 0.00 \\
|
||||
Slice Registers & 71 & 0 & 0 & 269200 & 0.03 \\
|
||||
\quad Register as Flip Flop & 71 & 0 & 0 & 269200 & 0.03 \\
|
||||
\quad Register as Latch & 0 & 0 & 0 & 269200 & 0.00 \\
|
||||
F7 Muxes & 0 & 0 & 0 & 67300 & 0.00 \\
|
||||
F8 Muxes & 0 & 0 & 0 & 33650 & 0.00 \\
|
||||
Unique Control Sets & 6 & -- & 0 & 33650 & 0.02 \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
\newpage
|
||||
|
||||
|
||||
\subsubsection{FSM codificata}
|
||||
La tabella riporta la codifica degli stati FSM generata automaticamente dal tool di sintesi. Sono presenti in totale 24 stati. Vivado ha scelto una codifica \textbf{one-hot} (un flip-flop per stato, 24 bit complessivi), tipica sulle FPGA: aumenta il numero di registri, risorsa abbondante, ma minimizza la logica di decodifica dello stato e ne accorcia i percorsi combinatori. Per compattezza la tabella riporta, per ogni stato, l'indice del bit attivo della codifica one-hot e la codifica sequenziale a 5 bit di partenza.
|
||||
\begin{table}[H]
|
||||
\caption{FSM -- Codifica degli stati}
|
||||
\label{tab:fsm-encoding}
|
||||
\centering
|
||||
\begin{tabular}{lcc}
|
||||
\toprule
|
||||
\textbf{Stato} & \textbf{One-hot (bit attivo)} & \textbf{Previous Encoding} \\
|
||||
\midrule
|
||||
\texttt{s\_reset} & 0 & 00001 \\
|
||||
\texttt{s\_done} & 1 & 00010 \\
|
||||
\texttt{s\_idle} & 2 & 00000 \\
|
||||
\texttt{s\_00\_read} & 3 & 00011 \\
|
||||
\texttt{s\_00\_wait} & 4 & 00100 \\
|
||||
\texttt{s\_00\_check} & 5 & 00101 \\
|
||||
\texttt{s\_00\_go\_next} & 6 & 00110 \\
|
||||
\texttt{s\_01\_check\_number} & 7 & 00111 \\
|
||||
\texttt{s\_01\_wait} & 8 & 01000 \\
|
||||
\texttt{s\_01\_write} & 9 & 01001 \\
|
||||
\texttt{s\_01\_check\_end} & 10 & 01010 \\
|
||||
\texttt{s\_01\_wait\_for\_count}& 11 & 01101 \\
|
||||
\texttt{s\_01\_copy} & 12 & 01011 \\
|
||||
\texttt{s\_01\_go\_next} & 13 & 01100 \\
|
||||
\texttt{s\_10\_place\_at\_start}& 14 & 01110 \\
|
||||
\texttt{s\_10\_wait\_for\_check}& 15 & 01111 \\
|
||||
\texttt{s\_10\_check\_id} & 16 & 10000 \\
|
||||
\texttt{s\_10\_wait} & 17 & 10001 \\
|
||||
\texttt{s\_10\_compare} & 18 & 10010 \\
|
||||
\texttt{s\_10\_update\_count} & 19 & 10100 \\
|
||||
\texttt{s\_10\_wait\_for\_count}& 20 & 10101 \\
|
||||
\texttt{s\_10\_go\_next} & 21 & 10011 \\
|
||||
\texttt{s\_11\_update\_count} & 22 & 10110 \\
|
||||
\texttt{s\_11\_wait\_for\_count}& 23 & 10111 \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
\newpage
|
||||
|
||||
|
||||
|
||||
\subsubsection{Statistiche RTL}
|
||||
La tabella dettaglia i componenti RTL inferiti dal tool di sintesi a partire dal codice VHDL. Sono presenti sommatori a 16, 9 e 8 bit per l'aritmetica su indirizzi, priorità e contatore. I registri a 16, 8, 6 e 1 bit corrispondono ai segnali interni e alle uscite registrate del design. I multiplexer a 24 ingressi riflettono la selezione tra i 24 stati della FSM (quelli a 24 bit operano sulla codifica one-hot dello stato).
|
||||
\begin{table}[H]
|
||||
\caption{Statistiche RTL -- Componenti}
|
||||
\label{tab:rtl-stats}
|
||||
\centering
|
||||
\small
|
||||
\begin{tabular}{rlrl}
|
||||
\toprule
|
||||
\textbf{Ingressi} & \textbf{Bit} & \textbf{Tipo} & \textbf{Quantità} \\
|
||||
\midrule
|
||||
\multicolumn{4}{l}{\textit{Adders}} \\
|
||||
2 & 16 bit & Adder & 4 \\
|
||||
2 & 9 bit & Adder & 1 \\
|
||||
2 & 8 bit & Adder & 3 \\
|
||||
\midrule
|
||||
\multicolumn{4}{l}{\textit{Registers}} \\
|
||||
-- & 16 bit & Register & 1 \\
|
||||
-- & 8 bit & Register & 2 \\
|
||||
-- & 6 bit & Register & 2 \\
|
||||
-- & 1 bit & Register & 3 \\
|
||||
\midrule
|
||||
\multicolumn{4}{l}{\textit{Muxes}} \\
|
||||
24 & 24 bit & Mux & 1 \\
|
||||
4 & 24 bit & Mux & 1 \\
|
||||
2 & 24 bit & Mux & 7 \\
|
||||
2 & 16 bit & Mux & 3 \\
|
||||
24 & 16 bit & Mux & 1 \\
|
||||
2 & 8 bit & Mux & 4 \\
|
||||
24 & 8 bit & Mux & 2 \\
|
||||
2 & 6 bit & Mux & 1 \\
|
||||
24 & 6 bit & Mux & 2 \\
|
||||
2 & 1 bit & Mux & 1 \\
|
||||
24 & 1 bit & Mux & 6 \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
\newpage
|
||||
|
||||
|
||||
|
||||
\subsubsection{Timing}
|
||||
La specifica richiede che il progetto funzioni con un periodo di clock di almeno 20 ns. Il requisito è stato verificato in sintesi applicando il vincolo \texttt{create\_clock -period 20.000} sul segnale \texttt{i\_clk}:
|
||||
|
||||
\begin{table}[H]
|
||||
\centering
|
||||
\caption{Design Timing Summary (periodo di clock 20 ns)}
|
||||
\label{tab:timing}
|
||||
\begin{tabular}{lrr}
|
||||
\toprule
|
||||
\textbf{Metrica} & \textbf{Slack (ns)} & \textbf{Endpoint in violazione} \\
|
||||
\midrule
|
||||
Worst Negative Slack (setup, WNS) & $+14.786$ & 0 / 114 \\
|
||||
Worst Hold Slack (WHS) & $+0.149$ & 0 / 114 \\
|
||||
Worst Pulse Width Slack (WPWS) & $+9.500$ & 0 / 72 \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{table}
|
||||
|
||||
Lo slack di setup ampiamente positivo indica che il percorso critico è di circa 5.2 ns: il modulo rispetta il vincolo dei 20 ns con un margine di quasi 4 volte. La correttezza funzionale del circuito sintetizzato è inoltre confermata dalla simulazione post-sintesi (functional) di tutti i test bench descritti nella sezione successiva.
|
||||
\newpage
|
||||
|
||||
\subsection{Report di simulazioni}
|
||||
\subsubsection{Test bench 1}
|
||||
Il test bench di esempio fornito dal docente copre le operazioni base quali reset, inserimento in lista, rimozione dalla lista, decremento di priorità e svuotamento della lista.
|
||||
|
||||
Seppur non vengano coperti molti casi limite, questo test bench ci offre la possibilità di analizzare facilmente i tempi di esecuzione delle singole operazioni.
|
||||
Le 10 operazioni, infatti, vengono eseguite correttamente in 2540 ns.\\
|
||||
In particolar modo, le latenze in cicli di clock (periodo 20 ns), con \textbf{N} task presenti in lista e \textbf{k} task spostati, sono le seguenti:
|
||||
\begin{itemize}
|
||||
\item \textbf{OP 00}: $(4 + 3N) \cdot 20\,$ns
|
||||
\item \textbf{OP 01}: $(6 + 3k) \cdot 20\,$ns, con $k = N - 1$; lista vuota: $2 \cdot 20\,$ns
|
||||
\item \textbf{OP 10}: $(6 + 2\max(N,1) + 3k) \cdot 20\,$ns
|
||||
\item \textbf{OP 11}: $3 \cdot 20\,$ns
|
||||
\end{itemize}
|
||||
|
||||
Nota: nell'operazione \textbf{10} il termine $2\max(N,1)$ è il costo della scansione duplicati, che percorre sempre l'intera lista, mentre $3k$ è il costo degli spostamenti, con $k$ compreso tra 0 (inserimento in fondo) e $N$ (inserimento in testa).
|
||||
Per caratterizzare il comportamento medio, si considera una distribuzione delle priorità equiprobabile: $E[T] = \left(6 + \frac{25}{8}N\right) \cdot 20\,$ns.
|
||||
|
||||
Tutte le formule sono state verificate al ciclo esatto da un test bench dedicato (par. 3.2.3).
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=1\textwidth]{WAVEFORM/RESET.png}
|
||||
\caption{Operazione di reset.}
|
||||
\label{fig:reset}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=1\textwidth]{WAVEFORM/INSERIMENTO_VUOTA.png}
|
||||
\caption{Operazione di inserimento in lista vuota.}
|
||||
\label{fig:insert_empty}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=1\textwidth]{WAVEFORM/SVUOTA.png}
|
||||
\caption{Operazione di svuotamento della lista.}
|
||||
\label{fig:empty}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=1\textwidth]{WAVEFORM/INSERIMENTO_PIENA.png}
|
||||
\caption{Operazione di inserimento in lista popolata.}
|
||||
\label{fig:insert_full}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=1\textwidth]{WAVEFORM/RIMOZIONE.png}
|
||||
\caption{Operazione di rimozione di un task.}
|
||||
\label{fig:remove}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=1\textwidth]{WAVEFORM/DECREMENTA.png}
|
||||
\caption{Operazione di decremento della priorità.}
|
||||
\label{fig:decrease}
|
||||
\end{figure}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\newpage
|
||||
|
||||
\subsubsection{Test bench 2 (casi limite)}
|
||||
Il secondo test bench è stato pensato per coprire i possibili casi limite che potrebbero presentarsi:
|
||||
|
||||
\begin{table}[H]
|
||||
\centering
|
||||
\renewcommand{\arraystretch}{1.6}
|
||||
\begin{tabular}{|m{6cm}|m{8cm}|}
|
||||
\hline
|
||||
\textbf{Caso testato} & \textbf{Descrizione} \\
|
||||
\hline
|
||||
DONE durante il reset & DONE rimane a 1 durante reset e inizializzazione. \\
|
||||
\hline
|
||||
Reset asincrono & Reset durante operazioni in corso: il modulo torna allo stato iniziale senza corrompere la memoria. \\
|
||||
\hline
|
||||
Operazioni su lista vuota & Rimozione, decremento e svuotamento su lista vuota non producono scritture. La rimozione restituisce ID = 000000. \\
|
||||
\hline
|
||||
Saturazione della priorità & Task già a priorità 11 non vengono modificati da ulteriori decrementi. \\
|
||||
\hline
|
||||
Ordinamento e FIFO & Inserimenti con priorità diverse e tra task di pari priorità; l'ordine di estrazione è verificato con rimozioni successive. \\
|
||||
\hline
|
||||
ID duplicati e ID = 0 & L'inserimento viene ignorato se l'ID è già presente o vale 0; DONE viene emesso comunque. \\
|
||||
\hline
|
||||
Sequenza di stress & Inserimenti, invecchiamenti, rimozioni e svuotamento in sequenza mista. \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\caption*{Casi limite testati nel test bench 2}
|
||||
\label{tab:testbench2}
|
||||
\end{table}
|
||||
|
||||
\subsubsection{Test bench 3 (latenze)}
|
||||
Un terzo test bench misura, per ciascuna operazione, il numero esatto di cicli di clock che intercorrono tra il campionamento di START e l'assertion di DONE, confrontandolo con le formule di latenza riportate nel paragrafo 3.2.1. Le 15 misure (inserimenti con 0--3 spostamenti e inserimento in fondo, rimozioni con lista vuota e con 1--4 task, invecchiamenti con 0--4 task incluso il caso di saturazione completa) coincidono tutte al ciclo esatto con il valore atteso: la FSM non contiene quindi stati morti né attese superflue.
|
||||
|
||||
Tutti e tre i test bench passano sia in simulazione comportamentale sia in simulazione post-sintesi functional.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\newpage
|
||||
\section{Conclusioni}
|
||||
I test comportamentali e post-sintesi mostrano che il modulo funziona correttamente, rispettando la specifica.
|
||||
Il componente completa l'elaborazione del test bench di esempio in 2540 ns, con un utilizzo delle risorse hardware
|
||||
estremamente contenuto: le Slice LUT occupano lo 0.13\% delle risorse disponibili sul
|
||||
dispositivo target Artix-7 FPGA xc7a200tfbg484-1, senza alcun latch inferito, confermando la leggerezza e la pulizia del design. Il vincolo di clock di 20 ns è rispettato con ampio margine (WNS $+14.786$ ns, percorso critico $\approx 5.2$ ns).
|
||||
|
||||
In fase di progettazione ho scelto deliberatamente di adottare un numero di stati superiore allo stretto necessario, privilegiando la leggibilità rispetto all'efficienza. Questa scelta, pur garantendo la correttezza del comportamento, introduce una leggera inefficienza temporale:
|
||||
accorpando o eliminando alcuni stati intermedi sarebbe possibile ridurre la latenza complessiva di qualche punto percentuale.
|
||||
Ad esempio, gli stati iniziali di alcune operazioni possono essere accorpati nello stato \textbf{S\_IDLE}, all'interno del ramo di decodifica dell'operazione corrispondente.
|
||||
|
||||
|
||||
\end{document}
|
||||
Reference in New Issue
Block a user