\chapter{Sistemi Logici Complessi}


\section{Introduzione}

In questo capitolo tratteremo sistemi logici costituiti da insiemi di
porte logiche, Flip-Flop ed, in alcuni casi, memorie. Tra questi
rientrano quelle che sono note come \index{macchina a stati finiti}
``macchine a stati finiti'', che trovano numerosissime
\Index{applicazioni} pratiche. Esse sono adoperate in sistemi
automatici di apertura/chiusura di accessi, in macchine per
distribuzione di bevande o altro, nei videogiochi, nei telefonini,
semafori etc.

Passeremo poi ad esaminare la struttura base dei microprocessori e
microcontrollori. Tra questi ultimi analizzeremo in dettaglio, a
titolo di esempio, un particolare modello: il \Index{16F877} della
\Index{Microchip\textsuperscript{\textregistered}}.

Data l'importanza che essi hanno sia nella struttura interna dei
processori, che nella comunicazione con periferiche, discuteremo anche
la struttura dei diversi tipi di BUS adoperati.



\section{Macchine a stati finiti}

Un semplice esempio concreto che si presta ad illustrare la struttura
a blocchi di una \Index{macchina a stati finiti} \`e offerto dalla
barra automatica che consente l'accesso ai binari di una
metropolitana. La figura~\ref{logici_fsm_1} mostra lo schema a blocchi
di una tale macchina, limitatamente alla struttura base.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/logici_fsm_1,width=9.0 cm,height=3.5 cm}}\end{center}
\caption{Schema a blocchi della \Index{macchina a stati finiti} che
controlla l'apertura e chiusura della sbarra d'accesso ad una
metropolitana.}  \protect\label{logici_fsm_1}
\end{figure}

La macchina ha solo due stati: ``bloccato'' e ``sbloccato''. Quando
essa \`e nel primo di questi stati una persona pu\`o, inserendo un
biglietto, sbloccarla. La macchina passa ora nello stato
``sbloccato'', come mostrato nel disegno dalla linea che indica la
transizione causata dall'\emph{azione} ``immissione del
\emph{biglietto}''.

L'etichetta associata alla transizione ha due parti, separate da uno
``/''. La prima di queste indica l'\emph{evento} che causa la
transizione, la seconda il nome dell'\emph{azione} che sar\`a eseguita
una volta che l'evento si sia verificato. L'azione porta il sistema
nello stato ``sbloccato''. Analogamente vediamo che all'evento
``passaggio'' segue l'azione ``blocco'', che porta il sistema nello
stato bloccato.

Dobbiamo, per completezza, vedere come descrivere situazioni anomale
che possono verificarsi.  Ad esempio, cosa accade se qualcuno cerca di
passare senza aver inserito il biglietto?  Possiamo prevedere che in
tal caso la barra rimanga bloccata, e scatti un allarme. L'altra
situazione anomala che potremmo prevedere \`e che la barra sia gi\`a
aperta e la persona inserisca un secondo biglietto. Le modifiche che
potrebbero esser apportate al precedente schema a blocchi, per ovviare
a queste situazioni anomale sono illustrate in
figura~\ref{logici_fsm_2}.


\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/logici_fsm_2,width=10.0 cm,height=4.0 cm}}\end{center}
\caption{Schema a blocchi modificato della \Index{macchina a stati
finiti} che controlla l'apertura e chiusura della sbarra d'accesso ad
una metropolitana.} \protect\label{logici_fsm_2}
\end{figure}
 
Vediamo dalla figura che nel primo dei due casi ipotizzati lo stato
del sistema non cambia (la sbarra rimane bloccata) ma scatta un
segnale d'allarme. Nel secondo, la sbarra rimane sbloccata, ma il
passeggero si sente rivolgere un ``grazie''!

Se il passeggero \`e passato senza aver introdotto un biglietto, la
sbarra potrebbe esser stata danneggiata. In tal caso un semplice
allarme pu\`o non esser sufficiente.  Potremmo voler far passare il
sistema in un nuovo stato, che definiremmo ``violazione'' e farlo
rimanere in tale stato fino all'intervento di un tecnico. La
figura~\ref{logici_fsm_3} illustra le modifiche apportate con
l'introduzione di tale nuovo stato.
 
\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/logici_fsm_3,width=9.0 cm,height=7.5 cm}}\end{center}
\caption{Aggiunta di uno stato ``violazione'' allo schema a blocchi
della \Index{macchina a stati finiti} che controlla l'apertura e
chiusura della sbarra d'accesso ad una metropolitana.}
\protect\label{logici_fsm_3}
\end{figure} 

Notiamo che ora il sistema pu\`o uscire dallo stato ``violazione'' a
seguito di un \emph{evento} ``pronto'', con che esso torna nello stato
normale ``bloccato''. Abbiamo inserito anche un nuovo stato (uno
pseudo-stato, indicato da un pallino nero) in cui la macchina si trova
quando \`e spenta. L'accensione fa passare la macchina nello stato
iniziale (bloccato).

L'esempio presentato, estremamente semplice (ma che pu\`o divenire
estremamente complicato nella realt\`a) illustra i concetti
fondamentali che sono alla base di una \Index{macchina a stati finiti}
(cui per brevit\`a ci riferiremo nel seguito come FSM, per Finite
State Machine). I concetti base sono quelli di ``stato'' di ``azione''
e di ``transizione'' tra stati.

Esaminiamo in dettaglio un esempio tratto dall'elettronica digitale:
un circuito che verifica la parit\`a di una serie di bit. L'output del
circuito dovr\`a essere \emph{alto} se in ingresso \`e arrivato un
numero dispari di ``1'', \emph{basso} nel caso contrario.

Definiamo ``stato dispari'' del circuito quello associato alla prima
situazione, ``stato pari'' il secondo. La figura~\ref{logici_fsm_4}
mostra gli stati e le transizioni tra di essi.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/logici_fsm_4,width=6.0 cm,height=6.0 cm}}\end{center}
\caption{Schema a blocchi di una FSM per la generazione del bit di
parit\`a di una stringa di bits.} \protect\label{logici_fsm_4}
\end{figure} 

Vediamo dal diagramma che se il sistema \`e nello stato ``pari'' ed il
prossimo bit in arrivo \`e un ``1'', esso passa nello stato
``dispari''. Da questo, se il bit successivo \`e ancora un ``1'', il
sistema ritorna nello stato ``pari''. Se invece il bit \`e uno ``0'',
il sistema non cambia stato, come indicato dalle linee chiuse
(bit=0). All'interno del simbolo di ciascuno dei due stati abbiamo
evidenziato in parentesi quadra l'output del sistema.

Il diagramma di figura~\ref{logici_fsm_4} si traduce facilmente in una
tabella delle verit\`a. Questa \`e la~\ref{tab_logici_fsm_1}.



\begin{table}[htb!]
        \begin{center}
                \begin{tabular}{| c | c  || l | c |}
\hline Stato & Bit in & Stato & output \\ Attuale & ingresso &
 Successivo & \\ \hline pari & 0 & pari & 0 \\ pari & 1 & dispari & 0
 \\ dispari & 0 & dispari & 1 \\ dispari & 1 & pari & 1 \\ \hline
                \end{tabular}
\caption{Tabella delle verit\`a per il diagramma a blocchi del
\Index{generatore del bit di parit\`a} di figura~\ref{logici_fsm_4}.}
\protect\label{tab_logici_fsm_1}
        \end{center}
\end{table}

Notiamo che l'output \`e quello associato allo \emph{Stato Attuale},
non allo \emph{Stato Successivo}. Indicando con l'abbreviazione StA lo
Stato Attuale e con StS lo Stato Successivo, e definendo ``0'' lo
stato pari ed ``1'' quello dispari, la precedente tabella diviene
la~\ref{tab_logici_fsm_2}.

\begin{table}[htb!]
        \begin{center}
                \begin{tabular}{| c | c  || c | c |}
\hline Stato & Bit in & Stato & output \\ Attuale & ingresso &
 Successivo & \\ \hline 0 & 0 & 0 & 0 \\ 0 & 1 & 1 & 0 \\ 1 & 0 & 1 &
 1 \\ 1 & 1 & 0 & 1 \\ \hline
                \end{tabular}
\caption{Tabella delle verit\`a modificata per il diagramma a blocchi
del generatore del bit di parit\`a di figura~\ref{logici_fsm_4}.}
\protect\label{tab_logici_fsm_2}
        \end{center}
\end{table}

Da questa tabella vediamo che:
\[
StS=StA \oplus Bit
\]
Tale funzione \`e di conseguenza facilmente implementabile facendo uso
di un OR esclusivo e di un FF di tipo D, come mostrato in
figura~\ref{logici_fsm_5}.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/logici_fsm_5,width=7.0 cm,height=2.5 cm}}\end{center}
\caption{Circuito che implementa una FSM per la generazione del bit di
parit\`a di una stringa di bits.} \protect\label{logici_fsm_5}
\end{figure} 

Il circuito \`e di tipo sincrono, cio\`e il cambiamento di stato ha
luogo, dopo che il Bit sia stato fornito all'ingresso dell'XOR, in
corrispondenza al fronte di salita dell'impulso di clock. L'uscita
dell'XOR definisce lo Stato Successivo, mentre il Q del FF fornisce la
parit\`a associata allo Stato Attuale.

Un'analisi della tabella consente di proporre un'implementazione
alternativa della medesima macchina. Notiamo infatti che se l'input
(Bit) \`e uguale a ``0'', lo stato non cambia con l'arrivo
dell'impulso di clock. Se l'input \`e invece ``1'', lo Stato
Successivo \`e il complemento di quello Attuale. Ci\`o suggerisce di
far ricorso ad un FF di tipo JK, come mostrato in
figura~\ref{logici_fsm_6}.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/logici_fsm_6,width=7.0 cm,height=4.0 cm}}\end{center}
\caption{Circuito che implementa una FSM per la generazione del bit di
parit\`a di una stringa di bits, con l'uso di un FF di tipo JK.}
\protect\label{logici_fsm_6}
\end{figure} 

Notiamo che lo Stato Attuale non figura pi\`u esplicitamente in questa implementazione.
Anche in questo caso \`e importante che il Bit in ingresso sia stabile
prima del fronte di salita dell'impulso di clock.

\subsection{Temporizzazioni nelle FSM}

Si preferisce in genere che una macchina di stato funzioni in modo
\emph{sincrono}, cio\`e che tutti i FF che la compongono effettuino il
passaggio da uno stato a quello successivo all'arrivo del medesimo
impulso di clock.

Come accennato nell'ultimo esempio esaminato, occorre che tutti gli
inputs ed outputs siano \emph{stabili} all'arrivo dell'impulso di
clock. La \emph{validit\`a} degli output dovr\`a essere assicurata
dopo il fronte di salita (o di discesa) del clock.

Per chiarire tali concetti, esaminiamo l'esempio di due FSM
comunicanti, come quelle mostrate schematicamente in
figura~\ref{logici_fsm_7}.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/logici_fsm_7,width=5.0 cm,height=1.4cm}}\end{center}
\caption{Due FSM che comunicano tra loro. La macchina FSM1 riceve in
ingresso l'output Y della FSM2 e viceversa.}
\protect\label{logici_fsm_7}
\end{figure} 

Ammettiamo che entrambe le macchine siano sincrone, con transizione
sul fronte di salita del clock e che l'output X della FSM1 sia l'input
della FSM2, mentre l'output Y della FSM2 sia l'input della FSM1.

Ammettiamo inoltre che entrambe le macchine abbiano due soli stati, A
e B per la FSM1, C e D per la FSM2. Ciascuna delle due macchine
inoltre cambi stato se al suo ingresso \`e presente, all'arrivo del
segnale di clock, un livello \emph{alto}, mentre rimanga nello stato
precedente se il segnale all'ingresso \`e \emph{basso}.  La
figura~\ref{logici_fsm_8} mostra il segnale di clock, la successione
degli stati in cui ciascuna delle due macchine verr\`a a trovarsi ed i
segnali X ed Y alle uscite.


\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/logici_fsm_8,width=6.5 cm,height=6.0 cm}}\end{center}
\caption{Successione degli stati e forme d'onda alle uscite di due FSM
comunicanti.  La forma d'onda in alto \`e il clock comune alle due
macchine.} \protect\label{logici_fsm_8}
\end{figure} 

La FSM1 sta per entrare nello stato A all'arrivo del secondo impulso
di clock, mentre la FSM2 \`e nello stato C, con l'uscita Y
bassa. Durante il secondo ciclo di clock, la FSM1 \`e nello stato A,
con X alto, mentre la FSM2 \`e in C, con Y basso. Con il terzo impulso
di clock l'input Y alla FSM1 \`e ancora basso, quindi essa rimane
nello stato A. L'input X alla FSM2 \`e alto, il che fa si che essa
passi nello stato D.  Con il quarto impulso di clock la FSM1, che ora
ha l'ingresso Y alto, passa nello stato B, mentre l'ingresso X della
FSM2 \`e divenuto alto da troppo poco tempo perch\'e essa possa
effettuare la transizione; quindi essa rimane nello stato D. Ora X \`e
basso mentre Y \`e alto. Con il quinto impulso di clock, la FSM1 passa
nello stato A mentre la FSM2 rimane in D. Con il sesto impulso di
clock, essendo sia X che Y alti, entrambe le macchine cambiano stato,
passando rispettivamente in B ed in C.

\subsection{FSM per il controllo di una \Index{macchina distributrice}}

Consideriamo un problema lievemente pi\`u complicato di quelli
esaminati finora: quello di una FSM per il controllo di una macchina
che, dopo l'inserimento di una certa somma, eroga una qualche bevanda.
Ammettiamo che il costo della bevanda sia 15 centesimi e che il
pagamento possa esser effettuato in monetine da 5 e da 10
centesimi. Indicando con ``C'' la moneta da 5 centesimi e con ``D''
quella da 10, la sequenza delle monetine da immettere potr\`a essere:
\begin{enumerate}

\item C, C, C

\item C, C, D

\item D, C

\item D, D

\item C, D

\end{enumerate}

Il secondo ed il quarto caso corrispondono a situazioni in cui la
persona ha erroneamente immesso pi\`u del necessario.

Il corrispondente diagramma degli stati \`e mostrato in
figura~\ref{logici_fsm_9}.


\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/logici_fsm_9,width=9.0 cm,height=7.0 cm}}\end{center}
\caption{Diagramma degli stati della FSM per il controllo di una
macchina per la distribuzione di bevande.}
\protect\label{logici_fsm_9}
\end{figure} 

Non abbiamo indicato le transizioni che non implicano un cambiamento
di stato. Ad esempio, nello stato $S_0$, se non \`e stata immessa
alcuna moneta, la macchina dovr\`a restare nel medesimo stato, anche
se ci\`o non \`e indicato in modo esplicito.

Il diagramma pu\`o esser semplificato, tenendo conto del fatto che gli
stati $S_4$, $S_5$,$S_6$,$S_7$,$S_8$ corrispondono al medesimo stato
(erogazione). Possiamo semplificare ulteriormente lo schema di figura,
pensando a ciascuno stato come definito dalla somma totale immessa
fino a quell'istante. Cio\`e, lo stato $S_1$ corrisponde a ``5c'', gli
stati $S_2$ ed $S_3$ a ``10c'', etc.  Si pu\`o allora ridisegnare il
diagramma come mostrato in figura~\ref{logici_fsm_10}.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/logici_fsm_10,width=4.0 cm,
height=8.0 cm}}\end{center}
\caption{Diagramma degli stati semplificato della FSM per il controllo
di una macchina per la distribuzione di bevande.}
\protect\label{logici_fsm_10}
\end{figure} 

Vediamo che ora gli stati sono solo quattro. Inoltre la transizione
dallo stato ``10c'' allo stato ``15c'' pu\`o esser causata sia
dall'azione ``C'', che dalla ``D'' (cio\`e dall'OR delle
due). Dall'ultimo diagramma si ottiene poi la tabella delle
verit\`a~\ref{tab_logici_fsm_3}.


\begin{table}[htb!]
        \begin{center}
                \begin{tabular}{| c | c | c || c | c |}
\hline \emph{Stato} & \multicolumn{2}{c||}{\emph{Input}} &
\emph{Stato} & \emph{Output} \\ \emph{Attuale} & D & C &
\emph{Successivo} & \\ \hline 0c & 0 & 0 & 0c & 0 \\ 0c & 0 & 1 & 5c &
0 \\ 0c & 1 & 0 & 10c & 0 \\ 0c & 1 & 1 & 15c & 0 \\ \hline 5c & 0 & 0
& 5c & 0 \\ 5c & 0 & 1 & 10c & 0 \\ 5c & 1 & 0 & 15c & 0 \\ 5c & 1 & 1
& 15c & 0 \\ \hline 10c & 0 & 0 & 10c & 0 \\ 10c & 0 & 1 & 15c & 0 \\
10c & 1 & 0 & 15c & 0 \\ 10c & 1 & 1 & 15c & 0 \\ \hline 15c & X & X &
15c & 1 \\ \hline
                \end{tabular}
\caption{Tabella delle verit\`a per il diagramma a blocchi di
figura~\ref{logici_fsm_10}.} \protect\label{tab_logici_fsm_3}
        \end{center}
\end{table}

Notiamo che \`e stato previsto il caso in cui siano state immesse
contemporaneamente sia la moneta da 5c che quella da 10c. Inoltre,
l'erogazione \`e associata allo stato ``15'' (anche se raggiunto con
l'immissione di una somma pi\`u alta !).

Associamo ora agli stati ``0c'', ``5c'', ``10c'', ``15c'' le
configurazioni di due bit, rispettivamente uguali a:
\[
0c \rightarrow 00
\]
\[
5c \rightarrow 01
\]
\[
10c \rightarrow 10
\]
\[
15c \rightarrow 11
\]
La tabella acquista allora la forma~\ref{tab_logici_fsm_4}.

\begin{table}[htb!]
        \begin{center}
                \begin{tabular}{| c | c | c | c || c | c | c |}
\hline \multicolumn{2}{|c|}{\emph{Stato}} &
\multicolumn{2}{c||}{\emph{Input}} & \multicolumn{2}{c|}{\emph{Stato}}
& \emph{Output} \\

\multicolumn{2}{|c|}{\emph{Attuale}} & & &
\multicolumn{2}{c|}{\emph{Successivo}} & \\

$Q_1$ & $Q_0$ & D & C & $D_1$ & $D_0$ & \emph{(erogazione)} \\ \hline
0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & 1 &
0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 1 & 1 & 1 & 0 \\ \hline 0 & 1 & 0 & 0 & 0
& 1 & 0 \\ 0 & 1 & 0 & 1 & 1 & 0 & 0 \\ 0 & 1 & 1 & 0 & 1 & 1 & 0 \\ 0
& 1 & 1 & 1 & 1 & 1 & 0 \\ \hline 1 & 0 & 0 & 0 & 1 & 0 & 0 \\ 1 & 0 &
0 & 1 & 1 & 1 & 0 \\ 1 & 0 & 1 & 0 & 1 & 1 & 0 \\ 1 & 0 & 1 & 1 & 1 &
1 & 0 \\ \hline 1 & 1 & 0 & 0 & 1 & 1 & 1 \\ 1 & 1 & 0 & 1 & 1 & 1 & 1
\\ 1 & 1 & 1 & 0 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & X & X & 1 \\ \hline
                \end{tabular}
\caption{Forma modificata della tabella delle verit\`a per il
diagramma a blocchi di figura~\ref{logici_fsm_10}.}
\protect\label{tab_logici_fsm_4}
        \end{center}
\end{table}

Dobbiamo ora realizzare il circuito che implementa tale macchina. Per
farlo, cominciamo con il minimizzare la tabella facendo uso delle
mappe~K per ciascuna delle funzioni $D_1$, $D_0$, $Output$. Le mappe
ottenute sono mostrate nelle
figure~\ref{logici_fsm_11},~\ref{logici_fsm_12},~\ref{logici_fsm_13}.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/logici_fsm_11,width=8.5 cm,height=8.5 cm}}\end{center}
\caption{Mappa di Karnaugh per la variabile $D_1$, ottenuta dalla
tabella~\ref{tab_logici_fsm_4}.} \protect\label{logici_fsm_11}
\end{figure} 

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/logici_fsm_12,width=8.0 cm,height=8.0 cm}}\end{center}
\caption{Mappa di Karnaugh per la variabile $D_0$, ottenuta dalla
tabella~\ref{tab_logici_fsm_4}.} \protect\label{logici_fsm_12}
\end{figure} 

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/logici_fsm_13,width=6.0 cm,height=6.0 cm}}\end{center}
\caption{Mappa di Karnaugh per la variabile $Output$, ottenuta dalla
tabella~\ref{tab_logici_fsm_4}.} \protect\label{logici_fsm_13}
\end{figure} 

Dall'analisi delle mappe si ottiene:
\[
D_1= Q_1 + Q_0 \cdot C + D
\]
\[
D_0=C \cdot \overline{Q}_0 + Q_0 \cdot \overline{C} + Q_1 \cdot C +
Q_1 \cdot D + D \cdot C
\]
\[
output=Q_1 \cdot Q_0
\]

\`E poi immediato verificare che un circuito che implementa queste
funzioni \`e quello di figura~\ref{logici_fsm_14}.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/logici_fsm_14,width=9.0 cm,height=7.0 cm}}\end{center}
\caption{Circuito che realizza le funzioni riassunte nella
tabella~\ref{tab_logici_fsm_4}.} \protect\label{logici_fsm_14}
\end{figure} 

\section{Microprocessori, Microcontrollori e Microcomputer} 
\index{microprocessore} \index{microcontrollore} \index{microcomputer}
\label{Microprocessori, Microcontrollori e Microcomputer}

\subsection{Introduzione}
 
Ci siamo occupati finora di porte logiche, memorie, flip-flop e, pi\`u
in generale, di sistemi costituiti da combinazioni di porte logiche,
flip-flop, registri/memorie.
  
\`E chiaro che, con una scelta opportuna dei componenti, \`e possibile
costruire sistemi che realizzino una qualsivoglia funzione
logica. Abbiamo esaminato alcuni di tali sistemi: quelli che
effettuano operazioni di somma, sottrazione, moltiplicazione e
divisione di numeri a pi\`u bit, quelli che calcolano la parit\`a di
un numero binario, etc.  Risulterebbe tuttavia assai pesante se si
dovesse costruire un nuovo circuito per ogni nuovo problema. Non \`e
di oggi l'esigenza di sistemi versatili che, opportunamente
``programmati'' si prestino a realizzare molte operazioni, anche di
tipo molto diverso.  In questi sistemi, il problema di realizzare
strutture che implementino funzioni di varia natura, si traduce in
quello di fornire al sistema una sequenza di istruzioni da eseguire;
quello che appunto chiamiamo un ``programma''.
 
I sistemi che eseguono tali sequenze di istruzioni posseggono un
ulteriore grado di flessibilit\`a: essi possono eseguire una certa
sequenza prestabilita di istruzioni, ma eseguirne, a partire da un
certo punto, una diversa se il risultato ottenuto a quel punto ha una
determinata caratteristica.

Si supponga ad esempio di voler far eseguire la sequenza di istruzioni
che segue:
 
\begin{enumerate}
\item si legga un numero N
\item si verifichi se N \`e positivo
\item se N \`e positivo, se ne calcoli la radice quadrata
\item se N \`e negativo, se ne modifichi il segno e si calcoli poi la
radice quadrata
\item si stampi il risultato, attribuendogli il segno del numero N
originale e si fermi l'esecuzione
\end{enumerate}

In questa sequenza vediamo che all'istruzione 2 pu\`o seguire la 3 se
N \`e positivo, mentre seguiranno le 4, 5 se N \`e negativo.
 
 L'esempio fatto, estremamente banale, illustra come l'esecuzione di
 sequenze diverse possa essere condizionata dal verificarsi di
 determinati \emph{eventi}. L'\emph{evento} era nel nostro esempio
 costituito dall'esser negativo il segno del numero dato. In un caso
 generale l'evento pu\`o esser costituito dal risultato ottenuto, in
 una serie di operazioni aritmetiche consecutive, ad un certo punto
 della sequenza. Ad esempio in una sequenza di operazioni che calcola
 il rapporto incrementale di una certa funzione $f(x)$:
\[
R(x_0,\Delta x_i)=\frac{f(x_0+\Delta x_i)-f(x_0)}{\Delta x_i}
\]
per valori decrescenti di $\Delta x_i$, l'evento pu\`o semplicemente
esser costituito dal verificarsi della condizione:

\[
\frac{|R(x_0,\Delta x_i)-R(x_0, \Delta x_{i-1})|}{|R(x_0,\Delta x_i)|}
< \epsilon
\]
con $\epsilon$ una costante data.


\`E anche possibile, in un caso ancor pi\`u generale, che l'evento
abbia un'origine esterna. Si supponga ad esempio di voler realizzare
un dispositivo che mantenga la temperatura di un certo ambiente
attorno ad un valore prestabilito $T_0$, alimentando un condizionatore
che pu\`o anche funzionare da pompa di calore. Il nostro dispositivo
sar\`a collegato, oltre che al condizionatore, ad uno strumento di
misura della temperatura.
 
Le istruzioni dovranno prevedere che:
\begin{enumerate}
\item Il sistema procede ad una prima lettura della temperatura
\item Se la temperatura \`e maggiore di $T_0$, il condizionatore
inizier\`a a raffreddare l'ambiente
\item Il sistema proceder\`a a leggere, ad intervalli di tempo
regolari, la temperatura
\item Se la temperatura diviene minore di $T_0$, il condizionatore,
funzionando ora da pompa di calore, inizier\`a a riscaldare l'ambiente
\item Il sistema proceder\`a a leggere, ad intervalli di tempo
regolari, la temperatura
\item Se la temperatura diviene maggiore di $T_0$ viene nuovamente
eseguito il ciclo di istruzioni a partire dalla 2 (viene effettuato
quello che chiameremo un \emph{\Index{JUMP}}).
\end{enumerate}  

I dispositivi che eseguono tali funzioni sono i
\index{microcontrollore}microcontrollori. Di questi esiste una grande
variet\`a. Essi possono differire per velocit\`a, numero di
connessioni con il mondo esterno, tipo di programmazione, etc.. Il
cuore di un \Index{microcontrollore} \`e il \Index{microprocessore}.
 
Un tipico microprocessore non dispone di periferiche (tastiera,
connessione a stampanti, etc.; in alcuni casi neanche memorie).  Un
\emph{\Index{microcontrollore}}, come anche un
\emph{\Index{microcomputer}} \`e sostanzialmente un
\Index{microprocessore} opportunamente integrato da periferiche,
collegate al microprocessore da apposite linee di comunicazione
(BUS). Un microcontrollore \`e in genere integrato in un singolo
\Index{chip} ed \`e dotato di un numero relativamente elevato di porte
di I/O. Queste possono essere adoperate sia per leggere parametri
fisici esterni forniti da opportuni sensori, sia per controllare
l'operazione di dispositivi esterni.

Ci occuperemo in questa sezione della struttura base di un
\index{microcontrollore}microcontrollore. Passeremo poi, nella
successiva, ad esaminare in dettaglio l'architettura di un
microcontrollore particolare: il \emph{16F877} della
\emph{microchip}. Discuteremo poi le istruzioni base riconosciute da
tale \index{microcontrollore}microcontrollore, e le illustreremo
infine con un esempio concreto.  Non discuteremo in modo esplicito
l'operazione di un \Index{microcomputer}, anche se la pi\`u gran parte
delle considerazioni che faremo, riferite ai microcontrollori, sono
applicabili anche ai microcomputer.

\subsection{Struttura base di un tipico \Index{microcomputer} e di un \index{microcontrollore}microcontrollore}

Un diagramma semplificato di un tipico microcomputer \`e mostrato in
figura~\ref{processori_1}.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/processori_1,width=14.0 cm,
height=8.0 cm}}\end{center}
\caption{Schema di massima di un \Index{microcomputer}.}
\protect\label{processori_1}
\end{figure} 
 
Al cuore del \Index{microcomputer} \`e un
\Index{microprocessore}. Questo riceve vari tipi di dati dall'esterno,
tra cui troviamo:
  
  Le istruzioni che servono al \Index{microprocessore} per poter
  iniziare il proprio lavoro: tipicamente gli ``\Index{indirizzi}'' su
  cui poter leggere il programma da eseguire; gli ``indirizzi'' dove
  scrivere (``indirizzi'' di display e stampanti) le informazioni in
  uscita, l'indirizzo della tastiera e di eventuali sensori o
  pulsanti, etc. Vedremo tra poco cosa intendiamo per ``indirizzi''.
  Tutte le comunicazioni tra il microprocessore ed il mondo esterno
  avvengono attraverso appositi collegamenti elettrici (o in alcuni
  casi ottici) costituiti in genere da gruppi di otto o pi\`u linee
  elettriche dedicate, dette BUS. Nell'esempio di figura un BUS
  (unidirezionale) collega una \Index{ROM} con il microprocessore, un
  secondo BUS (bidirezionale) collega il microprocessore con una
  memoria \index{memoria! dinamica}dinamica (RAM), ulteriori BUS
  collegano il \Index{microprocessore} con i dispositivi di
  input/output (I/O).
   
   Esaminiamo ora la struttura interna del \Index{microprocessore} che
   costituisce la parte ``intelligente'' del nostro sistema. Questa
   \`e mostrata sommariamente in figura~\ref{processori_2}. Al cuore
   del sistema \`e la \Index{CPU} (Central Processing Unit).
    
\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/processori_2,width=8.0 cm,
height=4.0 cm}}\end{center}
\caption{Schema di massima di un \Index{microprocessore}.}
\protect\label{processori_2}
\end{figure}     
    
    Le memorie possono essere interne o esterne al
    \Index{microprocessore}. La maggior parte dei microprocessori oggi
    in uso hanno una certa quantit\`a di memorie, integrate insieme
    alla \Index{CPU} in un unico \Index{chip}.
     
 La \Index{CPU} contiene una propria \Index{logica di controllo} ed un
 certo numero di registri (costituiti tipicamente da gruppi di 8/16/32
 \Index{celle di memoria} veloce in cui vengono caricate sia le
 istruzioni che debbono essere eseguite che i dati
 numerici). Programmi e dati risiedono nelle memorie. La CPU preleva
 le istruzioni dalle memorie e le esegue, prelevando dalle stesse
 memorie anche gli eventuali dati necessari.
 
 Una forma lievemente modificata della struttura mostrata nella
 precedente figura \`e quella di figura~\ref{processori_3}.
 
\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/processori_3,width=7.0 cm,
height=2.5 cm}}\end{center}
\caption{Schema del \Index{microprocessore}. Sono indicati i registri,
la \Index{logica di controllo} ed il bus degli \Index{indirizzi}.}
\protect\label{processori_3}
\end{figure}  
 
 
L'informazione binaria \`e trasferita, attraverso i BUS indicati,
dalla memoria nei registri e verso la \Index{logica di controllo}, ed
adoperata come segue:

\begin{enumerate} 
\item L'informazione trasferita alla \Index{logica di controllo}
costituisce l'\emph{\Index{istruzione}}. Essa viene tradotta dalla
logica di controllo in opportune sequenze di
\emph{\Index{micro-operazioni}}, richieste dall'istruzione. Ad
esempio, l'istruzione potrebbe richiedere di trasferire un dato (byte
o parola di pi\`u bytes) dalla memoria in uno dei registri.
\item I dati necessari ad eseguire l'\Index{istruzione} vengono
trasferiti dalla memoria nei registri, sotto il controllo della logica
\end{enumerate}

 
In realt\`a il trasferimento di istruzioni e di dati dalla memoria ai
registri ed alla \Index{logica di controllo}, utilizza il medesimo
BUS. In effetti uno schema che meglio corrisponde al caso che
concretamente si incontra \`e quello di figura~\ref{processori_4}.
  
\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/processori_4,width=10.0 cm,
height=6.0 cm}}\end{center}
\caption{Schema del \Index{microprocessore}. Sono indicati i registri,
la \Index{logica di controllo} ed il bus degli
\Index{indirizzi}. Notiamo che ora un unico BUS connette tutti i
componenti.}  \protect\label{processori_4}
\end{figure}    
  
  
Vediamo da tale schema che i dati provenienti dalle memorie viaggiano
lungo le linee del BUS il quale \`e collegato sia ai registri che
all'unit\`a contenente la \Index{logica di controllo}. Analogamente,
le istruzioni generate dalla logica di controllo sono ``viste'' sia
dalle memorie che dai registri. Ci\`o creerebbe delle ambiguit\`a se
non fosse stata introdotta una particolare struttura per il
BUS. Questo, nel caso pi\`u semplice, viene suddiviso in un insieme di
pi\`u BUS separati:
 
 
\begin{itemize}
\item[(a)]il \Index{DATA BUS}, lungo il quale viaggiano i dati. Questo
\`e un BUS bidirezionale, avente un numero di linee uguale al numero
di bit di cui \`e costituita la parola del processore. Ad esempio 8 o
16 o 32 linee.
\item[(b)]l'\Index{ADDRESS BUS} (BUS degli \Index{indirizzi}) che
definisce l'indirizzo (cella di memoria o periferica) a cui la parola
impostata sul DATA BUS \`e destinata
\item[(c)]il \Index{CONTROL BUS} (o STROBE) che pu\`o, in processori
diversi, assolvere funzioni diverse. Ad esempio in alcuni computer
questo BUS ha due linee: un livello alto su una delle due linee
segnala la richiesta che il dato proveniente sul \Index{DATA BUS}
venga \emph{scritto} all'indirizzo di periferica specificato
dall'\Index{ADDRESS BUS}; un segnale basso segnala invece una
richiesta di \emph{lettura} del dato dall'indirizzo di periferica
specificato. La seconda linea di STROBE \`e invece adoperata per
segnalare la richiesta di lettura o scrittura del dato dalla
\emph{memoria}, all'indirizzo specificato sulle \Index{ADDRESS LINES}.
\end{itemize}

Alcune osservazioni sono a questo punto necessarie.

\begin{enumerate} 
\item In primo luogo vediamo che il BUS, indicato in modo molto
sommario nella figura, collega in realt\`a un numero molto elevato di
indirizzi. Esso deve infatti consentire l'accesso ad ogni singola
cella di memoria, il che fa s\`i che ad esempio, in un processore
avente una memoria di 64~kbyte occorra un numero di linee nell'ADDRESS
BUS almeno pari a 16; in uno di 4 Gbyte almeno pari a 32.
  
\item Quando un componente immette dati (cio\`e livelli di tensione)
sulle \Index{DATA LINES}, occorre che tutti gli altri componenti
risultino ``sganciati'' dalle medesime linee. Ci\`o \`e ottenuto in
genere utilizzando, per il collegamento alle DATA LINES, delle porte
logiche ``tri-state'': si tratta di porte le cui uscite, oltre che
negli ovvi stati ``HIGH'' e ``LOW'', possono essere in un terzo stato
in cui l'impedenza verso massa \`e molto grande, stato noto appunto
con il nome di ``\Index{HIGH IMPEDANCE}''\footnote{Un esempio di
integrato tri-state \`e il latch trasparente 74125, gi\`a incontrato
nella sezione~\ref{dtypeflipflop}}. In un qualsiasi istante, l'uscita
di uno solo degli elementi collegati al \Index{DATA BUS} pu\`o essere
in uno dei due stati logici; tutte le altre saranno nel terzo stato.
Questa osservazione non vale per le \Index{ADDRESS LINES}, poich\'e su
queste solo l'unit\`a di controllo pu\`o scrivere
   
\item Nella pi\`u gran parte dei processori, le istruzioni eseguite
dai diversi componenti sono ``sincrone''. Un apposito CLOCK, di
frequenza fissata, determina l'intervallo di tempo in cui un ciclo di
operazioni ha inizio e fine. Ad esempio, in alcuni processori la
lettura di un byte dalla memoria richiede un ciclo di CLOCK,
l'esecuzione della somma di 2 byte pu\`o richiedere 6 cicli di CLOCK,
etc..
    
\item In una macchina in cui il \Index{DATA BUS} ha una larghezza pari
a 8 la lettura di una parola di 32 bit (4 bytes) richieder\`a quattro
letture consecutive dalla memoria.
 
\item Quelli che genericamente abbiamo chiamato ``dati'' (nel caso di
una macchina con un \Index{DATA BUS} di larghezza otto, un singolo
byte) possono indifferentemente essere numeri o istruzioni. Infatti
un'\Index{istruzione} altro non \`e che una sequenza di bit. Nel
nostro esempio della macchina avente parole di 8 bit, possiamo avere
quindi $2^8=256$ istruzioni elementari. Vedremo in seguito alcuni
esempi di tali istruzioni.

\item L'architettura sommariamente descritta, in cui un unico BUS
viene adoperato sia per i dati che per i programmi, \`e nota come
``architettura di Von Neumann''. Essa \`e adoperata in processori di
uso generale ed implica che la memoria utilizzata per i dati e quella
adoperata per i programmi debbano avere parole di uguale
lunghezza. Un'architettura alternativa, molto frequente nei
\index{microcontrollore}microcontrollori, \`e quella ``Harvard''. In
tale architettura sono presenti due BUS separati, uno per i dati ed
uno per i programmi. In tal caso, le rispettive memorie possono esser
costituite da parole di lunghezza diversa. Ad esempio, la memoria
utilizzata per i dati (RAM) pu\`o avere parole di 8 bit, mentre quella
adoperata per i programmi pu\`o aver parole di 12, 14, 16 o 32 bit. Il
vantaggio di tale architettura consiste nel fatto che la \Index{CPU}
pu\`o effettuare contemporaneamente un accesso alla memoria dati ed
uno alla memoria programmi, riducendo in tal modo il tempo di
esecuzione. Vedremo in seguito un esempio di microcontrollore basato
su tale architettura.

\end{enumerate}





Possiamo ora vedere in dettaglio le operazioni che la \Index{CPU}
esegue per effettuare operazioni di I/O. Nel caso in cui sia la CPU a
inviare dati verso una cella di memoria o una periferica, l'indirizzo
di questa viene impostato sulle \Index{ADDRESS LINES}, mentre i dati
vengono caricati sulle \Index{DATA LINES}. Successivamente la CPU
provvede a caricare un segnale di STROBE su una delle CONTROL LINES,
per segnalare che i dati sono pronti. Quando il ``destinatario''
(cella di memoria o periferica) vede il proprio indirizzo sulle
\Index{ADDRESS LINES} esso provvede a copiare l'informazione contenuta
sulle DATA LINES in un proprio buffer.  Se viceversa la CPU deve
leggere dei dati dalle \Index{celle di memoria} o da una periferica,
essa pone l'indirizzo di questa sulle ADDRESS LINES e carica un
segnale di STROBE sulle opportune CONTROL LINES. La periferica
``vede'' il proprio indirizzo sulle ADDRESS LINES, verifica la
presenza del segnale di STROBE relativo ad un'operazione di lettura
sulle CONTROL LINES e carica allora i dati sulle \Index{DATA
LINES}. Fatto ci\`o, la medesima periferica resetta la linea di
STROBE, a segnalare che i dati sono pronti.

Affinch\'e la periferica possa confrontare l'indirizzo presente sulle
\Index{ADDRESS LINES} con il proprio, questa dovr\`a far uso di un
opportuno comparatore ad N bit, dove N \`e la larghezza del BUS degli
\Index{indirizzi}. A tale scopo si fa uso di opportuni
\emph{decodificatori d'indirizzo}, alcuni esempi dei quali sono
discussi nella prossima sezione.

Il protocollo di comunicazione descritto, apparentemente semplice \`e
in realt\`a incompleto, come vedremo pi\`u avanti.

\subsection{Decodificatori d'indirizzo\index{decodificatore! d'indirizzo}}

Un decodificatore d'indirizzo \`e un dispositivo che riceve in
ingresso il BUS degli \Index{indirizzi}, confronta i singoli bit con
quelli, memorizzati in precedenza dall'utente, che definiscono
l'indirizzo del particolare dispositivo o cella di memoria\index{celle
di memoria}, e fornisce in uscita un opportuno livello logico che
attivi il dispositivo o cella di memoria.

Un integrato che \`e a volte utilizzato per realizzare tale operazione
\`e il \Index{74LS85}, mostrato in figura~\ref{74LS85l}. Questo \`e un
semplice comparatore a 4~bit, che fornisce un livello logico alto sul
piedino indicato con $A=B$, se si ha uguaglianza dei 4~bit A con i
4~bit B. Sugli ingressi si potranno ad esempio inviare i segnali del
BUS (supposto di larghezza 4) mentre gli ingressi B saranno collegati
ai livelli definiti dall'utente nello specificare l'indirizzo del
dispositivo.  Se il bus ha larghezza superiore a 4, si potr\`a far uso
di pi\`u integrati \Index{74LS85}, collegati in parallelo.


\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/74LS85,width=4.0 cm,
height=6.0 cm}}\end{center}
\caption{\index{decodificatore! d'indirizzo}Un comparatore a 4 bit,
  utilizzabile per realizzare un decodificatore d'indirizzo a 4
  linee.\index{74LS85}} \protect\label{74LS85l}
\end{figure} 

In modo analogo si pu\`o far s\`i, come mostrato in
figura~\ref{address_decoder_1}, che la \Index{CPU} selezioni in
scrittura una data porta di I/O, utilizzando un decodificatore
d'indirizzo ottenuto mettendo assieme pi\`u \Index{74LS85} (4
nell'esempio di figura) in associazione ad un latch ottale
\Index{74LS273} e ad alcune porte NAND. L'arrivo del segnale di STROBE
trasferir\`a il contenuto del BUS dati sull'uscita del latch, solo se
l'indirizzo presente sulle \Index{ADDRESS LINES} \`e quello giusto.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/address_decoder_1,width=10.0 cm,
height=8.0 cm}}\end{center}
\caption{Decodifica d'indirizzo e trasmissione dei dati ad un'unit\`a
di I/O.} \protect\label{address_decoder_1}
\end{figure}  

Un altro tipo di \index{decodificatore! d'indirizzo}decodificatore
d'indirizzo spesso adoperato \`e il \Index{74ALS679}, il cui layout
\`e mostrato in figura~\ref{74ALS679l}. Questo \`e essenzialmente una
porta NAND a 12 ingressi, dei quali un numero programmabile pu\`o
essere invertito. Il numero degli ingressi da invertire, contati a
partire da A1, \`e determinato dal codice binario presente sugli
ingressi P=P3,P2,P1,P0.  Ad esempio, se poniamo P=1010, avremo che i
primi 10 ingressi saranno invertiti. Ammettiamo ad esempio di avere un
BUS di \Index{indirizzi} a 12 linee, e di voler attribuire ad una
cella di memoria o porta di I/O l'indirizzo binario 111111110000
(esadecimale EE0) porremo: P3=0,P2=1,P1=0,P0=0. Con ci\`o, se sul BUS
indirizzi \`e presente la configurazione suddetta, l'uscita della
porta sar\`a \emph{bassa}. Ci\`o segnaler\`a che il dispositivo
associato \`e quello selezionato (se il livello basso \`e quello
adoperato per la selezione; altrimenti occorrer\`a far seguire alla
porta un NOT).

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/74ALS679,width=3.0 cm,
height=8.0 cm}}\end{center}
\caption{Chip NAND a 12 ingressi, per il quale un numero programmabile
di ingressi pu\`o essere invertito. Il numero di ingressi invertiti
(contati a partire da A1) \`e determinato dai bit di comando
P3,P2,P1,P0.\index{74ALS679}} \protect\label{74ALS679l}
\end{figure}  

\subsection{\Index{I/O programmato}: registri di stato\index{registro!
di stato}, \Index{interrupt}s e \Index{DMA}} \label{I/O programmato}

Le procedure di Input/Output esaminate finora prevedevano che l'intero
processo fosse controllato dalla \Index{CPU}. Questa \`e una
restrizione eccessiva; infatti in tal modalit\`a, il dispositivo di
I/O \`e fermo ad aspettare che la CPU si occupi di leggere i dati da
esso immessi sulle \Index{DATA LINES}. Consideriamo ad esempio una
semplice tastiera; se noi pigiamo uno dei tasti, dovremo aspettare che
la CPU abbia letto il corrispondente codice dalle DATA LINES, prima di
batterne un'altro. La periferica non ha per\`o alcun modo di sapere se la CPU
ha effettuato la lettura. Anche se tale problema pu\`o esser risolto
facendo ricorso alle CONTROL LINES, ci\`o rende intrinsecamente lento
il processo. Se infatti il dispositivo di I/O adoperato
(nastro magnetico, disco..) \`e intrinsecamente molto veloce, le sue
prestazioni risulteranno drasticamente peggiorate, a causa della
necessit\`a che esso aspetti di volta in volta il segnale di OK da
parte della CPU.

Si pu\`o ovviare a tale problema facendo uso dei cosiddetti ``registri
di stato''\index{registro! di stato}. Questi consentono al dispositivo
di I/O di ``segnalare'' alla \Index{CPU} che vi sono dei dati pronti
ad esser letti. Ad esempio, nel caso della tastiera appena menzionato,
quando noi battiamo un tasto, un qualche circuito collegato alla
tastiera dovr\`a settare un bit su di una certa linea, per segnalare
alla CPU che \`e presente sulle \Index{DATA LINES} un carattere pronto
ad esser letto. La CPU dovr\`a verificare di continuo lo stato della
linea contenente il bit di stato (in questo caso il ``registro'' ha un
solo bit) e tutte le volte che il bit \`e alto proceder\`a alla
lettura. La stessa \Index{CPU} provveder\`a poi a resettare il bit,
indicando in tal modo alla periferica che il dato \`e stato letto. A
volte (ad esempio nel caso della tastiera) il bit di stato pu\`o esser
trasmesso attraverso una delle DATA LINES; baster\`a sceglierne una
che non sia utilizzata per i dati veri e propri.

L'operazione di set e poi di reset del bit di stato, pu\`o ad esempio
esser effettuata tramite un FF, come mostrato schematicamente in
figura~\ref{keyboard_control}.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/keyboard_control,width=10.0 cm,
height=8.0 cm}}\end{center}
\caption{Protocollo di comunicazione tra una tastiera \Index{ASCII} e
la CPU.} \protect\label{keyboard_control}
\end{figure}  

Quando viene battuto un tasto, l'informazione della tastiera viene
caricata sulle linee d'ingresso del registro \Index{74ACT574}.  La
tastiera genera anche un impulso positivo che, arrivando all'ingresso
di clock del FF, f\`a passare questo nello stato di \emph{set}
(Q=1). Il medesimo impulso, arrivando sull'ingresso di clock del
\Index{74ACT574}, attiva il trasferimento del dato (carattere) sul BUS
DATI. Il buffer tri-state '125, con l'ingresso collegato al Q del FF e
l'uscita collegata alla linea 7 del BUS, pone tale linea a livello
alto. La \Index{CPU} vede tale livello ed inizia il processo di
lettura del carattere sul BUS DATI. Essa invia un poi un impulso
negativo all'ingresso OE del \Index{74ACT574}, nonch\'e al CLEAR del
FF, con che sia l'uscita Q del FF che la linea D7 del \Index{DATA BUS}
ritornano al livello 0, a segnalare che un nuovo dato pu\`o esser
immesso.


Nell'esempio fatto, il \index{registro! di stato}registro di stato \`e
di un solo bit. Nel caso pi\`u generale tale registro avr\`a un certo
numero di bit, ciascuno dei quali segnaler\`a una diversa condizione.
Ad esempio, oltre al bit che indica la presenza di un dato da leggere,
potr\`a esservene uno che indichi, nel caso della lettura di un nastro
magnetico, l'inizio o la fine del nastro; un'altro che segnali
un'errore di parit\`a, etc..Tutti questi bit saranno impacchettati in
una \Index{STATUS WORD} (un byte) che la CPU dovr\`a leggere per testare poi i
singoli bit.


Anche se l'utilizzo dei registri di stato \`e di enorme utilit\`a
nelle operazioni di I/O, risulta necessario nella maggioranza dei casi
far uso anche dei cosiddetti \emph{\Index{interrupt}s}.  Questi sono
dei segnali (spesso \emph{\Index{active low}}, o \emph{\Index{edge
triggered}}) generati da una periferica per richiamare l'attenzione
della \Index{CPU}. Infatti, con il semplice uso degli STATUS
REGISTERS, accade che la CPU deve spendere un'elevata frazione del
proprio tempo ad interrogare (operazione detta \emph{\Index{polling}})
i vari dispositivi e verificare le rispettive STATUS FLAGS. Se il
numero dei dispositivi \`e elevato, la CPU finirebbe col non fare
altro. Ci\`o \`e illustrato in figura~\ref{polling}. L'utilizzo degli
\emph{\Index{interrupt}s} risolve tale problema.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/polling,width=5.0 cm,
height=8.0 cm}}\end{center}
\caption{Protocollo di interrogazione\index{protocollo di
interrogazione} dei registri di stato\index{registro! di stato}
(\Index{polling}).} \protect\label{polling}
\end{figure} 

A ciascun dispositivo, o gruppo di dispositivi, pu\`o esser attribuito
un \emph{\Index{interrupt}} che esso attiva per richiedere
l'attenzione della \Index{CPU}.  L'interrupt generato fa s\`i che la
CPU interrompa la propria azione per verificare l'origine ed il motivo
dell'interruzione.  Ci\`o che la CPU fa in tal caso \`e completare
l'istruzione in corso, salvare nello STACK quella successiva e nei
registri eventuali dati; poi identificare il dispositivo che ha
generato l'\Index{interrupt} e leggere il relativo registro di stato,
per decidere ci\`o che deve esser fatto.

In pratica, quando la CPU vede un interrupt su di una certa linea (le
linee di interrupt sono spesso indicate con le sigle IRQ: IRQ1, IRQ2,
IRQ3...) essa, dopo aver completato l'istruzione in corso e
memorizzato le altre informazioni sopra descritte, salta ad un
indirizzo di memoria prestabilito (uno per ogni IRQ) dove \`e
memorizzata la procedura (\emph{\Index{interrupt} \Index{handler}})
che deve esser eseguita per quel particolare interrupt. Tale procedura
altro non \`e che una routine, scritta spesso in \Index{Assembler},
che effettua i compiti prestabiliti legati al particolare interrupt.
Gli \Index{indirizzi} degli interrupt handlers sono memorizzati in
quello che \`e noto come l'\emph{interrupt vector}.  Uno schema che
descrive sommariamente la gestione degli interrupts \`e mostrato in
figura~\ref{interrupt}.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/interrupt,width=6.0 cm,
height=7.0 cm}}\end{center}
\caption{Protocollo di gestione degli \Index{interrupt}s.}
\protect\label{interrupt}
\end{figure} 

Una complicazione in tale procedura deriva dal fatto che spesso, ad un
dato \Index{interrupt} sono collegati pi\`u dispositivi di I/O. Per
risolvere il problema, i collegamenti vengono realizzati nel modo
schematicamente indicato in figura~\ref{interrupt_1}.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/interrupt_1,width=12.0 cm,
height=10.0 cm}}\end{center}
\caption{Protocollo di gestione degli interrupts, nel caso in cui
pi\`u dispositivi siano connessi al medesimo IRQ.}
\protect\label{interrupt_1}
\end{figure} 

Come si vede, alla linea IRQ2 sono collegati, tramite un buffer
tri-state, sia il dispositivo A che il C. Se solo uno di questi ha
generato un \Index{interrupt} (portando la linea corrispondente al
livello \emph{basso}), l'uscita del buffer dell'altro dispositivo
sar\`a nello stato di alta impedenza; ne segue che il livello di
tensione presente sulla linea sar\`a basso.

Ammettiamo ora che la \Index{CPU} ``veda'' un'\Index{interrupt} su di
una certa linea di interrupt, ad esempio la IRQ2. Essa, come gi\`a
detto, completer\`a l'esecuzione dell'istruzione in corso, salver\`a i
dati nei registri e passer\`a il controllo allo ``\Index{handler}''
associato al determinato interrupt (IRQ2 nel nostro esempio). Ora la
routine ``handler'' sa quale \`e l'interrupt che lo ha attivato, ma
non sa quale dei due dispositivi associati a tale linea lo abbia
generato. Per scoprirlo, lo handler legge i \emph{registri di stato}
\index{registro! di stato}di tutti i dispositivi connessi al
determinato livello di interrupt (infatti, il dispositivo che genera
l'interrupt deve sempre specificare la richiesta settando uno o pi\`u
\emph{status bits}). Una volta che lo handler abbia individuato il
dispositivo che ha effettuato la richiesta ed anche, dallo status bit,
il \emph{tipo} di richiesta, esso esegue l'azione necessaria e, in
aggiunta, resetta lo \emph{status bit} (o gli \emph{status bits}) e
l'IRQ generato.  Notiamo per inciso che, se pi\`u di un dispositivo
aveva attivato il determinato IRQ, anche se viene disattivato il
buffer tri-state del primo dispositivo (cio\`e tale buffer viene messo
nello stato di alta impedenza) rimane attivo (cio\`e basso) quello del
secondo.

Lo \Index{handler} restituisce ora il controllo alla
\Index{CPU}. Questa, qualora veda il determinato IRQ ancora attivo,
chiama nuovamente lo handler che a sua volta v\`a a leggere i
\emph{registri di stato}\index{registro! di stato} dei dispositivi
connessi al determinato livello di \Index{interrupt}. Ora trover\`a
che il registro associato al primo dispositivo \`e resettato mentre
\`e ancora attivo quello relativo al secondo.  Lo handler esegue ora
l'azione richiesta da tale dispositivo, resetta lo (o gli)
\emph{status bit}, resetta il determinato IRQ e restituisce il
controllo alla CPU.

A volte \`e opportuno impedire che un dispositivo, normalmente
abilitato a generare interrupts, ne generi. Ad esempio, una stampante
potrebbe generare interrupts tutte le volte che il suo buffer \`e
vuoto, per richiedere altri dati da stampare. Se tuttavia la stampa
\`e terminata, non ha senso che la stampante continui a generare
interrupts, che potrebbero creare problemi, in particolare nel caso in
cui la stampante condivida con altri dispositivi il medesimo livello
di interrupt. Si procede allora ad una disabilitazione della
capacit\`a della stampante di generare interrupts (non si disabilita
tuttavia il particolare IRQ, che potrebbe esser adoperato da altri
dispositivi).

Il ``\Index{polling}'' cio\`e la ripetuta interrogazione dei registri
di stato, pu\`o esser paragonato al sollevare il telefono ogni minuto
per verificare se qualcuno ci stia chiamando. L'uso degli interrupts
pu\`o esser invece paragonato con l'aspettare che suoni il telefono,
prima di sollevare il ricevitore.



L'utilizzo dei \index{registro! di stato}registri di stato, o anche
degli interrupts, risulta troppo lento nei casi in cui si debba
trasferire rapidamente grandi quantit\`a di dati da un dispositivo
verso la \Index{CPU} o verso un'altro dispositivo. Ad esempio, nel
caso in cui si debba leggere o scrivere dati su di disco o nastro
magnetico, o acquisire dati da un sensore esterno, a velocit\`a di
diverse centinaia di migliaia di bytes/secondo, sarebbe impensabile
applicare il sistema descritto sopra, con l'uso di \Index{interrupt}s
per ciascun byte trasferito. Quello che si f\`a in questi casi \`e di
consentire che l'unit\`a periferica esterna prenda direttamente il
controllo dei BUS; tale unit\`a si comporta, a partire da un certo
istante, da BUS Master, comportandosi come una CPU. Essa, una volta
abilitata dalla CPU del microcontrollore, pone sulle \Index{ADDRESS LINES} l'indirizzo del
destinatario, sulle \Index{DATA LINES} i dati da trasferire e sulle
CONTROL LINES le istruzioni di lettura/scrittura.





\subsection{Operazione della \Index{logica di controllo} ed \Index{esecuzione
delle istruzioni}}
  
La logica di controllo altro non \`e che un piccolo circuito
sequenziale. La sua funzione \`e quella di generare i segnali di
controllo per le singole operazioni elementari, quali quelle di
trasferire i dati dalla memoria ad appositi registri, di modificare
singoli dati (e.g. effettuare uno \emph{shift} dei bit in un byte,
calcolare l'AND di un byte con un altro, etc.) di fornire i dati
all'unit\`a logico aritmetica (\Index{ALU}) che \`e quella sezione
della \Index{CPU} in grado appunto di effettuare operazioni
aritmetiche o logiche.

Gli inputs all'unit\`a di controllo sono i bit dell'istruzione che
deve essere eseguita; ciascuno dei bits di ogni istruzione particolare
far\`a s\`i che l'unit\`a di controllo attraversi in modo ciclico
un'unica sequenza di stati, allo scopo di generare le singole
\Index{micro-operazioni} di cui un'\Index{istruzione} elementare \`e
costituita. Una tipica sequenza \`e mostrata nella
figura~\ref{processori_5}.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/processori_5,width=10.0 cm,
height=7.0 cm}}\end{center}
\caption{Sequenza delle istruzioni in un \Index{microprocessore} e
\Index{micro-operazioni} generate da ciascuna \Index{istruzione}.}
\protect\label{processori_5}
\end{figure}   
     
     Durante la prima parte del ciclo, l'\Index{istruzione} \`e letta
     dalla memoria e fornita agli inputs della logica di
     controllo. Tale operazione \`e effettuata dalla logica di
     controllo in modo automatico per una qualsivoglia
     istruzione. Questo \`e noto come ``ciclo di prelevamento''
     (FETCH).
       
La seconda parte \`e il ciclo di esecuzione vero e proprio. Questo
dipende ovviamente dalla particolare istruzione. Una volta che la
\Index{logica di controllo} abbia generato i segnali di controllo
richiesti dall'istruzione, essa automaticamente esegue un altro ciclo
di FETCH, per leggere l'istruzione successiva dalla memoria, dopo di
che il ciclo continua.

\subsection{Struttura interna di una semplice macchina} \label{Struttura interna di una semplice macchina}

Una rappresentazione schematica, un p\`o pi\`u dettagliata di quelle
viste finora, di un semplice \Index{microprocessore} \`e quella
mostrata in figura~\ref{simple_processor}.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/simple_processor,width=10.0 cm,
height=9.0 cm}}\end{center}
\caption{Struttura interna di un tipico \Index{microprocessore}.}
\protect\label{simple_processor}
\end{figure}  

Tutti i registri sono collegati attraverso una BUS comune. Anche se in
genere non tutti i registri avranno la medesima dimensione (numero di
bit) il BUS che li collega dovr\`a avere una larghezza pari alla
dimensione del pi\`u largo di essi. Le funzioni svolte dai diversi
tipi di registri\index{registro} sono elencate qui di seguito:
 
\begin{enumerate}  
\item MEMORY \index{MEMORY ADDRESS REGISTER}ADDRESS REGISTER
(MAR). Non \`e altro che il registro responsabile di scrivere sulle
\Index{ADDRESS LINES} l'indirizzo di memoria da accedere in
lettura/scrittura.
\item MEMORY \index{MEMORY DATA REGISTER}DATA REGISTER (MDR). Questo
\`e il registro responsabile di porre sulle \Index{DATA LINES} i dati
da scrivere in memoria o leggere dalla memoria.
\item \Index{INSTRUCTION REGISTER} (IR). Questo \`e il registro in cui
viene memorizzata temporaneamente l'\Index{istruzione} che si
esegue. Questo registro \`e l'interfaccia diretta con la logica di
controllo; il ``codice di operazione'' (\Index{OPCODE}) viene caricato
nell'IR durante il ciclo di FETCH ed \`e poi adoperato dalla logica di
controllo per generare le successive \Index{micro-operazioni}
necessarie ad implementare l'istruzione.
\item Il \Index{PROGRAM COUNTER} (PC). Questo \`e il registro
contenente l'indirizzo in memoria della prossima istruzione da
eseguire. \`E anche noto come INSTRUCTION POINTER (IP).
\item L'ACCUMULATORE (A). \`E il registro in cui la pi\`u gran parte
dell'elaborazione del dato viene effettuata. Esso costituisce uno
degli input della \Index{ALU}.
\item Il \Index{CONTROL REGISTER} (CR). \`E quello che fornisce i
segnali di STROBE alle CONTROL LINES. Esso consente alla logica di
controllo di sincronizzare il flusso dei dati tra la \Index{CPU} e le
memorie.
\item Il \Index{DATA POINTER} (DP). \`E un registro che contiene
l'indirizzo dell'operando (dato) richiesto da una determinata
\Index{istruzione}
\item Lo STACK (non mostrato nella
figura~\ref{simple_processor}). Questo \`e un insieme di registri,
ciascuno di dimensione pari a quella del BUS degli indirizzi di
programma. \`E un dispositivo di tipo ``Last In-First Out'' (LIFO),
come mostrato in figura~\ref{processori_6}.

\begin{figure}[htb!]
  \begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/processori_6,width=7.0 cm,
height=5.0 cm}}\end{center}
\caption{Struttura ed operazioni dello STACK.}
\protect\label{processori_6}
\end{figure}   
  
Nello STACK possono essere memorizzati consecutivamente
\Index{indirizzi} di istruzioni.  Un comando di PUSH carica la nuova
\Index{istruzione} in cima allo STACK, spingendo le altre verso il
basso. Un commando di POP, estrae l'ultima istruzione dalla sommit\`a
dello STACK e sposta tutte le altre verso l'alto. Lo STACK \`e
comunemente adoperato nelle \emph{chiamate} a sottoprogrammi. Quando
una tale chiamata (CALL) ha luogo la \Index{CPU} pone nella prima
locazione libera dello STACK l'istruzione che segue il CALL (cio\`e
quella che sarebbe stata eseguita in assenza del CALL), salta poi alla
locazione dove \`e memorizzata la prima \Index{istruzione} del
sottoprogramma, esegue questa e le successive ed infine, quando
incontra l'istruzione che termina il sottoprogramma (normalmente un
RETURN), esegue un POP, cio\`e carica dalla sommit\`a dello STACK
l'indirizzo che era stato memorizzato al momento del CALL. Tale
procedura pu\`o esser ripetuta pi\`u volte in sequenza nel caso in cui
il sottoprogramma chiami a sua volta altri sottoprogrammi. Si vede da
ci\`o che un parametro importante \`e la \emph{profondit\`a} dello
STACK (cio\`e il numero di registri che lo costituiscono.

\item Lo \Index{STACK POINTER} (SP). \`E un registro dedicato
adoperato per indicare la posizione nello STACK della successiva
istruzione da eseguire.
\item PROCESSOR STATUS WORD (PSW). \`E una parola contenente le
\emph{flags} che indicano i codici di stato, generati dal processore.
\item I GENERAL REGISTERS (B,C,D,E). Questi sono registri d'uso
generale adoperati dalla \Index{CPU}. Hanno la medesima larghezza
dell'accumulatore.

\end{enumerate}

\subsection{Le istruzioni in un tipico \Index{microprocessore}}

Ciascuna \Index{istruzione} inviata alla \Index{CPU} comporter\`a in
qualche modo l'elaborazione o manipolazione di dati all'interno della
CPU: trasferimento di dati, somma, confronto, etc.. A tale scopo
ciascuna istruzione dovr\`a contenere i seguenti cinque elementi:

\begin{enumerate}
\item \textbf{L'operazione da eseguire} (somma, trasferimento di dati,
caricamento, immagazzinamento,etc.). Questa parte dell'istruzione
costituisce il \emph{codice operativo} (\Index{OPCODE}). Un tipico
\Index{microprocessore} disporr\`a di un set molto limitato di
operazioni primitive.
\item \textbf{La sorgente dei dati}, cio\`e l'indirizzo dove trovare i
dati. Se i dati sono in memoria occorrer\`a specificarne l'indirizzo;
se i dati sono altrove la loro locazione dovr\`a essere specificata in
altro modo.
\item \textbf{La sorgente del secondo dato}, per quelle istruzioni che
ne richiedano uno (la somma richiede due dati mentre il complemento ne
richiede solo uno).
\item \textbf{La destinazione del dato risultante} dopo che
l'operazione sar\`a stata eseguita.
\item \textbf{La locazione dell'\Index{istruzione} successiva} da
eseguire dopo che quella attuale sia stata completata.
\end{enumerate} 
 
Chiaramente tutte queste informazioni non possono essere contenute in
una singola locazione di memoria (tipicamente 8 bits) e di conseguenza
\`e necessario ridurre in qualche modo la lunghezza dell'istruzione.
La riduzione \`e ottenuta facendo opportune ipotesi su alcune di
queste:

\begin{itemize}
\item l'informazione 5 pu\`o essere omessa facendo l'ipotesi che
l'istruzione successiva da eseguire segua immediatamente l'istruzione
corrente in memoria (cio\`e che le istruzioni siano immagazzinate in
locazioni consecutive della memoria)
\item Le informazioni 2, 3, 4 possono essere eliminate facendo uso dei
registri interni alla \Index{CPU} per immagazzinare i dati (o
l'indirizzo dei dati) e rendendo l'uso di tali registri implicito
nella particolare istruzione. Ci\`o aumenta il numero di istruzioni
possibili, ma attraverso una scelta giudiziosa, \`e possibile
mantenere il numero di istruzioni al di sotto di 256, in modo tale che
esse possano essere rappresentate da un singolo byte.
\end{itemize} 
 
Ad esempio nel processore 8085, nell'istruzione:

\vspace{0.3 cm} \textbf{ADD C (istruzione=81H, o 10000001 in binario)}
\vspace{0.3 cm}

\`e implicito che:

\begin{enumerate}
\item L'operazione \`e una somma
\item La sorgente del primo byte di dati \`e l'accumulatore (implicito
nell'istruzione)
\item La sorgente del secondo byte di dati \`e il registro C
(implicito nell'istruzione)
\item La destinazione \`e l'accumulatore (implicito nell'istruzione)
\end{enumerate}
 
L'\Index{istruzione} completa richiede cos\`i solo 8 bits e pu\`o
quindi esser contenuta in una singola locazione di memoria.
  
Dopo aver ridotto in tal modo la dimensione delle istruzioni, \`e
tuttavia ancora necessario per alcune istruzioni fornire ulteriori
informazioni in aggiunta al codice operativo. Una tale istruzione
comporter\`a tipicamente un accesso alla memoria e sar\`a quindi
necessario fornire l'indirizzo della locazione di memoria da
leggere. In tal caso \`e necessario far uso di pi\`u di otto bits per
specificare l'istruzione; una tale istruzione vien detta
\textbf{istruzione multibyte}.
  
Il primo byte di un'\Index{\textbf{istruzione multibyte}}
\`e l'\Index{OPCODE}. I bytes addizionali, che forniscono
l'informazione aggiuntiva formano ci\`o che vien detto
l'\emph{operando}. L'intera sequenza dei bytes costituisce
l'istruzione.

\subsection{I \Index{microcicli}}

L'esecuzione di ciascuna \Index{istruzione} nella \Index{CPU} comporta
l'esecuzione di un certo numero di operazioni ridotte dette
\Index{micro-operazioni} o microcicli. Ciascun microciclo impiega un
ciclo di clock e rappresenta un'operazione di trasferimento dati o di
manipolazione di registri. La notazione adoperata \`e tipicamente la
seguente:
 
\vspace{0.5 cm}

\textbf{Operazione di trasferimento dati:}

\[
destinazione \leftarrow sorgente
\]
\[
\;\;\;MAR \;\;\leftarrow \;\;\;PC
\]
\[
\;\;\;IR \;\;\leftarrow \;\;MDR
\]

La prima di queste istruzioni copia il Program Counter nel Memory
Address Register. La seconda copia il Memory Data Register
nell'Instruction Register.

\vspace{0.5 cm}

\textbf{Operazione sui registri\index{registro}:}

\[
destinazione \leftarrow espressione
\]
\[
\;\;\;PC \;\;\leftarrow \;\;\;PC+1
\]
\[
\;\;\;SP \;\;\leftarrow \;\;SP-1
\]

La prima di queste istruzioni incrementa di uno il Program Counter; la
seconda decrementa di uno lo Stack Pointer.

Qualora sia necessario trasferire dati alla memoria esterna o leggere
dati da tale memoria, ci\`o non pu\`o esser fatto in un singolo
microciclo. La memoria esterna \`e considerata come una serie di
registri analoghi ai registri interni della \Index{CPU}; tuttavia
prima che uno di questi registri (parola) possa essere letto o
scritto, \`e necessario indicare quale sar\`a il registro
coinvolto. Ci\`o vien fatto mettendo l'indirizzo della parola nel
MEMORY \index{MEMORY ADDRESS REGISTER}ADDRESS REGISTER. Ci\`o fa si
che l'appropriata parola di memoria sia abilitata e collegata al
MEMORY \index{MEMORY DATA REGISTER}DATA REGISTER. I dati possono
quindi essere trasferiti tra il MDR e la parola indirizzata (la
direzione del trasferimento dipende dalla circostanza che si tratti di
un'azione di lettura o di scrittura). Tale trasferimento di dati deve
aver luogo almeno un ciclo di clock dopo che l'indirizzo della parola
\`e stato scritto sul MAR, in modo da dar tempo alla memoria di
stabilizzarsi. Questi micro cicli sono rappresentati come segue:

\[
MAR \leftarrow registro\; sorgente
\]
\[
MDR \leftarrow memoria(MAR)
\]
 
Ciascun microciclo che comporti un trasferimento di dati tra due dei
registri interni della CPU f\`a uso del BUS interno; di conseguenza
solo uno di questi \Index{microcicli} pu\`o aver luogo durante un
singolo ciclo di clock. Se tuttavia un microciclo comporta una
manipolazione di un singolo registro o usa la memoria esterna o i BUS
esterni allora esso pu\`o aver luogo simultaneamente ad un
trasferimento tra registri.

\subsection{\Index{Assembler} e \index{linguaggio}linguaggi di livello pi\`u elevato}

Come visto nella precedente sezione, le istruzioni che un processore
\`e in grado di eseguire sono estremamente elementari, il che fa s\`i
che per realizzare operazioni che ci appaiono banali, quale ad esempio
elevare un numero ad una certa potenza occorrer\`a fornire al
processore un numero relativamente grande di istruzioni elementari.
  
  Per chiarire ulteriormente tale punto, esaminiamo ancora un esempio,
relativo al vecchio \Index{microprocessore} 6502. Le istruzioni
elementari necessarie per sommare due numeri (consistenti ciascuno di
un singolo byte esadecimale) in linguaggio macchina sono elencate
nella tabella~\ref{tab_microprocessori_1}.
  


Il programma in linguaggio macchina sarebbe allora:\begin{tabbing}


$\&70=\&A5$\\

$\&71=\&80$\\

$\&72=\&18$\\

$\&73=\&65$\\

$\&74=\&81$\\

$\&75=\&85$\\

$\&76=\&82$\\

$\&77=\&60$\\

\end{tabbing}

\begin{table}[!h]
\begin{center}
\begin{tabular}{| l | l | l |}
\hline \it{\Index{istruzione}} & \it{tipo} & \it{significato} \\
\hline 
\hline 
A5 & codice & pone nell'accumulatore il contenuto della \\ 
& operativo & locazione che segue \\
\hline 
80 & operando & indirizzo della locazione di memoria in\\ 
& & cui \`e contenuto il primo addendo\\ 
\hline 
18 & codice operativo & azzera il riporto\\ 
\hline 
65 & codice operativo & somma al contenuto dell'accumulatore il dato\\ 
& & contenuto all'indirizzo indicato dalla \\
& & locazione di memoria che segue\\ 
\hline 
81 & operando & indirizzo della locazione di memoria dove \`e \\
& & memorizzato il secondo operando\\ 
\hline 
85 & codice operativo & memorizza il contenuto dell'accumulatore \\
& & all'indirizzo specificato dall'operando seguente\\ 
\hline 
82 & operando & locazione di memoria in cui deve essere\\
& & immagazzinata la risposta\\ 
\hline 
60 & codice operativo & fine di questa sezione del programma\\ 
\hline
\end{tabular}
\end{center}
\caption{Istruzioni elementari necessarie per sommare due numeri in
  linguaggio macchina.} 
\protect\label{tab_microprocessori_1}
\end{table}

Qui il simbolo $\&$ che precede la locazione di memoria e quello che
precede l'\Index{istruzione} stanno ad indicare che si tratta di
valori esadecimali. Le istruzioni sono, come si vede, memorizzate
nelle locazioni di memoria a partire dalla 70~(esadecimale). Prima di
eseguire il programma occorrer\`a ``caricare'' i due numeri (di un
byte ciascuno) da sommare, nelle locazioni 80 e 81 (esadecimali).  Ad
esempio, per sommare i due numeri 11 e 23 (decimali) occorrer\`a
porre:

\begin{tabbing}
$\&80=11$\\

$\&81=23$
\end{tabbing}

e poi ``eseguire'' le istruzioni contenute nelle locazioni di memoria
che iniziano alla 70.
 
 Programmare un \Index{microcomputer} o un \Index{microprocessore}
facendo uso delle istruzioni ``di macchina'', quali quelle ora
esaminate, pu\`o risultare estremamente penoso. Un lieve aiuto viene
offerto dalla possibilit\`a di lavorare in \Index{Assembler}. Questo
\`e un linguaggio sostanzialmente coincidente con quello della
macchina, ma dove i nomi dei codici operativi sono sostituiti con
altri che hanno un immediato significato mnemonico e dove le locazioni
di memoria contenenti gli operandi vengono indicate con delle
etichette o LABEL, definite all'inizio del programma.  Un opportuno
COMPILATORE di uso generale (compilatore \Index{Assembler} o
``assemblatore'') provveder\`a poi a convertire il programma scritto
in linguaggio Assembler in ``codice macchina''~\footnote{Una
limitazione del linguaggio Assembler \`e costituita dal fatto che
ciascun tipo di microprocessore deve far uso di un proprio
compilatore. Tale limitazione non \`e presente in linguaggi di livello
pi\`u elevato, quali il C, il \Index{Fortran}, il \Index{Basic}
etc.}. Ad esempio il programma esaminato, relativo alla somma di due
numeri, in Assembler diviene:

\begin{table}[htbp] 
\begin{center}
\begin{tabular}{l | l}
.ADDIZIONE & label che definisce l'inizio della routine \\ 
LDA PRIMO & carica nell'accumulatore il numero contenuto nella \\ 
& locazione di memoria etichettata PRIMO\\ 
CLC & azzera il bit ``carry''\\ 
ADC SECONDO & somma al contenuto dell'accumulatore il numero
contenuto\\ 
& nella locazione di memoria etichettata SECONDO
\\ STA SOMMA & memorizza il contenuto dell'accumulatore nella
locazione\\ 
& di memoria etichettata SOMMA\\ RTS & fine del programma
                \end{tabular}
        \end{center}

\end{table}                

Qui LDA sta per ``Load Accumulator''; CLC per ``Clear Carry''; ADC per
``Add Accumulator''; STA per ``Store Accumulator''.

Una volta \emph{assemblato} il programma occorre riempire le locazioni
di memoria etichettate PRIMO e SECONDO con i due addendi, ed eseguire
il programma.
  
  Anche l'uso dell'\Index{Assembler} risulta pesante per l'utente,
  dovendo questi far continuo ricorso ai registri, accumulatore,
  etc. In altre parole, anche la programmazione in Assembler \`e
  strettamente legata alla struttura del \Index{microprocessore}, che
  l'utente deve sempre avere presente nel programmare un generico
  problema. Esistono in commercio numerosi
  \emph{\index{linguaggio}linguaggi} di livello pi\`u elevato, che
  liberano l'utente da tali vincoli. Tra questi, i pi\`u diffusi sono
  il C, il \Index{Basic}, il \Index{Fortran}. Altri come il Pascal, il
  Cobol, etc. stanno rapidamente diventando obsoleti. Negli ultimi
  anni hanno avuto una larghissima diffusione le versioni
  \emph{grafiche} di alcuni di questi programmi: \`e il caso del C++,
  del VISUAL BASIC, etc.
  
Con la diffusione di Internet hanno acquistato grande importanza il
Java ed il PERL.  Non entreremo nei dettagli di alcuno di questi
linguaggi, ma ci limiteremo ad illustrare come il programma
precedente, relativo alla somma di due numeri, possa essere scritto in
\Index{Fortran} (vedasi la tabella~\ref{fortran_example}).
  
\begin{table}[htb!]
                \begin{tabular}{l  l}
& PROGRAM ADDIZIONE \\ & INTEGER PRIMO, SECONDO, SOMMA \\ & PRIMO=11
\\ & SECONDO=23 \\ & SOMMA=PRIMO+SECONDO \\ & PRINT 1001, SOMMA \\
1001 & FORMAT(1x,I4) \\ & STOP \\ & END
                \end{tabular}
\caption{Esempio di routine in \Index{Fortran} per effettuare la somma
di due interi.} \protect\label{fortran_example}
\end{table}         

La prima riga definisce semplicemente il nome del programma. La
seconda \emph{dichiara} le variabili PRIMO, SECONDO e SOMMA come
interi. La terza e quarta attribuiscono i valori ai due operandi
(operazione che nell'esempio in \Index{Assembler} era effettuata al di
fuori del programma). La quinta istruzione calcola la somma e la
successiva stampa il risultato in ``formato'' intero di quattro cifre,
come specificato dalla settima istruzione, che ha una LABEL numerica
1001.  Qui vediamo anche l'utilizzo di tali LABELS, che possono anche
esser adoperate per effettuare dei ``salti'' (\Index{JUMP}),
attraverso istruzioni del tipo ``GO TO 2000'' (salta all'istruzione
che ha la LABEL 2000).

Vediamo infine come il medesimo programma potrebbe esser scritto in
\index{linguaggio}linguaggio C~(vedasi la tabella~\ref{c_example}).

\begin{table}[htb!]
                \begin{tabular}{l  l}
& MAIN()$\{$ \\ & INT PRIMO=11; \\ & INT SECONDO=23;\\ & INT SOMMA; \\
& SOMMA=PRIMO+SECONDO; \\ & PRINTF($''\%d \;\backslash n'',SOMMA$); \\
& $\}$
                \end{tabular}
\caption{Esempio di routine in C per effettuare la somma di due
interi.} \protect\label{c_example}
\end{table}       

Qui la prima riga dichiara il programma come un MAIN (per distinguerlo
da una procedura \emph{chiamabile} da altro programma) ed apre
(parentesi $\{$) la sequenza delle istruzioni, chiusa da un'analoga
parentesi $\}$ all'ultima riga di codice. Le successive tre istruzioni
attribuiscono i valori agli operandi e \emph{dichiarano} questi ed il
risultato come interi (INT). L'istruzione che segue calcola la somma e
pone il risultato nella variabile SOMMA. Il risultato \`e poi stampato
(PRINTF) come intero. Notiamo come la fine di ciascuna istruzione sia
segnalata dalla punteggiatura ``;''.

Sia nel caso del programma scritto in FORTRAN che in quello in C,
occorrer\`a effettuare una \emph{\Index{compilazione}} prima di
poterlo eseguire. Il compilatore crea un \emph{modulo}, essenzialmente
in \index{linguaggio}linguaggio macchina, a partire dalle istruzioni
scritte in FORTRAN on in C.

Gli esempi fatti, estremamente semplici, non rendono appieno l'idea
del grado di semplificazione che si ottiene ricorrendo a tali
\index{linguaggio}linguaggi, rispetto all'utilizzo
dell'\Index{Assembler}. Un programma che esegua una gran quantit\`a di
calcoli numerici, e che in C comprenda qualche migliaio di istruzioni,
in Assembler ne richiederebbe diverse decine di migliaia.  Si deve
necessariamente far ricorso all'Assembler solo in circostanze molto
particolari; ad esempio quando si debba accedere in modo diretto a
porte di I/O, o si debba programmare dei videogiochi. La credenza che
utilizzando l'\Index{Assembler} si guadagni in velocit\`a di
esecuzione v\`a decisamente sfatata: i compilatori oggi disponibili,
sia per il linguaggio C che per il FORTRAN, sono estremamente
sofisticati ed \`e impresa difficilissima ``batterli'' programmando
direttamente in Assembler.
   
\section{\Index{BUS} e standard di comunicazione}

Nelle precedenti sezioni abbiamo fatto uso del concetto di BUS ed
abbiamo accennato alla trasmissione di dati e/o programmi, sia tra
componenti di un dato microcontrollore/microprocessore che con
eventuali periferiche (stampanti, monitor, modem, dischi esterni,
etc). Ci occuperemo ora di descrivere sia gli standard adoperati per
la trasmissione che la struttura dei diversi tipi di BUS. Data
l'enorme variet\`a di architetture disponibili oggi sul mercato e la
complessit\`a di queste, non potremo che fornire una sommaria
descrizione delle principali caratteristiche di quegli standard che
sono oggi maggiormente diffusi. Per i dettagli di particolari tipi di
BUS e protocolli di comunicazione associati \`e necessario consultare
le caratteristiche fornite dai produttori.  Nel seguito di questa
sezione discuteremo la struttura fisica ed i protocolli di
comunicazione definiti da alcuni BUS standard.

Come visto in precedenza, un BUS \`e un canale di comunicazione
condiviso da pi\`u dispositivi. Tali dispositivi dialogano tra loro
secondo uno standard definito dalle specifiche del BUS stesso.  Al
livello fisico un BUS non \`e altro che un insieme di conduttori con
il quale si interconnettono i vari sottosistemi.  Tali connessioni
elettriche vengono usate non soltanto al fine di scambiare dati tra di
essi, ma anche, in alcuni casi, per ricevere alimentazione.  Esistono
numerosi BUS standard che si distinguono per numero di linee presenti,
tipo di segnali elettrici utilizzati, lunghezza massima del BUS,
presenza di un clock, velocit\`a massima di trasferimento dati,
modalit\`a di trasmissione, topologia di connessione delle
periferiche, etc.  Un BUS possiede a livello logico tre linee di
comunicazione:
\begin{itemize}
\item linee di controllo: utilizzate per il controllo del flusso dati:
ad esempio per il trasporto dei segnali di inizio e fine delle
transazioni o per gli interrupt request;
\item linee di indirizzamento: che indicano a quale sottosistema la
transazione si riferisce e l'indirizzo della cella di memoria
interessata;
\item linee dati: utilizzate per trasferire i dati.
\end{itemize}
I vantaggi di una simile archittura di comunicazione sono molteplici.
Il sistema \`e estremamente versatile in quanto si possono facilmente
aggiungere e rimuovere periferiche; le schede di espansione possono
quindi essere usate su qualunque sistema usi il BUS per il quale sono
state costruite.  In una tipica applicazione le linee fisiche del BUS
sono condivise da molte periferiche e questo f\`a s\`{\i} che risulti
economico da realizzare.  Naturalmente condividere le linee del BUS
porta anche ad alcuni inconvenienti: la velocit\`a di trasferimento dati
\`e limitata dal ``traffico'' sul BUS quando troppe periferiche sono
connesse contemporaneamente; la complessit\`a del BUS stesso \`e
maggiore, in quanto deve consentire la coesistenza di periferiche con
tempi di risposta differenti, garantendo le comunicazioni tra essi.
Esistono anche tipi di BUS in cui ogni periferica possiede la propria
linea dedicata di comunicazione. Questi non presentano gli svantaggi
appena visti ma sono in generale pi\`u complessi e ``costosi'' da
implementare.

In sistemi dotati di pi\`u di una CPU, o comunque di pi\`u di un
dispositivo che pu\`o iniziare transazioni sul BUS, occorre un
meccanismo per stabilire quale dei dispositivi che chiedono l'accesso,
debba averlo per primo. Tale meccanismo \`e noto come
\textit{arbitraggio}.

Un dispositivo che sia in grado di prendere il controllo del BUS \`e
detto \textit{BUS Master}\index{BUS! Master}, mentre uno che sia solo
in grado di rispondere a transazioni iniziate da un Master \`e detto
\textit{BUS Slave}\index{BUS! Slave}.

Non tutti i BUS permettono la presenza di pi\`u sottosistemi Master
contemporaneamente. Se un BUS lo permette si dice che esso supporta il
BUS mastering.

\begin{figure}[htb!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/immagini_bus_1.eps,width=11.0 cm,height=8 cm}}\end{center}
\caption{Esempio di un BUS con pi\`u dispositivi BUS Master
presenti. Da ``Computer Architecture: theme and variations'' Alan
Clements. Ringraziamo il Prof. A. Clements per il permesso di
riprodurre questa figura.}  
\protect\label{immagini_bus_1}
\end{figure}
Nella figura~\ref{immagini_bus_1}, la CPU \`e un BUS master, mentre la
memoria di sistema \`e un BUS slave.  Una delle porte di I/O \`e stata
considerata \emph{bus master}, poich\'e si \`e ipotizzato che
anch'essa sia in grado di prender controllo del BUS (ad esempio, per
trasferimento di interi blocchi di dati: DMA). L'altra periferica \`e
un BUS slave, poich\'e essa \`e solo in grado di rispondere a
richieste di lettura/scrittura.

La connessione tra il disco esterno ed il suo \emph{controller} \`e
anch'essa un BUS. La CPU \`e mostrata in un riquadro separato, con una
propria memoria cui \`e collegata tramite un BUS locale.

Per il collegamento di periferiche (dischi veloci, videocamere,
tastiere, etc.) si fa uso dei cosiddetti ``BUS periferici'' o BUS di
I/O. Rientrano in questa categoria il BUS SCSI, FireWire, RS-232, USB,
Ethernet, etc. In passato il collegamento di una periferica ad un
computer risultava spesso penoso, dovendosi conoscere e settare in
modo opportuno vari parametri (velocit\`a di connessione, parit\`a,
bits di controllo etc.) sia nel computer che nella periferica. Oggi i
dispositivi noti come \emph{plug-and-play} risolvono il problema,
poich\'e sono in grado di ``negoziare'' e settare per conto proprio i
parametri necessari.

\subsubsection{Modelli di trasferimento dati}

Esistono differenti modi con cui un BUS pu\`o trasferire dati tra i
differenti sottosistemi.  Una comunicazione pu\`o essere
\textit{sincrona} o \textit{asincrona}.

Nel primo caso una delle linee di controllo \`e una linea di clock e
la comunicazione avviene secondo un protocollo di trasmissione che
prevede che tutte le altre linee del BUS siano lette o impostate in
coincidenza con il clock comune.  Il vantaggio principale di una
comunicazione sincrona \`e che \`e semplice da realizzare e richiede
poca logica di controllo.  
%La controparte \`e quella di essere
%vincolati ad un clock comune per tutte le periferiche e che per
%garantire la sincronia di tutti i sottosistemi il BUS non pu\`o essere
%troppo lungo o altrimenti si incorre in problemi di clock skew, ovvero
%di una degradazione del segnale di clock.  
Sull'altro versante il vincolo di un clock comune a tutte le
periferiche \`e un limite all'utilizzo di tale tipo di BUS ed inoltre
richiede, perch\'e sia conservato il sincronismo, dei BUS
relativamente corti. 
In una tipica comunicazione
sincrona la comunicazione viene dapprima impostata tramite le linee di
controllo e poi vengono trasmessi i dati ad ogni ciclo di clock.

Le comunicazioni asincrone invece non necessitano di un clock di
riferimento e si possono adattare ad un maggior numero di
periferiche. L'assenza di clock permette di avere linee di
comunicazione piuttosto lunghe.  Affinch\'e una comunicazione
asincrona sia possibile \`e per\`o necessario un qualche protocollo di
``handshaking''\footnote{Per ``handshaking'' (letteralemente ``stretta
  di mano'') si intende lo scambio, tra un processore ed un
  dispositivo esterno, o tra due processori, delle informazioni
  necessarie perch\'e la trasmissione di un pacchetto dati possa aver
  luogo. Un tipico segnale di ``handshacking'' pu\`o ad esempio essere
costituito dall'invio, da parte del processore, di due bit
predefiniti.} e solitamente la lunghezza del messaggio trasmesso non
pu\`o essere molto lungo o si incorre nel rischio della perdita di
sincronia.  Una tipica comunicazione asincrona inizia
con una richiesta dati ad un sottosistema, richiesta che avviene sulle
linee di controllo. Il sottosistema interessato risponde settando le
linee dati ed impostando un'apposita linea di controllo per confermare
che i dati sono presenti. Il sottosistema che aveva effettuato la
richiesta legge i dati e comunica, sempre tramite le linee di
controllo, che ha effettuato la lettura. A questo punto la
comunicazione ha termine ed i sottosistemi rilasciano il BUS.

In generale, si tende ad usare BUS sincroni in applicazioni nelle
quali si pu\`o far uso di periferiche diverse le cui velocit\`a sono
per\`o molto simili. I bus sincroni tendono ad avere una minore
latenza\footnote{La latenza di un BUS \`e il tempo richiesto per
predisporre un trasferimento dati.} e possono avere una maggiore
larghezza di banda (bandwidth)\footnote{La bandwidth \`e semplicemente
il numero di bit che possono esser trasmessi al secondo. Ad esempio,
un BUS che abbia una \emph{larghezza} pari a 24 e lavori a 60 MHz, ha
una bandwidth pari a $6\;10^7 \times 24\;=\;1.44\;Gb/s$.}.

I BUS di uso ``general purpose'' tendono invece ad essere asincroni,
poich\'e tale soluzione offre maggior flessibilit\`a.

I BUS differiscono anche nel numero di linee con le quali i dati
vengono trasmessi. Un BUS si dice \textit{seriale} se i dati vengono
trasferiti un bit alla volta su di un'unica linea; si dice invece
\textit{parallelo} se al contrario vengono trasferiti pi\`u bit ad
ogni ciclo.  Solitamente in un BUS parallelo il numero di bit
trasferito \`e un multiplo di 8, cio\`e vengono trasferiti uno o pi\`u
byte in parallelo.

\subsubsection{Architetture di BUS\index{BUS! architetture di}}

Tre differenti tipologie di BUS si sono sviluppate e si sono affermate
nel tempo durante l'evoluzione dei personal computer e delle
tecnologie elettroniche:
\begin{itemize}
\item i \textit{backplane BUSes};
\item gli \textit{I/O BUSes};
\item i BUS processore-memoria (detti anche front-side BUSes).
\end{itemize}

Questi ultimi sono BUS di connessione dedicati, ad alta velocit\`a,
con il solo compito di garantire un accesso diretto alla memoria
centrale da parte del processore. Dipendono dal particolare tipo di
microprocessore e di memoria presenti nel microcomputer e sono
studiati in modo da garantire la massima efficienza di trasferimento
dati tra di essi. Data l'alta velocit\`a di trasferimento sono adatti
al trasferimento di dati solo su corte distanze.

Un tipico backplane BUS consente di estendere le capacit\`a di un
microprocessore tramite apposite schede di espansione\footnote{Una
  scheda di questo tipo pu\`o ad esempio essere costituita da un ADC,
  un modem, un'interfaccia per fotocamera, una memoria aggiuntiva
  etc.}. Esso \`e composto da un \textit{backplane} dove il BUS
risiede e nel quale sono presenti una serie di connettori, chiamati
\textit{slot}, montati perpendicolarmente ad esso.  I backplane BUS
sono per questo motivo estremamente flessibili nel numero e nel tipo
di periferiche che possono supportare.  Proprio per garantire questa
variet\`a di periferiche supportate, e per permettere distanze di
comunicazione maggiori, la velocit\`a di trasferimento dati \`e
inferiore a quella tipica della tipologia di BUS vista in precedenza.
\begin{figure}[t!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/backplanes_pci2.eps,width=7 cm,height=5 cm}}\end{center}
\caption{Esempi di backplanes.}  \protect\label{backplanes1}
\end{figure}
\begin{figure}[htb!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/plug_card_in_bus.eps,width=7 cm,height=5 cm}}\end{center}
\caption{Scheda di espansione per un backplane VME.}
\protect\label{backplanes2}
\end{figure}
Uno dei vantaggi principali dei backplane BUS \`e che sono dei BUS
standard e garantiscono quindi la compatibilit\`a delle periferiche
con tutti i sistemi aderenti a tale standard.  Alcuni esempi di
backplanes e di schede da inserirvi sono mostrati in
figura~\ref{backplanes1}~e~\ref{backplanes2}.

L'ultimo tipo di BUS sono i BUS di I/O. Questi sono pensati per
connettere dispositivi ad un microcomputer attraverso opportuni cavi
di comunicazione. Caratteristica principale di questo tipo di BUS \`e
la grande lunghezza che il BUS pu\`o raggiungere. Per questo motivo
per\`o la velocit\`a di comunicazione \`e inferiore a quella dei
precedenti tipi di BUS.  Anche questi BUS, come quelli basati su
backplane, consentono l'interfacciamento ad una grande variet\`a di
periferiche e sono codificati in standard industriali.

Lo stato dell'arte dei moderni BUS di sistema usati nei PC e
nell'industria \`e il risultato finale del susseguirsi di molte
generazioni di tecnologie e del tentativo da parte dei costruttori di
fornire uno standard comune.  I primi microcomputer (si pensi ad
esempio all'IBM PC/XT basata sull'Intel 8088 con BUS ISA) possedevano
un unico BUS di sistema al quale erano connessi tutti i suoi
sottosistemi: microprocessore, memoria, dischi rigidi, schede di
espansione e periferiche di I/O.  Tale approccio garantiva la
semplicit\`a dell'architettura ed il suo basso costo si adattava bene
alle necessit\`a dell'epoca.  Con l'avanzare delle tecnologie fu
evidente per\`o che il collo di bottiglia principale era proprio la
lentezza di un tale BUS.  Quando le nuove CPU, quali l'intel 80486,
capaci di lavorare a frequenze di clock elevate, divennero popolari,
fu chiaro che bisognava trovare un modo per ovviare a tale
incoveniente.  Se da un lato, infatti, tali BUS erano sufficienti per
le comunicazioni tra le perifieriche pi\`u lente, essi non lo erano
certamente per quei dispositivi che necessitavano di trasferire grosse
quantit\`a di dati velocemente (si pensi ad esempio alle schede video
o al microprocessore stesso).  La soluzione fu l'introduzione delle
architetture \textit{local BUS}.  Queste prevedono una struttura a tre
livelli di BUS.  Il primo livello \`e costituito dal front-side BUS
con il quale si garantisce al microprocessore l'accesso dedicato alla
memoria.  Il secondo livello \`e costituito da un backplane BUS e
connette le periferiche ``veloci'', ovvero quei dispositivi che
necessitano di grande larghezza di banda.  Tutte le altre periferiche
sono connesse sul terzo livello di BUS, il BUS di I/O a bassa
velocit\`a.
\begin{figure}[htb!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/immagini_bus_2.eps,width=10cm,height=6cm}}\end{center}
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/immagini_bus_3.eps,width=10cm,height=6cm}}\end{center}
\caption{Differenti architetture dei BUS. Da ``Computer Architecture:
  theme and variations'' Alan Clements. Ringraziamo il
  Prof. A. Clements per il permesso di riprodurre questa figura.}
\protect\label{busarch2}
\end{figure}
Il collegamento tra i vari livelli di BUS \`e fornito da appositi chip
che fungono da \textit{bridge}, consentendo cos\`{\i} anche ai
dispositivi non presenti sul front-side BUS il dialogo con il
microprocessore e la memoria centrale.  Questo approccio elimina il
collo di bottiglia presente quando tutte le periferiche devono
risiedere sullo stesso BUS. Schemi dei due tipi di BUS descritti in
questo paragrafo sono mostrati in figura~\ref{busarch2}. Quella in
alto mostra un sistema in cui un unico BUS \`e condiviso da tutte le 
periferiche che possono essere BUS Master o Slave; la seconda
rappresenta invece un'architettura schematizzata a tre livelli di BUS.

\subsection{Backplane BUSes}

\subsubsection{ISA}\index{BUS! ISA}
Il BUS ISA (\textit{I}ndustry \textit{S}tandard \textit{A}rchitecture)
fu introdotto da IBM come parte del suo rivoluzionario PC/XT nel 1981.
Il primo ISA XT era sotto il completo controllo del microprocessore
(l'Intel 8088) e il numero di linee di indirizzo, di dati e la
velocit\`a del BUS furono limitate a quelle del processore.

Il BUS XT ha un design relativamente semplice e possiede 53 linee di
segnale ed 8 linee tra alimentazione e terra.  Esso \`e un BUS
\textit{sincrono}, che cio\`e opera secondo la temporizzazione fornita
da un clock di sistema uguale per tutte le periferiche connesse ad
esso; \`e un BUS a 8 bit, cio\`e in grado di trasferire 8 bit di dati
alla volta, con controllo di parit\`a; le linee di interrupt sono
edge-triggered, ovvero gli interrupt sono segnalati dal cambio di
tensione sulla linea: questo implica che le linee di interrupt non
possano essere condivise da pi\`u periferiche. Il BUS XT non supporta
il BUS mastering delle periferiche e quindi gli unici dispositivi che
potevano assumere il controllo del BUS nell'IBM PC/XT erano il
microprocessore ed il controller DMA.  Le caratteristiche principali
dell'ISA XT sono:
\begin{itemize}
\item 20 linee di indirizzamento;
\item 8 linee di dati;
\item 6 linee di interrupt request;
\item 3 linee DMA;
\item velocit\`a di clock: 4.77 MHz;
\item velocit\`a di trasferimento dati: 4.77 MB/s.
\end{itemize}
Il BUS XT fu caratterizzato dalla semplicit\`a del suo design e,
sebbene non introdusse alcuna caratteristica particolarmente
innovativa, era ben adatto alla particolare architettura per la quale
era nato.

Proprio la semplicit\`a del BUS XT ne limit\`o le potenzialit\`a e,
per far fronte alle nuove esigenze, una versione evoluta del BUS fu
introdotta nel 1984 da IBM con il BUS ISA AT (\textit{A}dvanced
\textit{T}echnology). Una caratteristica importante dell'ISA AT fu la
sua compatibilit\`a con il precedente BUS XT. I principali
miglioramenti dell'ISA AT rispetto al suo predecessore furono
l'aumento del numero linee dati (16) e di indirizzamento (24) e della
velocit\`a di clock (a 8~MHz).

\subsubsection{PCI}\index{BUS! PCI}
Nel 1992 Intel annunci\`o la propria tecnologia local BUS, denominata
PCI (\textit{P}e\-ri\-phe\-ral \textit{C}omponent
\textit{I}nterconnect).
%Secondo Intel la proposta dell'associazione VESA non era niente pi\`u
%che una soluzione rapida e ad hoc ai problemi dei vecchi BUS (essendo
%essenzialmente un'espansione del BUS locale dell'Intel 80486) pensata
%specificatamente per i problemi dell'interfaccia video. 
Quello che Intel voleva era un BUS generico adattabile a tutte le
esigenze. L'obiettivo era quello di ottenere un BUS veloce ed
economico da realizzare. Inoltre si voleva rendere tale BUS
indipendente dal tipo di microprocessore utilizzato.  La soluzione di
Intel fu quella di isolare completamente il BUS locale del
microprocessore dal resto a cui il BUS PCI si interfaccia tramite un
bridge (figura~\ref{pci}).  
\begin{figure}[htb!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/immagini_local_pci_bus.eps,width=10cm,height=6cm}}\end{center}
\caption{Architettura del BUS PCI. Da ``Computer Architecture:
  theme and variations'' Alan Clements. Ringraziamo il
  Prof. A. Clements per il permesso di riprodurre questa figura.}
\protect\label{pci}
\end{figure}
Nonostante ci\`o il PCI \`e un BUS locale in quanto, come nel
caso del VLB, ad esso si connettono direttamente le periferiche
``veloci'' mentre quelle ``lente'' possono essere disposte su un altro
BUS collegato al PCI tramite l'apposito bridge.  Rendere completamente
indipendente il BUS del microprocessore da quello di tutte le altre
periferiche si \`e dimostrata un'idea vincente in quanto, da un lato
non pone limiti alla possibilit\`a di sviluppo dei processori che
possono avere BUS locali veloci studiati per le proprie esigenze,
dall'altra, rendendo indipendenti anche le periferiche, garantisce la
compatibilit\`a di queste con le generazioni di tecnologie future. Non
a caso, infatti, PCI \`e tuttora lo standard dominante nel mercato dei
personal computer.  Era chiaro dunque che il modo migliore per
risolvere i problemi di larghezza di banda dati delle periferiche era
di dividerle secondo le loro necessit\`a e costruire una gerarchia di
BUS locali indipendenti tra loro e comunicanti tramite appositi
bridge. Questa soluzione garantisce una flessibilit\`a enorme ed
un'elevata adattabilita alle nuove tecnologie, mantenendo la
compatibilit\`a con gli standard preesistenti: \`e per questo che i
moderni sistemi (in primo luogo, ma non solo, i personal computer)
hanno adottato tale architettura.

Le caratteristiche tecniche del BUS PCI sono:
\begin{itemize}
\item BUS sincrono a 32 o 64 bit di dati e indirizzi;
\item possibilit\`a di operare con logica a 5 o 3.3 Volt;
\item velocit\`a di clock a 33 o 66 MHz;
\item velocit\`a di trasmissione dati fino a 132 MB/s (32 bit mode) o
264 MB/s (64 bit mode) a 33 MHz;
\item piena compatibilit\`a con il BUS mastering;
\item supporto completo per il DMA;
\item configurazione automatica delle periferiche (PNP).
\end{itemize}
La grande versatilit\`a del BUS PCI ne determin\`o il successo, che
dura ancor oggi. Nel corso degli anni il BUS PCI ha dato luogo a
numerosi standard industriali (ad esempio Compact PCI, Mini PCI,
PC104-Plus, PISA, P2CI, PMC, IPCI, CardBUS) e recentemente \`e nata un
sua un'estensione denominata PCI-X. Quest'ultima, compatibile con lo
standard originale, si differenzia per una maggiore velocit\`a di
clock che pu\`o arrivare fino a 533 MHz consentendo cos\`{\i} un
trasferimento dati fino a 4.3 GB/s.  PCI-X non sembra comunque
destinato al successo del predecessore, a causa dell'avvento di una
nuova tipologia di BUS (vedi PCIe nel seguito).

\subsubsection{AGP}\index{BUS! AGP}
A fianco del BUS PCI sono presenti in un normale personal computer
altri tipi di BUS per soddisfare diverse esigenze. Nel seguito vedremo
alcuni di questi BUS, ad esempio quelli dedicati alle periferiche
``esterne''. Tra i BUS specifici che pi\`u comunemente vengono
utilizzati oggi vi \`e il BUS AGP (\textit{A}ccelerated
\textit{G}raphics \textit{P}ort). Come il nome suggerisce tale BUS \`e
nato per venire incontro alle necessit\`a dei moderni acceleratori
grafici. Lo standard fu presentato da Intel nel 1997 nella sua
versione 1.0, ed \`e oggi arrivato alla versione 3.  AGP \`e
un'estensione di PCI pensato come BUS locale per schede video. Esso
definisce 20 nuove linee di segnale, un nuovo connettore, tensioni di
lavoro di 1.5 o 3.3~$V$. La versione 3.0 dello standard definisce
velocit\`a di clock multiple di 66 MHz nelle varianti 1x, 2x, 4x e 8x,
arrivando in tal modo ad una frequenza massima di 533 MHz. La
larghezza del BUS dati \`e di 32 bit; pertanto la velocit\`a di
trasferimento dati massima \`e di 2.1 GB/s. AGP, come PCI sul quale
\`e basato, \`e un BUS sincrono e possiede quindi un clock comune di
riferimento; ma possiede anche modalit\`a di trasferimanto dati
asincrona. AGP \`e un esempio di BUS locale dedicato ad una
particolare tipologia di periferica. Un altro esempio di tali BUS
sar\`a mostrato nel seguito con i BUS dedicati alle memoria di massa.

\subsubsection{PCI Express}\index{BUS! PCI Express}
Lo standard PCIe (\textit{PCI} \textit{E}xpress) definisce un tipo di
BUS di nuova generazione.  Mentre nei BUS visti finora, le periferiche
condividono il BUS fisico che trasporta comandi, dati e indirizzi, nel
BUS PCIe le linee hardware non vengono condivise ma le periferiche
sono connesse ad un livello logico superiore. Infatti una delle
caratteristiche peculiari di PCIe \`e la differente topologia con la
quale le periferiche vengono connesse sul BUS PCIe.  Non condividendo
lo stesso BUS fisico, le periferiche PCIe sono connesse
individualmente ad uno \textit{switch} dedicato che ``smista'' le
comunicazioni da e verso le periferiche ad esso connesso, consentendo
in tal modo le comunicazioni tra esse.  Un'altra differenza primaria
rispetto ai BUS finora visti \`e il fatto che PCIe \`e un BUS seriale
anzich\'e parallelo (come \`e ad esempio PCI). Questo significa che il
BUS dati ha una larghezza pari ad 1 bit. PCIe trasferisce sia dati che
comandi in modo asincrono usando un BUS con 4 sole linee, denominate
PCIe \textit{link}, formato da una coppia di linee per i segnali in
ingresso ed una per quelli in uscita. Al livello fisico i segnali
utilizzati da PCIe sono differenziali di tipo LVDS (Low Voltage
Differential Signaling) trasmessi alla velocit\`a di 2.5 Gb/s in
entrambe le direzioni indipendentemente.  PCIe \`e pensato per essere
altamente scalabile: \`e possibile ``unire'' pi\`u link per aumentare
la banda dati; lo standard prevede in tal modo velocit\`a di
trasferimento che vanno da 2.5~Gb/s per un link 1x fino a 80~Gb/s per
un link 32x ottenuto combinando 32 link 1x.

\subsubsection{CAMAC}\index{BUS! CAMAC}
Il CAMAC (\textit{C}omputer \textit{A}utomated \textit{M}easurement
\textit{A}nd \textit{C}ontrol) \`e un sistema modulare nato nel 1969
dalla necessit\`a di uno standard per le periferiche di presa e
gestione dati negli esperimenti di fisica nucleare.  Un sistema CAMAC
\`e composto da strumenti modulari inseriti in un ``crate'' (tipicamente
con 25 alloggiamenti detti stazioni).  I crate ospitano il
\textit{dataway} al quale i moduli si interfacciano tramite un
connettore a 86 pin. Il dataway fornisce le tensioni di alimentazione
ai moduli, nonch\'e il BUS di indirizzamento, il BUS dati e quello di
controllo.  Le stazioni numero 24 e 25 ospitano un modulo speciale
detto \textit{crate controller} che ha il compito di gestire le
comunicazioni tra i moduli e il computer host al quale sono connessi.
Durante un'operazione, il controller genera sul dataway un comando che
consiste in un segnale sulla linea della stazione alla quale \`e
destinata la richiesta, il numero a 4 bit della sottostazione sulle
linee di sottoindirizzamento, 5 bit indicanti la funzione richiesta
sulle linee di funzione ed infine imposta la linea di \textit{Busy} al
livello logico 1 ad indicare che \`e in corso un'operazione.  Il
modulo richiesto genera una risposta di comando accettato e agisce
eseguendo la funzione richiesta. Se il comando richiede trasferimento
dati vengono usate le linee di lettura o scrittura.


\subsubsection{VME}\index{BUS! VME}
Il BUS VME (\textit{V}ersa \textit{M}odule \textit{E}uropa) \`e stato
introdotto nel 1981 per far fronte alla necessit\`a di avere un BUS
flessibile e potente e non legato alla particolare architettura di un
microprocessore e permetterne in tal modo la coesistenza su di un
unico BUS.  Sono previste larghezze di BUS dati e indirizzi
selezionabili dinamicamente per far fronte all'eterogeneit\`a delle
architetture esistenti: sono possibili indirizzamenti a 16, 24 o 32
bit e trasferimento dati di 8, 16 o 32 bit per ciclo. La velocit\`a
massima di trasferimento dati \`e di 40 MB/s.  Ogni device presente
sul BUS possiede un indirizzo o un insieme di indirizzi. \`E possibile
il DMA e VME supporta il BUS mastering.  Al contrario della maggior
parte dei BUS incontrati in precedenza il trasferimento dati avviene
in modo asincrono.

\subsection{I/O BUSes}\index{BUS! di I/O}
I BUS periferici permettono di connettere periferiche quali dischi
rigidi, cd-roms, stampanti, scanners, ecc. ad un microcomputer.  I BUS
di I/O appartengono al secondo dei livelli di BUS delineati in
precedenza e sono pilotati da un controller che generalmente risiede
sul BUS locale. Nel seguito vedremo alcuni degli standard pi\`u
diffusi.

\subsubsection{ATA}\index{BUS! ATA}
L'ATA (\textit{A}dvanced \textit{T}echnology \textit{A}ttachment) fu
definito come standard all'inizio degli anni 90 e da allora ha subito
una continua serie di evoluzioni per tenersi al passo con le
tecnologie delle memorie di massa (specialmente dischi rigidi) sempre
pi\`u veloci e sofisticate.  Ancora oggi ATA \`e lo standard pi\`u
diffuso tra gli hard disk (questa popolarit\`a \`e in gran parte
dovuta al fatto che le periferiche ATA sono pi\`u economiche di quelle
che fanno uso di tecnologie concorrenti).  La variet\`a di nomi
connessa a questo standard \`e incredibile e fuorviante nel momento in
cui vengono usati anche termini impropri (quali IDE) per riferirsi ad
esso.  Gli standard, noti con i nomi di ATA-1 fino ad ATA-7,
definiscono modalit\`a di trasferimento dati programmato, i cosidetti
PIO modes, e modalit\`a di accesso diretto alla memoria, DMA modes,
introdotti nel momento in cui la velocit\`a di trasferimento \`e
divenuta una necessit\`a.  I PIO modes e i DMA modes differiscono per
la velocit\`a di trasferimento e le modalit\`a con le quali i dati
vengono traferiti.  Il primo standard noto come ATA-1 prevedeva una
velocit\`a di trasferimento dati massima di 8.3 MB/s e definiva i PIO
modes 0 e 1 mentre non era previsto alcuna modalit\`a di trasferimento
DMA; lo standard ATA-7 (anche detto Ultra-ATA/133) arriva a trasferire
133 MB/s e prevede le modalit\`a PIO modes 0,1,2,3,4 e DMA modes 0,1,2
e Ultra-DMA modes 0,1,2,3,4 e 5. Come si vede \`e presente una grande
variet\`a all'interno di questo standard in continua evoluzione.
Tutti gli standard ATA garantiscono la compatibilit\`a con le
precedenti modalit\`a di trasferimento, per cui, ad esempio, un
controller ATA-7 pu\`o gestire periferiche ATA-5.  Una delle poche, se
non l'unica, caratteristica rimasta invariata nel tempo \`e il numero
di linee del BUS che \`e 40 con una larghezza del BUS dati di 8 bit
per le versioni pi\`u vecchie e di 16 bit per le pi\`u recenti.  Uno
dei limiti dei BUS ATA \`e il limitato numero di periferiche che
possono essere connesse contemporaneamente. Esso era di sole due
periferche negli standard pi\`u vecchi, ed \`e attualmente di quattro.

\subsubsection{SCSI}\index{BUS! SCSI}
Lo standard SCSI (\textit{S}mall \textit{C}omputer \textit{S}ystems
\textit{I}nterface) definito nel 1986 \`e probabilmente lo standard
pi\`u vecchio ancor oggi in uso nei moderni sistemi.  SCSI fu pensato
per essere facilmente espandibile, veloce e dotato di una interfaccia
di alto livello. Naturalmente questi vantaggi rispetto alle
interfaccie ATA, portarono ad una notevole complessit\`a delle
periferiche SCSI e ad un conseguente maggior costo delle stesse.  Come
nel caso di ATA, anche SCSI si \`e evoluto nel corso degli anni e sono
stai definiti vari standard noti con i nomi da SCSI-1 a SCSI-4. Il
numero delle periferiche connesse era di 7 per SCSI-1 e arriva fino a
16 per le specifiche SCSI-3 e SCSI-4. La larghezza del BUS dati \`e 8
o 16 bit. Il BUS supporta sia modalit\`a di trasferimento sincrono che
asincrono. La massima velocit\`a di trasferimento dati \`e di 5 MB/s
per SCSI-1 ed arriva fino a 320 MB/s secondo le specifiche SCSI-4.

\subsubsection{RS-232 -- standard per comunicazioni seriali sui
  PC}\index{BUS! RS-232}
RS-232 fu originariamente approvato dalla Electronic Industries
Association (EIA) nel 1960 e si modific\`o in seguito nel corso degli
anni fino alla terza versione RS-232C del 1969 usata ancor oggi dalla
maggior parte dei personal computer.  Lo standard non specifica un
tipo di connettore, e si sono diffusi due modelli: il DB25 a 25 pin ed
il pi\`u comune DB9 a 9 pin (vedi figura~\ref{connettoriseriali}).
\begin{figure}[htb!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/serialconnector.eps,width=8 cm}}\end{center}
\caption{Connettori DB9 (sinistra) e DB25 (destra), maschi (sopra)
e femmine (sotto).}  \protect\label{connettoriseriali}
\end{figure}
%L'RS-232 \`e uno standard di comunicazione seriale unidirezionale in cui i segnali sono riferiti a terra. Lo standard specifica le propriet\`a elettriche sia del driver della linea sia quelle del receiver: tensioni nel range +5 fino a +15 volts indicano un livello logico basso; tensioni da -5 a -15 volts un livello logico alto; la linea ha una impedenza di carico che va da 3 a 7~k$\Omega$ ed una lunghezza massima poco inferiore ai 20~m; lo slew rate deve essere minore di 30~V/$\mu$s. 
%La trasmissione dei dati avviene in modo asincrono e divisa per gruppi di bit. I frame (gruppi di bit) sono formati da un bit di start che segnala l'inizio della comunicazione, 7 o 8 bit di dati, opzionalmente 1 bit di parit\`a e da 1 o 2 bit di stop per segnalare la fine del messaggio.
%Il trasmettitore ed il ricevitore sono impostati per operare nella stessa modalit\`a ed alla stessa velocit\`a; la brevit\`a del frame garantisce che i due rimangano sincronizzati durante il frame stesso.
%Velocit\`a comuni di trasmissione sono 300, 1200, 2400, 4800, 9600, 19200 e 38400 bps (bit per second).
La trasmissione \`e asincrona. In
questo tipo di trasmissione, un bit di START ed un bit di STOP vengono
aggiunti all'inizio ed alla fine di ciascun gruppo di 8 bit.  A volte
i bit di STOP sono due. La velocit\`a di trasmissione \`e misurata in
BAUD (cio\`e in cambiamenti di stato/secondo). Valori comunemente adoperati
sono: 300, 1200, 2400, 4800, 9600, 19200 e 38400 BAUD.  Nello standard
di trasmissione RS-232C lo zero logico \`e una tensione superiore a
+3V (pi\`u precisamente nell'intervallo $+5V\div+15V$); l'uno logico
una tensione inferiore a -3V (pi\`u precisamente nell'intervallo
$-5V\div-15V$). La linea viene normalmente tenuta al valore logico
uno. La trasmissione di una parola ha inizio quando la linea viene
portata allo zero logico (START bit). Segue la stringa di bit che
costituiscono il carattere (con il bit meno significativo inviato per
primo) ed infine lo STOP bit.

All'estremit\`a di ricezione, una porta UART (Universal
Synchronous/A\-syn\-chro\-nous Receiver/Transmitter) viene attivata
dallo START bit. Essa trasferisce gli otto bit che seguono su di un
BUS parallelo e viene poi resettata dallo STOP bit.

Lo standard RS-232C prevede che, nella comunicazione tra due
dispositivi A e B generici, una linea (oltre alla relativa linea di
massa) venga adoperata da A per inviare dati a B ed una venga
adoperata da B per inviare dati ad A. Se A \`e un computer o terminale
(T) e B una periferica (C) saranno quindi necessarie almeno tre linee:
una che connette la porta UART di \emph{scrittura} di T alla porta di
\emph{lettura} di C, una seconda che connette la porta UART di
\emph{lettura} di T con quella di \emph{scrittura} di C, ed una linea
di massa. In realt\`a, lo standard prevede anche delle ulteriori
linee, dette di \emph{handshaking}, che possono essere utilizzate da
ciascuno dei due dispositivi per comunicare all'altro che i dati sono
pronti ad esser letti o che nuovi dati sono richiesti. In particolare
si hanno altre quattro linee, due delle quali corrispondono a
richieste che il dispositivo T (chiamato Data Terminal Equipment o
DTE) invia al dispositivo C (noto come Data Communication Equipment o
DCE) mentre le altre due corrispondono a richieste che il DCE invia al
DTE.

Le prime due di queste quattro linee sono note come RTS (Request To
Send) e DTR (o Data Terminal Ready). Le altre due sono note come CTS
(Clear to Send) e DSR (Data Set Ready).

Alcuni dispositivi oggi in uso evitano l'uso di queste linee di
\emph{handshaking} ma ricorrono a quello che \`e noto come
\emph{software handshaking}. Per una discussione approfondita di
questi punti si rinvia alla letteratura specializzata.

\subsubsection{IEEE-1284 -- porta per comunicazioni parallele sui PC}
\index{BUS! IEEE-1284}
IEEE-1284 \`e uno standard che definisce comunicazioni parallele
bidirezionali. Tali porte di comunicazione sono diffuse sui personal
computer soprattutto per l'interfacciamento a stampanti. Lo standard
IEEE-1284 definito nel 1994, ha rimpiazzato lo standard Centronix
ormai obsoleto pur mantenedo la compatibilit\`a con esso.  Il nuovo
standard prevede l'utilizzo di un connettore DB25 con 17 linee di
segnale e 8 di terra.  Le linee di segnale sono divise in:
\begin{itemize}
\item 4 linee di controllo;
\item 5 linee di stato;
\item 8 linee di dati.
\end{itemize}
Le linee di controllo sono usate come interfaccia di controllo e
trasportano i segnali di handshaking tra i due device connessi. Le
linee di stato sono usate in parte nel protocollo di handshaking e
come indicatori di stato per cose quali fine carta, indicatore di
linea occupata ed errori di interfaccia o della periferica.

Lo standard IEEE-1284 prevede 5 modalit\`a di trasferimento dati:
\begin{itemize}
\item \textit{Compatibility Mode}: anche detto Centronix o standard
mode, \`e il modo di trasmissione dati del vecchio standanrd. Prevede
che il trasferimento dati sia unidirezionale dal pc alla periferica e
che vengano trasferiti 8 bit di dati alla volta sulle linee dati. La
velocit\`a massima di trasmissione \`e di circa 150~kB/s;
\item \textit{Nibble Mode}: questo modo permette di trasferire dati
dalla periferica al pc ed \`e quindi spesso usato assieme al
Compatibility Mode. Prevede il trasferimento di 4 bit di dati alla
volta usando le linee di stato. La velocit\`a di trasferimento dati
\`e di circa 50~kB/s;
\item \textit{Byte Mode}: prevede il trasferimento dei dati 8 bit alla
volta sulle linee dati dalla periferica al pc;
\item \textit{EPP Mode}: (Enhanced Parallel Port) fu sviluppato come
standard di trasferimento dati ad alta velocit\`a. Esso era in grado
di trasferire 8 bit di dati (utilizzando le linee dati) in modo
sincrono con il BUS ISA in entrambe le direzioni (da e verso la
periferica). La velocit\`a di trasferimento dati \`e di circa
1.5~MB/s;
\item \textit{ECP Mode}: (Extended Capability Port) \`e un modo
avanzato di trasferimento dato che aumenta le prestazioni del modo EPP
portando la velocit\`a di trasferimento dati a circa 2.5~MB/s.
\end{itemize}


\subsubsection{USB}\index{BUS! USB}
%L'USB (\textit{U}niversal \textit{S}erial \textit{B}us) fu
%originariamente sviluppato nel 1995 con la versione 1.0 e si \`e poi
%evoluto con l'introduzione dello standard ad alta velocit\`a USB 2.0
%nel 2000.  USB \`e nato dall'esigenza di poter aggiungere periferiche
%al sistema in modo semplice per l'utente.  Le periferiche USB si
%dividono in due categorie: gli \textit{hub} e le cosidette
%\textit{funzioni} (ovvero le periferiche vere e proprie).  Le
%periferiche funzioni sono connesse ad un hub si i quali possono
%connettere in cascata (fino a 5 livelli) per permettere l'uso di un
%maggior numero di funzioni. Il limite di periferiche supportate
%contemporaneamente \`e di 128 dato dal numero di bit (7) di
%indirizzamento delle periferiche.  USB \`e un BUS seriale
%bidirezionale e prevede l'uso di cavi a 4 linee (1 ground, 1
%alimentazione +5 volt, 1 coppia differenziale per i dati) con
%impedenza di 90~$\Omega$ della lunghezza massima di 4 metri.  \`E
%compito degli hub fornire alimentazione alle periferiche funzioni ad
%esso connesse.  I dati vengono trasmessi usando la codifica
%\textit{NRZI} nella quale uno 0 logico \`e rappresentato da un cambio
%di tensione sulla linea ed un 1 logico dall'assenza di cambio.
%Esistono tre modalit\`a di trasmissione dati: un modo
%\textit{slow-speed} per periferiche ``lente'' con velocit\`a massima
%di trasferimento di 1.5~Mb/s; un modo \textit{full-speed} che arriva
%fino a 12~Mb/s; ed un modo \textit{high-speed} che permette velocit\`a
%di trasferimento dati fino a 480~Mb/s (quest'ultima definita dallo
%standard USB 2.0).  Nelle prime due modalit\`a di trasferimento le
%tensioni che definiscono i livelli alto e basso sono di 2.8~V e di
%0.3~V rispettivamente; per la terza di 400~mV e 0~V con tolleranze del
%10\%.  Come nel caso di RS-232 la comunicazione avviene tramite
%pacchetti di bit. Ogni trasmissione dati avviene attraverso lo scambio
%di 3 pacchetti: uno che contiene l'indirizzo della periferica; uno che
%contiene i dati; ed un'ultimo pacchetto che termina la comunicazione.

Lo standard USB (\textit{U}niversal \textit{S}erial \textit{B}us)
costituisce un'interfaccia per il collegamento ai PC di periferiche
quali stampanti, scanners, dischi, etc. (come nel caso di RS-232) ma
anche di dispositivi di misura, controllo e simili, che stanno
acquistando una grandissima diffusione.

\begin{figure}[b!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/usb_cable.eps,width=\textwidth}}\end{center}
\caption{Bus USB. A sinistra \`e mostrata una sezione del cavo; a
  destra, alcuni connettori.} \protect\label{usb_cable}
\end{figure} 
USB \`e inoltre un BUS seriale estendibile: ad una porta USB \`e
possibile collegare uno \emph{hub} (ovvero un'estensione di porta)
dotato di pi\`u porte analoghe, a ciascuna delle quali pu\`o essere
attaccato un ulteriore \emph{hub} e via dicendo. In totale \`e
possibile attaccare ad una porta USB fino ad un massimo di 127
dispositivi diversi. I cavi di collegamento contengono due conduttori
per i segnali, un conduttore di massa ed un conduttore
di alimentazione (+5 V). In tal modo \`e possibile alimentare
periferiche che siano sprovviste di una propria alimentazione
(purch\'e esse assorbano complessivamente meno di 100 mA). La
figura~\ref{usb_cable} mostra, nella parte sinistra, una sezione del
cavo. Nella parte destra sono mostrati alcuni tipici connettori.

I segnali sulle linee sono differenziali, con livelli di tensione di
0V e 3.3 V.

Esistono tre versioni, compatibili tra loro, dello standard USB. Le
caratteristiche di queste sono mostrate nella
tabella~\ref{specifiche_usb}.

\begin{table}[htb!]
        \begin{center}\small
                \begin{tabular}{| c | c  | c | c |}
\hline Specifica & Velocit\`a pratica & Applicazione & Caratteristica
 \\ & di trasmissione & tipica & \\ \hline ''Low speed'' & Bassa &
 Tastiera, & Costo \\ USB 1.1 (1.5 Mb/s) &(100-100 kb/s) & Mouse
 \ldots & minimo \\ \hline ''Full Speed'' & Media & Stampanti, &
 Larghezza di banda \\ USB 1.1 (12 Mb/s) &(0.5-10 Mb/s) & Scanner
 \ldots & garantita \\ \hline ''High Speed'' & Alta & Video, & Alta
 Larghezza di \\ USB 2.0 (500 Mb/s)&(25-500 Mb/s) & Dischi esterni.. &
 banda garantita \\ \hline
                \end{tabular}
\caption{Specifiche USB e velocit\`a di trasmissione.}
\protect\label{specifiche_usb}
        \end{center}
\end{table}


Come si vede, la pi\`u recente (USB 2.0) \`e anche la pi\`u veloce,
con una velocit\`a massima di 500 Mb/s.
 
 La comunicazione tra un computer (host) ed una periferica (device)
 \`e basata su di un complesso protocollo ed \`e organizzata in
 pacchetti (packets).
 
I tipi di pacchetti rilevanti per un USB a bassa velocit\`a sono
mostrati nella tabella~\ref{pacchetti_usb}.

\begin{table}[htb!]
        \begin{center}
                \begin{tabular}{| c | c  | c |}
\hline Nome & Gruppo & Funzione \\ \hline SETUP & TOKEN & Inizia un
 trasferimento di controllo \\ \hline IN & TOKEN & Inizia un
 trasferimento dati verso l'host \\ \hline OUT & TOKEN &Inizia un
 trasferimento dati al device \\ \hline DATA0 & DATA & Trasferisci da
 0 ad 8 bytes di dati \\ \hline DATA1 & DATA & Trasferisci da 0 ad 8
 bytes di dati \\ \hline ACK & HANDSHAKE & Informazione accettata \\
 \hline NAK & HANDSHAKE & Occupato; invia successivamente \\ \hline
 STALL & HANDSHAKE & Informazione non corretta \\ \hline
                \end{tabular}
\caption{Tipi di pacchetti rilevanti per un USB a bassa
velocit\`a.} \protect\label{pacchetti_usb}
        \end{center}
\end{table}


In aggiunta ai pacchetti mostrati, esistono delle condizioni
aggiuntive quasi statiche (reset, sospendi, ri-inizia).

Una transazione USB \`e un insieme di pacchetti scambiati tra
l'\emph{host} e la periferica (device). Una transazione ha sempre
inizio con l'\emph{host} che invia un TOKEN (SETUP, IN, OUT) al
device. I device non sono in genere in grado di iniziare
transazioni. Il pacchetto TOKEN contiene l'indirizzo del device
nonch\'e l'ENDPOINT all'interno di esso. l'ENDPOINT specifica il
conduttore (IN o OUT) collegato.

Ciascun pacchetto \`e composto da diversi campi. Questi sono:

\begin{itemize}
\item Sync

Ogni pacchetto deve iniziare con questo campo, che \`e una stringa di
8 bit nelle due modalit\`a di trasmissione a velocit\`a pi\`u bassa,
mentre \`e di 32 bit in quella a velocit\`a pi\`u elevata. Tale campo
viene adoperato per sincronizzare il clock del ricevitore con quello
del trasmettitore. Gli ultimi due bit indicano il punto di partenza
del campo successivo che \`e il PID.

\item PID

questo sta per Packet ID ed \`e quello che indica il tipo di pacchetto
che viene inviato. Ad esempio, PID=1101 sta per SETUP, PID=0010 sta
per ACK Handshake, PID=0011 per DATA0 etc.. Come si vede il PID ha
solo 4 bit; tuttavia, per controllare che il PID venga ricevuto
correttamente, i 4 bit vengono complementati ed aggiunti ai primi
quattro, con che il PID diviene una stringa di 8 bit. Ad esempio un
PID di SETUP diviene: 11010010

\item ADDR

questo \`e l'indirizzo del dispositivo cui il pacchetto \`e
destinato. Ad esso sono riservati 7 bit, il che implica un massimo di
127 dispositivi. L'indirizzo 0 \`e non assegnato. Un dispositivo a cui
non sia ancora stato assegnato un indirizzo dovr\`a rispondere ai
pacchetti inviati all'indirizzo 0.

\item ENDP

\`e il campo di endpoint (4 bit)

\item CRC

\`e un campo di controllo (Cyclic Redundancy Check)

\item EOP

End of Packet

\end{itemize} 

Riassumendo, vediamo che l'inizio della transazione avviene quando
l'host invia al device un TOKEN, ad esempio OUT\footnote{eventualmente
preceduto da un pacchetto SETUP}, costituito da un pacchetto
contenente i campi:

\vspace{0.5 cm} Sync PID ADDR ENDP CRC EOP
\vspace{0.5 cm}

Questo pacchetto specifica al device connesso all'indirizzo ADDR
(endpoint ENDP) che l'host \`e pronto ad inviare dati (IN ed OUT sono
sempre riferiti all'host).

Successivamente l'host invia un pacchetto di dati. Tale pacchetto
sar\`a composto dai seguenti campi:

\vspace{0.5 cm} Sync PID DATA CRC EOP
\vspace{0.5 cm}
 
Dove DATA pu\`o avere una lunghezza massima di:
 
\begin{itemize}
\item 8 bytes per dispositivi a bassa velocit\`a
\item 1023 bytes per dispositivi a piena velocit\`a
\item 1024 bytes per dispositivi ad alta velocit\`a
\end{itemize}
  
Una volta ricevuto il pacchetto dei dati il device risponder\`a con un
pacchetto di handshake, per segnalare che i dati sono stati
correttamente ricevuti. Tale pacchetto \`e costituito dai campi:

\vspace{0.5 cm} Sync PID EOP
\vspace{0.5 cm}
 
Se il device non \`e subito pronto, esso invier\`a un pacchetto NAK,
per chiedere all'host di inviare il pacchetto in un secondo momento.




\section{Il \Index{PIC\textsuperscript{\textregistered}}16F877}

\subsection{Introduzione}

Nelle sezioni precedenti abbiamo fornito una descrizione della
struttura e dell'utilizzo di un
\index{microcontrollore}microcontrollore. In questa sezione ci
proponiamo di fornire una descrizione, alquanto pi\`u dettagliata, di
un microcontrollore particolare, il
PIC\textsuperscript{\textregistered}16F877 della
\Index{Microchip\textsuperscript{\textregistered}}.  Il circuito
integrato
PIC\textsuperscript{\textregistered}16F877~\cite{ManualePIC}, fa parte
della famiglia PIC\textsuperscript{\textregistered}16F87X, composta da
quattro microcontrollori a \index{memoria! FLASH}memoria FLASH (la
lettera F nel nome indica proprio la presenza della memoria di tipo
FLASH).  Tali microcontrollori sono prodotti dalla ditta {\it
\Index{Microchip\textsuperscript{\textregistered}}}. La sigla
\Index{PIC\textsuperscript{\textregistered}}, utilizzata per la prima
volta dalla ditta {\it General Instruments}, \`e l'abbreviazione di
``Programmable Intelligent Computer''. Attualmente tuttavia si tende
ad interpretare questa sigla come ``Peripheral Interface Controller''.

I \index{microcontrollore}microcontrollori che appartengono a questa
famiglia offrono funzionalit\'a molto simili, differenziandosi tra
loro essenzialmente per la dimensione delle varie memorie e il numero
di pin di input/output a disposizione.  Essendo piuttosto facili da
programmare, essi sono stati utilizzati in una grande variet\'a di
\Index{applicazioni}.

\begin{figure}[htb!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/ChipPIC16F877.eps,width=0.5\textwidth}}\end{center}
\caption{Fotografia dell'integrato della
\Index{Microchip\textsuperscript{\textregistered}}
PIC\textsuperscript{\textregistered}16F877.}  \protect\label{Chip}
\end{figure}

\subsection{L'architettura del \Index{PIC\textsuperscript{\textregistered}}16F877}
Il \index{microcontrollore}microcontrollore \`e composto dal
\Index{microprocessore}, vero e proprio cuore del sistema, che si
occupa di eseguire le operazioni matematiche e di gestire l'esecuzione
dei programmi, e da vari dispositivi interni dedicati a compiti
specifici, detti \Index{periferiche interne} o moduli.  Una
caratteristica peculiare dei
PIC\textsuperscript{\textregistered}16F87X \`e l'adozione di
un'architettura di tipo ``Harvard'', che permette alla \Index{CPU} di
gestire istruzioni e dati attraverso memorie e bus separati. Questo
tipo di architettura permette alla CPU di effettuare
contemporaneamente un accesso alla memoria programmi ed uno alla
memoria dati.  La velocit\`a di esecuzione di un'istruzione risulta
quindi maggiore rispetto a quella ottenuta con un'architettura
tradizionale (detta di ``Von Neuman''), nella quale dati e programmi
vengono prelevati attraverso il medesimo bus.

Il microcontrollore \`e realizzato in un circuito integrato contenuto
in un involucro detto DIL40 che presenta 40 pin, 20 da ciascun lato
(vedi figura~\ref{Chip}). I pin sono virtualmente numerati da 1 a 40
come mostrato in figura~\ref{Integrato}.

\begin{figure}[htb!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/PIC16F877.eps,width=9.0 cm,height=9.5 cm}}\end{center}
\caption{Schema del circuito integrato
PIC\textsuperscript{\textregistered}16F877. Accanto ad ogni piedino
\`e riportata la numerazione e la sigla che indica le funzioni ad esso
associate.}  \protect\label{Integrato}
\end{figure}

Come per tutti i circuiti integrati ognuno dei pin \`e utilizzato per
una o pi\`u funzioni, indicate da una apposita sigla.  L'architettura
generale di un \index{microcontrollore}microcontrollore ed il suo
funzionamento sono stati discussi nella sezione~\ref{Microprocessori,
Microcontrollori e Microcomputer}. In questa sezione vengono descritte
le caratteristiche specifiche del microcontrollore
PIC\textsuperscript{\textregistered}16F877.

L'architettura del PIC\textsuperscript{\textregistered}16F877 \`e
schematizzata nel diagramma a blocchi mostrato in
figura~\ref{DiagrammaABlocchi}. In questa figura sono riportati tutti
i componenti che saranno descritti nella prossime sezioni.

\begin{figure}[htb!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/DiagrammaABlocchi.eps,width=1.0\textwidth}}\end{center}
\caption{Diagramma a blocchi dell'architettura del
\index{microcontrollore}microcontrollore
PIC\textsuperscript{\textregistered}16F877~\cite{ManualePIC}.}
\protect\label{DiagrammaABlocchi}
\end{figure}

\subsection{Pin per le funzioni di base}
Iniziamo la descrizione delle funzioni associate ai vari pin, a
partire da quelli che assicurano le funzioni basilari del
microcontrollore: alimentazione, clock ed inizializzazione. Questi pin
devono essere sempre connessi.
\begin{itemize}
\item{Alimentazione}: la tensione di riferimento per il livello logico
$0$ ($0~V$) \`e collegata ai pin 12 e 31, indicati con $V_{ss}$,
mentre i pin 11 e 32, indicati con $V_{dd}$ vengono collegati alla
tensione di riferimento per il livello logico $1$ ($5~V$).
\item{Clock}: come per tutti i microprocessori \`e necessario avere un
segnale di riferimento per mantenere la sincronia nell'esecuzione
delle operazioni.  Nel caso del 16F877 \`e possibile derivare il
segnale di clock da circuiti costituiti da cristalli o da circuiti
oscillanti a feedback basati su resistenze, condensatore ed elementi
attivi. Il clock pu\`o avere varie frequenze di oscillazione fino ad
un massimo di $20~MHz$.  Usualmente si realizza il circuito di clock
utilizzando un quarzo che permette di ottenere una elevata stabilit\`a
sia temporale che al variare della temperatura ed alla stesso tempo
offre una frequenza di oscillazione molto precisa.  Il segnale
generato dal quarzo viene connesso ai pin 13 e 14 (OSC1 ed OSC2)
utilizzando il circuito mostrato in figura~\ref{CircuitoClock}.

\begin{figure}[htb!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/Clock.eps,width=0.6\textwidth}}\end{center}
\caption{Schema del circuito di clock del
PIC\textsuperscript{\textregistered}16F877 realizzato con un
cristallo~\cite{ManualePIC}.}  \protect\label{CircuitoClock}
\end{figure}

Il tempo che intercorre tra due impulsi di clock successivi \`e detto
ciclo del clock.  Il
\Index{PIC\textsuperscript{\textregistered}}16F877 esegue
un'istruzione elementare, cio\`e un ciclo macchina, ogni quattro cicli
di clock e quindi, nell'ipotesi di utilizzare la massima frequenza di
clock, pu\`o eseguire un'istruzione elementare ogni $200~ns$. Questo
\Index{microprocessore} \`e quindi capace di eseguire 5 milioni di
operazioni elementari al secondo. Tale numero, apparentemente molto
grande, \`e in effetti piccolo rispetto alle prestazioni di un PC
attuale, che funziona ad almeno $2~GHz$ corrispondente a 2 miliardi di
cicli di clock al secondo.

\item{Inizializzazione}: il pin 1 denominato $MCLR$ \`e utilizzato per
inizializzare il \Index{microprocessore}. Se questo pin viene connesso
a massa il microprocessore arresta l'esecuzione del programma ed
esegue la routine di reset. Questa routine usualmente carica in tutti
i registri i valori iniziali ed inizia ad eseguire il programma in
memoria a partire dalla prima istruzione. Affinch\'e il
microprocessore funzioni correttamente questo pin deve quindi essere
collegato a $5~V$. Esso \`e spesso collegato ad un pulsante di RESET
che permette di mettere a massa temporaneamente il pin 1 provocando
una riinizializzazione del \index{microcontrollore}microcontrollore.
\end{itemize}

\subsection{Le porte del \Index{PIC\textsuperscript{\textregistered}}16F877}\label{SezionePorte}

Con l'eccezione dei pin che assicurano le funzioni di base discusse
nel paragrafo precedente, tutti gli altri pin del microprocessore
corrispondono ad ingressi o uscite digitali. Molti di essi hanno anche
altri ruoli ma questi saranno discussi pi\`u avanti. Tutti i pin di
ingresso ed uscita del PIC16F877 sono suddivisi in gruppi detti {\em
porte}.  In totale si hanno 5 porte indicate oguna con una lettera: A,
B, C, D ed E. La porta A comprende 6 pin, le porte B, C e D ne
comprendono 8 mentre la porta E ne comprende 3.  I pin appartenenti ad
ogni porta sono numerati da 0 ad $n$ e quindi ogni pin viene indicato
con una sigla che indica la porta ed il numero del pin in quella
porta. Ad esempio $RA3$ indica il pin 4 (la numerazione parte da 0)
della porta A.  \`E possibile individuare in figura~\ref{Integrato} i
pin appartenenti alle varie porte ed in figura~\ref{DiagrammaABlocchi}
la loro posizione nello schema a blocchi.  Le sigle indicate a fianco
del nome del pin delle varie porte indicano le eventuali altre
funzioni associate al pin. In totale sono disponibili 33 pin di
input/output.  Il grande numero di pin disponibili per ingressi ed
uscite sono uno dei punti di forza di questo particolare
\index{microcontrollore}microcontrollore.  In effetti essi non sono
sempre tutti disponibili poich\'e alcuni possono essere utilizzati per
funzioni particolari associate ai moduli interni del microprocessore
oppure possono essere dedicati a connessioni con periferiche esterne,
come ad esempio lo schermo o la tastiera

Tutti i pin delle porte sono configurabili come ingressi o uscite del
microprocessore.  La struttura generale delle 5 porte \`e grosso modo
la stessa. Ogni porta \`e configurata utilizzando il {registro di
direzione} dei dati. Questo fa parte dei registri di stato discussi
nella sezione~\ref{I/O programmato} di questo capitolo. Esso \`e
indicato come TRIS seguito dalla lettera che individua la porta. Ad
esempio TRISA \`e il \Index{registro} di direzione dei dati che
corrisponde alla porta A.  Ogni bit di questo registro corrisponde ad
un pin della porta, il bit 0 al pin 0 e cos\`i via.  Il valore di ogni
bit del registro determina se il pin ad esso corrispondente \`e
utilizzato come ingresso o come uscita.  Il valore 1 configura il pin
come ingresso ed il valore 0 lo configura come uscita.  Ad esempio se
si assegna il valore 00000100 al registro TRISB il terzo pin della
porta B (RB2) \`e configurato come ingresso e tutti gli altri come
uscite.  Un pin configurato come ingresso \`e collegato a massa
tramite un circuito di alta impedenza, mentre uno configurato come
uscita \`e collegato ad un circuito di latch.

Ad ogni porta \`e associato anche un registro dati indicato con PORT
seguito dalla lettera che indica la porta, ad esempio PORTA \`e il
registro dati della porta A. Per ogni pin configurato come uscita il
valore del bit del registro corrispondente determina il valore inviato
al pin. Viceversa per i pin configurati come ingressi i valori dei bit
corrispondenti sono uguali al valore alto o basso rivelato sul pin.

Cinque dei pin della porta A ed i tre pin della porta E sono
configurabili anche come \emph{ingressi analogici}. Il registro
denominato ADCCON1 permette di definire quali degli otto pin sono
utilizzati come ingressi analogici.  I registri TRISA e TRISE
controllano anche in modo analogico la configurazione di input o
output dei pin. Quindi, quando si utilizzano alcuni dei pin come
ingressi analogici, \`e necessario impostare correttamente il valore
di questi registri. Come vedremo in seguito, gli ingressi analogici
sono collegati ad un \Index{convertitore analogico-digitale} interno
al microcontrollore, che sar\`a discusso in seguito.


\subsection{Le memorie}
Il \Index{microprocessore} contiene tre tipi di memoria: la memoria di
programma di tipo \index{memoria! FLASH}~\footnote{Le memorie FLASH
sono una sottovariet\`a delle \Index{EEPROM}. A differenza di una
normale EEPROM, in una \emph{flash memory} non \`e possibile
cancellare e riscrivere singoli bytes, ma solo l'intera memoria o
gruppi di bytes}, la memoria di dati volatile di tipo RAM ed una
seconda memoria di dati non volatile di tipo EEPROM.  Queste memorie
utilizzano bus separati denominati Data Bus e Program Bus
rispettivamente mostrati in figura~\ref{DiagrammaABlocchi}.  Le
caratteristiche particolari di ogni memoria, descritte qui di seguito,
sono determinate dal particolare tipo di funzioni che essa svolge.
\begin{itemize}
\item{La memoria di programma} \\ Il ``Program Counter'', il cui ruolo
\`e descritto in sezione~\ref{Struttura interna di una semplice
macchina}, nel PIC\textsuperscript{\textregistered}16F877 ha una
profondit\`a pari a 13 bit. Esso \`e quindi in grado di indirizzare
$8000$ diversi \Index{indirizzi} (per la precisione 8191).  La memoria
di programma del PIC\textsuperscript{\textregistered}16F877,
costituita da una memoria di tipo \index{memoria! FLASH}, ha quindi
una dimensione pari a $8000$ parole di 14 bit.  14 bit \`e anche la
larghezza del bus di programma (in figura~\ref{DiagrammaABlocchi} si
pu\`o vedere la connessione tra la memoria FLASH, il program counter e
l'instruction register).  La memoria FLASH \`e una memoria non
volatile ed elettricamente cancellabile.  L'organizzazione della
memoria di programma \`e mostrata in figura~\ref{MemoriaFLASH}. Le
locazioni di memoria da 0005h (``h'' indica la notazione esadecimale)
in poi sono divise in quattro banchi di 2000 parole ciascuno. Questa
struttura viene sfruttata nella procedura di indirizzamento.

Le locazioni di memoria 0000h (``reset vector'') e 0004h
(``\Index{interrupt} vector'') contengono rispettivamente i puntatori
alle routine che vengono eseguite al reset del microprocessore ed alla
ricezione di un interrupt.

\begin{figure}[htb!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/MemoriaFLASH.eps,width=0.6\textwidth}}\end{center}
\caption{Schema della memoria \index{memoria!
FLASH}~\cite{ManualePIC}.}  \protect\label{MemoriaFLASH}
\end{figure}

Il programma che si vuole implementare viene normalmente scritto in
\Index{Assembler}, C o \Index{Basic} e viene quindi tradotto in
linguaggio macchina dai compilatori appropriati. Il programma
compilato deve poi essere caricato nella memoria di programma.
 
\begin{figure}[htb!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/MemoriaRAM.eps,width=0.8\textwidth}}\end{center}
\caption{Schema della memoria RAM. In figura si pu\'o notare la
suddivisione in quattro banche di dimensione 128 byte ciascuna (ogni
casella indica 1 byte). Le locazioni di memoria pi\'u basse di ogni
banca sono dedicate ai registri speciali indicati in figura dalle
varie sigle. Le locazioni di memoria pi\'u alte sono dedicate ai
registri generici (indicati in figura come General purpose
register). I numeri indicati in esadecimale accanto alle locazioni di
memoria indicano il relativo indirizzo~\cite{ManualePIC}.}
\protect\label{RegisterMap}
\end{figure}

\item{La memoria RAM} \\ Questa memoria, descritta in dettaglio in
sezione~\ref{RandomAccessMemory}, \`e utilizzata dalla
\Index{CPU}, dalle periferiche e dall'utente per le variabili di
programma. Questo tipo di memoria \`e caratterizzata da una scrittura
molto rapida ($\simeq~100~ns$) tuttavia le informazioni in essa
immagazzinate non vengono conservate quando il
\index{microcontrollore}microcontrollore non \`e alimentato, cio\`e la
memoria \`e volatile.  Essa \`e suddivisa in quattro sezioni dette
{\em banche} ognuna composta da $128$ byte (ad esempio gli
\Index{indirizzi} della prima banca vanno da 00h a 7Fh). Le locazioni
di memoria pi\`u basse di ogni banca sono riservate ai registri per le
funzioni speciali che servono a definire la configurazione del
microcontrollore o ad istruirlo ad eseguire determinate
operazioni. Viceversa le locazioni di memoria pi\`u alte sono a
completa disposizione dell'utente.  In figura~\ref{RegisterMap} \`e
mostrato lo schema di organizzazione della memoria RAM in quattro
banche e sono indicati i registri dedicati ad uso speciale, ai quali
\`e assegnato un nome mnemonico che aiuti a ricordarne la funzione, ed
i registri di uso generale.  Si possono ad esempio individuare i
registri speciali TRISA o ADCCON1 le cui funzioni sono state
precedentemente discusse.

Quando si programma in un linguaggio diverso dal linguaggio macchina
\`e il compilatore che si occupa della gestione della memoria RAM.

\item{La memoria \Index{EEPROM}} \\ Il \Index{microprocessore}
contiene un blocco di 256 byte di memoria di tipo EEPROM.  Questa \`e
elettricamente cancellabile, riscrivibile e non volatile quindi
verr\`a utilizzata per tutti i dati che non devono essere persi quando
il microcontrollore viene spento.  La richiesta di scrittura di un
byte in questa memoria procede attraverso l'operazione di
cancellazione e quindi riscrittura del byte.  Un ciclo di scrittura
viene eseguito in circa $4~ms$.
\end{itemize}

\subsection{Le \Index{periferiche interne}}
In questa sezione sono brevemente descritte le funzionalit\`a offerte
dalle periferiche interne del \Index{microprocessore} ed il modo per
utilizzarle.  La descrizione non \`e esaustiva ma si propone soltanto
di dare un'idea delle potenzialit\`a del microprocessore.  Le
periferiche sono:

\begin{itemize}
\item tre contatori indicati come, timer 0 1 e 2;
\item un \Index{convertitore analogico-digitale} (CAN) a 10 bit;
\item un modulo per la generazione di impulsi di periodo regolabile
(\Index{PWM});
\item un modulo per la comunicazione seriale sincrona;
\item un modulo USART\footnote{Universal Synchronous/Asynchronous
Receiver/Transmitter};
\item un modulo di comunicazione parallela;
\end{itemize}
Se si analizza lo schema dell'architettura del \Index{microprocessore}
PIC\textsuperscript{\textregistered}16F877 mostrato in
figura~\ref{DiagrammaABlocchi} si possono facilmente individuare le
varie periferiche nella parte inferiore del disegno connesse al bus
dei dati. Le caratteristiche principali di queste periferiche vengono
descritte qui di seguito.
\begin{itemize}
\item{I contatori} \\ I tre contatori (o timer), indicati in figura
come TIMER0, TIMER1, TIMER2, possono essere incrementati ogni volta
che viene generato un determinato numero di cicli dal segnale di clock
del microprocessore. Il numero di cicli necessari per incrementare di
una unit\`a i contatori pu\`o essere definito attraverso un opportuno
registro.  Considerando che un ciclo di clock pu\`o corrispondere fino
ad un minimo di $50~ns$, si capisce che i contatori possono essere
utilizzati per eseguire misure di tempo piuttosto precise.

I timer 0 e 2 sono contatori a 8 bit mentre il timer 1 \`e a 16 bit.
Questo significa che i primi due possono contare fino ad un massimo di
255 conteggi mentre l'ultimo fino ad un massimo di 65535 conteggi.  I
timer 0 ed 1 possono essere incrementati anche attraverso un segnale
esterno collegato al pin RA4. Tre registri denominati OPTION\_REG,
T1CON e T2CON permettono di configurare tutte le opzioni dei tre
contatori.

Ogni volta che uno dei contatori passa dal massimo numero registrabile
a 0 pu\`o essere generato un segnale di \Index{interrupt}. Questo
segnale permette quindi di contare quante volte il contatore ha
ricominciato a contare da 0. Utilizzando, ad esempio, una variabile
che viene incrementata ogni volta che l'interrupt \`e generato, si
pu\`o estendere l'intervallo di conteggi eseguibili e quindi gli
intervalli di tempo misurabili.


\item{Il \Index{convertitore analogico-digitale}} \\ Il convertitore
analogico-digitale (ADC) permette di convertire una tensione analogica
in un valore numerico binario. La tensione in ingresso all'ADC viene
letta da uno degli otto input analogici descritti nella
sezione~\ref{SezionePorte}. Tre bit del registro ADCON0 permettono di
selezionare quale di questi input \`e collegato all'ADC, in questo
modo \`e possibile misurare fino ad otto diverse grandezze fisiche con
un solo ADC. Lo schema del circuito di ingresso del convertitore
analogico digitale \`e mostrato in figura~\ref{ADC}.

\begin{figure}[htb!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/ADC.eps,width=0.6\textwidth}}\end{center}
\caption{\index{convertitore analogico-digitale}Schema del circuito di
ingresso dell'ADC~\cite{ManualePIC}.}  \protect\label{ADC}
\end{figure}
L'ingresso analogico selezionato \`e collegato al condensatore di un
circuito di sample-and-hold. Questo circuito permette di caricare il
condensatore al valore della tensione in ingresso e di mantenere il
valore di tensione pressoch\'e costante durante il tempo necessario ad
eseguire la conversione. L'uscita del circuito di sample-and-hold \`e
collegata all'ingresso del convertitore che fornisce in uscita il
valore digitale attraverso una serie di approssimazioni successive. La
tensione \`e cos\`i convertita in un numero a 10 bit.

Per fare in modo che il convertitore funzioni correttamente \`e
necessario che il condensatore di ingresso abbia il tempo necessario
per caricarsi al valore di tensione applicata e che in seguito il
convertitore abbia il tempo necessario ad effettuare la conversione.
Il tempo necessario affinch\'e queste due operazioni siano eseguite
\`e pari a qualche centinaia di microsecondi.

La risoluzione dell'ADC, pari a 10 bit, permette di raggiungere, su un
intervallo $0-5~V$, una precisione di $5~mV$. I valori di riferimento
per le tensioni minima e massima (gli estremi dell'intervallo di
conversione) sono programmabili.
\item{Il modulo CCP} \\ Il modulo CCP offre tre tipi di
funzionalit\`a: \Index{Capture}, Compare o \Index{PWM} (Pulse Width
Modulation).  Quando il modulo funziona in modo ``Capture'' il valore
del timer1 viene letto ogni volta che un determinato evento, definito
dall'utente, si realizza.  Il tipo di evento pu\`o essere il fronte di
discesa o di salita di un segnale o l'occorrenza di un predeterminato
numero di fronti di salita. Il tipo di evento \`e selezionato
attraverso il valore di un registro dedicato.  Il funzionamento nel
modo ``Compare'' permette di confrontare continuamente il valore dei
registri CCPR1H e CCPR1L con il valore del contatore 1 memorizzato nei
registri TMR1L e TMR1H (vedi figura~\ref{RegisterMap}).  Ogni volta
che i valori sono uguali il pin RC2/CCP1 viene portato ad un valore
definito dall'utente.  L'utente pu\`o scegliere di portare il pin ad
un valore alto, basso o di lasciarlo invariato. Anche in questo caso
la scelta dell'azione da eseguire viene definita dal valore di un
apposito registro.  L'ultima modalit\`a di funzionamento \`e quella
come generatore di impulsi (PWM) di periodo e duty-cycle programmabili
con una risoluzione fino a 10 bit.  Questo modulo \`e realizzato in
modo tale da permettere di generare treni di impulsi in modo molto
semplice senza sovraccaricare il \Index{microprocessore}.
\item{I moduli per la comunicazione} \\ Esistono tre moduli dedicati
alla comunicazione tra il microprocessore ed il mondo esterno.  Due di
questi moduli utilizzano la comunicazione seriale, trasmettono cio\`e
i dati su una sola linea, e sono il modulo MSSP (Master Synchronous
Serial Port) ed il modulo USART (addressable Universal Synchronous
Asynchronous Receiver Transmitter).  Queste periferiche permettono di
comunicare con altri \index{microcontrollore}microcontrollori o con
periferiche esterne quali shift registers, driver per schermi,
convertitori A/D o D/A.  Il modulo USART pu\`o essere configurato sia
per utilizzare un protocollo di comunicazione ``\Index{full duplex}
asincrono'' sia ``\Index{half duplex} sincrono''.  Esiste poi un terzo
modulo che permette di utilizzare la porta D come una porta parallela
che pu\`o essere letta e scritta in modo asincrono. La porta D
utilizzata in questo modo pu\`o essere direttamente interfacciata ad
un bus a 8 bit di un microprocessore esterno.
\end{itemize}

\subsection{Gli \Index{interrupt}}
Nella sezione~\ref{I/O programmato} \`e stata discussa la procedura
generale che porta alla generazione di un interrupt.  Il
\index{microcontrollore}microcontrollore
PIC\textsuperscript{\textregistered}16F877 \`e capace di generare
\Index{interrupt}s innescati da 14 possibili sorgenti. Ogni volta che
si verifica un interrupt il PIC\textsuperscript{\textregistered}
interrompe l'esecuzione del programma e salta all'istruzione contenuta
all'indirizzo 0x04\footnote{A partire da questo indirizzo \`e
memorizzata la Interrupt Service Routine (ISR)} nella memoria di
programma. Il tempo che trascorre tra il verificarsi dell'evento
collegato all'interrupt e l'istante in cui inizia l'esecuzione
dell'istruzione alla locazione 0x04 \`e detto ``latenza di
interrupt''. Nel PIC\textsuperscript{\textregistered}16F877 questa \`e
pari a 3-4 cicli di macchina, a seconda del tipo di interrupt e del
punto di esecuzione del programma al momento della ricezione
dell'interrupt.

Tra tutte le possibili sorgenti di interrupt quelle che sono
utilizzate pi\`u frequentemente sono generate da:
\begin{itemize}
\item timer 0 e timer 1 quando si ha la transizione dal massimo
conteggio raggiungibile, 255 per il timer 0, 65535 per il timer 1,
allo zero.  Questo \Index{interrupt} \`e, ad esempio, utilizzato per
realizzare orologi che misurino intervalli di tempo maggiori di quelli
ottenibili da un contatore semplice;
\item un fronte di salita o discesa di un segnale collegato al pin
RB0.  Questo interrupt pu\`o ad esempio permettere di rendere
sensibile il microprocessore ad un'azione su di un modulo esterno come
una tastiera o un pulsanteò
\item la fine della conversione eseguita dal \Index{convertitore
  analogico-digitale};
\item la presenza di un segnale sulla porta di comunicazione seriale o
su quella parallela.
\end{itemize}
Ogni sorgente di \Index{interrupt} pu\`o essere singolarmente
abilitata o disabilitata.

\subsection{Programmazione del dispositivo}

Come gi\`a accennato, il programma sviluppato dall'utente, dopo la
\Index{compilazione}, deve essere trasferito nella memoria programma
(FLASH) del PIC\textsuperscript{\textregistered}16F877.  Allo scopo
esistono vari metodi:

\begin{itemize}
\item{\textbf{Programmatore esterno: }} In commercio esistono vari
modelli di programmatori, sviluppati dalla stessa
\Index{Microchip\textsuperscript{\textregistered}} o da terze
parti. In generale si tratta di dispositivi piuttosto costosi.  Per
programmare il \Index{microprocessore} \`e necessario rimuovere questo
dalla scheda dove \`e installato, piazzarlo sul programmatore, facendo
uso di uno zoccolo, e avviare il programma che gestisce il
programmatore stesso. In generale questa tecnica \`e piuttosto
faticosa, in quanto rimuovere il componente \`e talvolta un'operazione
delicata e sicuramente non immediata.
\item{\textbf{Bootloader: }} In questo caso la programmazione avviene
``in situ'', utilizzando la periferica USART. Questa, nota anche come
porta seriale, \`e una interfaccia standard presente in moltissimi
elaboratori (compreso il PC), ne risulta che , in questo caso, per
programmare il \Index{microprocessore} non \`e necessario possedere
alcun dispositivo aggiuntivo. In effetti, andando nei dettagli, un
programmatore esterno \`e ancora necessario, ma solo per programmare
il \Index{PIC\textsuperscript{\textregistered}} la prima volta, ossia
per trasferire nella FLASH un piccolo programma che prende il nome di
bootloader.  In particolare:
\begin{itemize} 
\item{} Il bootloader viene trasferito dal programmatore nella parte
finale della memoria \index{memoria! FLASH}. Necessita soltanto di 256
words, quindi viene scritto nelle locazioni 0x1F00-0x1FFF. Viene anche
scritta la locazione 0x0, ossia il reset vector, in modo da puntare
alla locazione 0x1F00.
\item{} All'accensione, quindi, il controllo del
PIC\textsuperscript{\textregistered} passa subito al programma del
bootloader, che attende per 512 ms l'arrivo di un particolare
messaggio dalla porta seriale.
\item{} Se tale messagggio arriva, il bootloader capisce che l'utente
vuole trasferire un nuovo programma nella memoria FLASH. D'ora in poi
ogni word ricevuta viene scritta nella FLASH, a partire dalla
locazione 0x05. Questo equivale quindi a programmare il
PIC\textsuperscript{\textregistered}.
\item{}Se il messagggio atteso dal bootloader non arriva entro 512 ms
dall'accensione, il bootloader esegue un salto all'istruzione 0x5,
dando quindi inizio all'esecuzione del programma dall'utente.
\end{itemize}
\end{itemize} 

In definitiva, quindi, l'utilizzo del bootloader semplifica molto la
fase di programmazione, ma presenta anche due effetti collaterali: il
primo \`e che l'utente non pu\`o piu' utilizzare le ultime 256
locazioni ( circa il 3\% del totale) mentre il secondo \`e che
all'accensione il programma dell'utente viene tenuto in sospeso per
circa mezzo secondo, il che potrebbe anche non essere accettabile a
seconda dell'applicazione.

\section{I codici operativi del \Index{PIC\textsuperscript{\textregistered}}16F877}

\subsection{Opcodes}

Il circuito integrato
PIC\textsuperscript{\textregistered}16F877~\cite{ManualePIC}
appartiene alla famiglia dei \index{microcontrollore}microcontrollori
RISC (Reduced Instruction Set Computer). Questo significa che il
numero di codici operativi supportati \`e abbastanza limitato
(soltanto 35) ma che questi sono tutti altamente ottimizzati in
termini di velocit\`a di esecuzione. In particolare tutti i codici
operativi vengono eseguiti in un solo ciclo macchina (pari a 4 cicli
dell'oscillatore esterno) escluse le istruzioni di salto alle funzioni
e di ritorno dalle funzioni al programma principale, che prevedono una
modifica del valore del Program Counter, e che necessitano di due
cicli macchina. D'altra parte l'assenza di codici operativi molto
specializzati fa s\`i che generare codice per funzioni anche molto
semplici pu\`o richiedere molte istruzioni, il che allunga ovviamente
il tempo di esecuzione del programma. Ad ogni modo sicuramente la
programmazione in \Index{Assembler} dei microprocessori RISC \`e molto
semplificata rispetto a quelli tradizionali (CISC: Complex Instruction
Set Computer)

Nel \Index{PIC\textsuperscript{\textregistered}} 16F877 ogni
istruzione \`e definita da una parola di 14 bit (pari alle dimensioni
del \textit{Program Bus}). Alcuni bit sono l'opcode vero e proprio,
che specifica il tipo di istruzione, mentre gli altri sono operandi
che specificano ulteriormente il tipo di funzione o includono valori
di costanti necessarie all'esecuzione.

Il \textit{Data Bus}, invece, trasporta i dati, provenienti dalla
memoria RAM o dalle periferiche e che sono manipolati dai codici
operativi. Il data bus e' largo 8 bit, da cui la classificazione del
16F877 come ``processore ad 8 bit''.
 
Le istruzioni sono in genere catalogate in tre gruppi:
\begin{itemize}
\item{\textbf{Riferite al byte}}: sono istruzioni eseguite per lo
 pi\`u nella \Index{ALU}, e che eseguono operazioni logiche quali
 AND,OR,XOR,SHIFT,etc. Quasi tutte fanno uso del registro W, che e'
 l'equivalente nei processori PIC\textsuperscript{\textregistered} del
 registro accumulatore, descritto in precedenza.
\item{\textbf{Riferite al bit}}: sono istruzioni che permettono di
modificare singoli bit dei registri, oppure di saltare l'istruzione
che segue a seconda del valore di un determinato bit.
\item{\textbf{Letterali e di controllo}}: sono istruzioni che hanno al
loro interno definito anche il valore di una costante. Tale valore
puo' essere utilizzato, a seconda della istruzione, ad esempio come
indirizzo dove eseguire salti ad altre parti del programma oppure per
essere sommato al registro accumulatore.
\end{itemize}

E' importante notare che tutti i codici operativi possono agire sia
sui registri della RAM di uso generale, e quindi manipolare i dati
dell'utente, sia sulle locazioni riservate alla definizione delle
periferiche, definendone quindi il comportamento.
 
Quasi tutti i codici operativi modificano a seguito della loro
esecuzione alcuni bit di un registro particolare chiamato
\textit{STATUS REGISTER}, localizzato all'indirizzo 0x3 della RAM. \\
In particolare i bit interessati sono:
\begin{itemize}
\item{\textbf{Bit 0 (C) }}: bit di riporto o carry. Si porta al
 livello alto se l'operazione ha comportato un riporto. Ad esempio una
 istruzione di somma quale 0x8C + 0x84 = 0x110, poich\'e il risultato
 \`e maggiore di 0xff (che \`e l'intero ad 8 bit piu' grande) da come
 risultato 0x110 - 0xff = 0x11, ed inoltre porta a livello alto il bit
 di carry.
\item{\textbf{Bit 1 (DC) }}: molto simile al bit di carry solo che si
riferisce al riporto del quarto bit meno significativo (0xf + 0x1 =
0x10 ed inoltre porta alto il bit DC
\item{\textbf{Bit 2 (Z)}}: bit di zero, diviene alto se il risultato
di una operazione matematica e' 0
\end{itemize}



La figura ~\ref{OPCODESTABL}, tratta dal datasheet del
\Index{microprocessore}, riporta schematicamente l'elenco dei codici
operativi, sia in forma mnemonica sia come codice binario vero e
proprio.  Andando nei dettagli:
\begin{itemize}
\item{\textbf{W}}: e' il registro accumulatore
\item{\textbf{f}}: rappresenta l'indirizzo di una locazione di memoria
da utilizzare durante l'esezuzione del'istruzione
\item{\textbf{d}}: e' uno dei 14 bit dell'istruzione ed indica dove
deve essere scritto il risultato dell'operazione. Se d=0 il risultato
viene scritto nel registo W, altrimenti nella locazione all'indirizzo
f.
\item{\textbf{b}}: indica la posizione di un bit all'interno di un
registro
\item{\textbf{k}}: indica una costante larga 8 bit da utilizzare
nell'istruzione
\end{itemize}

\begin{figure}[htb!]
\begin{center}\mbox{\epsfig{file=sistemi_logici_complessi/opcode.eps,width=0.8\textwidth}}\end{center}
\caption{Tabella codici operativi 16F877~\cite{ManualePIC}.}
\protect\label{OPCODESTABL}
\end{figure}      

\subsection{Esempi di codici operativi}

Illustriamo adesso i dettagli relativi a qualcuno dei codici
operativi. Le informazioni relative agli altri possono essere
facilmente dedotte dalla figura ~\ref{OPCODESTABL} oppure consultando
il datasheet.

\begin{itemize}
\item{\textbf{Riferite al \Index{byte}}}
\begin{itemize}
\item{\textbf{ADDWF}}: esegue l'addizione tra il contenuto del
registro W e il contenuto della locazione f. Il risultato viene
scritto nuovamente nel registro W se d=0 altrimenti nel registro f. Le
istruzioni sono molto ottimizzate: in un solo ciclo macchina e'
possibile leggere un registro, eseguire un'operazione e scrivere di
nuovo lo stesso registro.  Se il risultato della somma e' superiore a
0xff il bit di carry si porta alto.
\item{\textbf{DECF}}: decrementa di 1 il contenuto del registro f. Se
il risultato e' 0 si alza il bit Z dello STATUS REGISTER.
\item{\textbf{NOP}}: nessuna operazione viene eseguita
\end{itemize}
\item{\textbf{Riferite al bit}}
\begin{itemize}
\item{\textbf{BCF}}: pone a 0 il bit b del registro all'indirizzo f
\item{\textbf{BTFSC}}: verifica il valore del bit b del registro f. Se
questo e' 0 viene saltata l'esecuzione dell'istruzione che segue.
\end{itemize}

\item{\textbf{Letterali e di controllo}}
\begin{itemize}
\item{\textbf{ADDLW}}: somma il contenuto della costante k al registro
W e scrive il risultato in W. Sia il bit di carry che il bit Z possono
essere modificati dall'operazione.
\item{\textbf{MOVLW}}: copia la costante k nel registro accumulatore W
\item{\textbf{CALL}}: salta all'indirizzo contenuto nella costante k,
che e' supposto essere l'indirizzo di partenza di una funzione. Prima
pero' salva il contenuto del program counter nello stack, in modo tale
che al termine della funzione il programma possa riprendere
l'esecuzione a partire dal punto in cui era stata interrotta. Per
l'esecuzione richiede 2 cicli di macchina.
\item{\textbf{GOTO}}: simile a CALL, esegue un salto incondizionato ma
senza copiare il program counter nello stack. Per l'esecuzione
richiede 2 cicli di macchina.
\item{\textbf{RETURN}}: eseguita al termine di una funzione. Legge
dallo stack l'ultima locazione salvata in modo da poter continuare
l'esecuzione a partire dal punto dove era rimasta.  Per l'esecuzione
richiede 2 cicli di macchina.
\end{itemize}
\end{itemize}

\subsection{Cenni sul \index{linguaggio}linguaggio \Index{Assembler}}

Come gi\`a descritto nelle precedenti sezioni, l'\Index{Assembler} \`e
un linguaggio che assegna ad ogni codice operativo un nome
``mnemonico'' tale da ricordare il linguaggio umano e quindi
semplificare la programazione rispetto a scrivere il programma del
microprocessore in termini di 0 e 1 binari.

Oltre alle istruzioni ``mnemoniche'' relative ai codici operativi,
esistono poi delle ``direttive''al compilatore (come d'altronde in
tutti i linguaggi di programmazione) ossia delle istruzioni che
permettono, tra le altre cose, di scrivere codice con maggiore
leggibilit\`a.

Vediamo un frammento di codice:

\begin{small}
\verbatiminput{esempio.asm}
\end{small}

La prima riga , cominciando per ``;'' , definisce un commento. La
seconda assegna il valore \textit{0xc} alla parola
\textit{``testreg''} , per aumentare la leggibilit\`a.  La terza
contiene il codice operativo \textit{movwf}, che copia il contenuto
del registro \textit{W} nel registro alla locazione \textit{0xC},
identificata da \textit{testreg}. Questa riga \`e proceduta
dall'etichetta \textit{label1}, che serve per riferirsi a questa riga
di programma da parte di altre istruzioni. L'ultima riga contiene
l'istruzione \textit{btfss} che verifica se il secondo bit di
\textit{testreg} \`e 1 ed eventualmente salta l'istruzione che
segue. Si noti l'indentazione, obbligatoria, presente nel codice
riportato.

In genere tutte le dichiarazioni \textit{``equ''} dei registri di
configurazione del microprocessore sono contenute in un file di
configurazione, fornito insieme al programma assemblatore ed incluso
nel codice scritto dall'utente.

\subsection{Esempio completo di un programma \Index{Assembler}}

Vediamo adesso un esempio di un programma Assembler completo. Si
tratta di un generatore di onde quadre. Viene generato un segnale sul
Pin 7 della Porta B con una frequenza di circa 5 Hz.  Per ogni riga
\`e riportato un commento nel seguito.  Il programma \`e composto dal
ciclo principale e dalla funzione \textit{``delay''} che genera il
ritardo.

\begin{small}
\verbatiminput{flash.asm}
\end{small}


Esaminiamo ora, una alla volta, queste istruzioni.

\begin{itemize}
\item{\textbf{1-3}}: commenti
\item{\textbf{4}}: il processore per cui viene effettuata la
\Index{compilazione} \`e il 16F877
\item{\textbf{5}}: file con le definizioni dei registri
\item{\textbf{6-7}}: i registri alle locazioni 0x30 e 0x31 sono
riferiti come \emph{delreg} e \emph{count}
\item{\textbf{8}}: le istruzioni che seguono sono caricate nelle
locazioni di memoria programma (flash) a partire dalla 0x0. La
locazione 0x0 corrisponde al vettore di reset, ossia l'esecuzione del
programma, all'accensione comincia da qui.
\item{\textbf{10-13}}: Il pin 7 della porta B deve essere definito
come output. Questo si ottiene ponendo a 0 il bit 7 del registro TRIS
B. Questo registro e' localizzato nel banco 1 della RAM. Prima di
tutto quindi, selezioniamo questo banco. Allo scopo i bit RP0 e RP1
del registro di stato devono essere posti, rispettivamente, a 1 e 0. A
questo punto possiamo porre a 0 il il bit 7 del registro TRIS B, ed
infine selezionare di nuovo il banco 0 di memoria (RP0 = 0)
\item{\textbf{15}}: Da questa riga ha inizio il programma principale,
   detto {\bf main}, \\ Viene posto a 1 il bit 7 del registro PORT B,
   il che equivale a far generare un livello alto al PIN B7 del
   microprocessore. A questa istruzione viene assegnata l'etichetta
   \textit{begin}.
\item{\textbf{16}}: viene chiamata la funzione \textit{delay}, che
genera un ritardo di circa 100 ms
\item{\textbf{17}}: viene riportato a 0 il bit 7 del registro PORT B e
quindi anche il valore di tensione sul pin B7 si porta a 0
\item{\textbf{18}}: viene di nuovo generato un ritardo di 100 ms
\item{\textbf{19}}:l'esecuzione salta indietro all'esecuzione del
codice operativo con l'etichetta \textit{begin}. E' chiaro quindi che
siamo in presenza di un loop infinito
\end{itemize}

Vediamo adesso in dettaglio come funziona la funzione
\textit{delay}. L'idea \`e quella di eseguire due loop, uno dentro
l'altro, decrementando ad ogni ciclo il valore di un registro per
loop. Quando entrambi i registri sono 0 l'esecuzione torna al
programma principale.

\begin{itemize}
\item{\textbf{22-25}}: i registri \textit{delreg} e \textit{count}
sono caricati rispettivamente con 0xff e 0x82. Si noti che per
caricare un registro con una costante, \`e necessario prima di tutto
caricare la costante nell'accumulatore e poi copiare l'accumulatore
nel registro.
\item{\textbf{26-28}}: l'istruzione, etichettata come \textit{loop2},
decrementa il valore del registro count, scrivendo il risultato
nuovamente dentro count.  Se il valore di count \`e diverso da 0 viene
eseguita la riga seguente e quindi il salto al loop interno
(\textit{loop1}), se invece \`e 0 viene saltata una istruzione, quindi
si passa alla riga 28, che fa saltare alla riga 32 che esegue
l'istruzione di ritorno al ciclo principale. Questo indica che il
ritardo programmato \`e trascorso.
\item{\textbf{29-31}}: qui si esegue il loop interno. Il registro
\textit{delreg} viene decrementato.  Se \textit{delreg} \`e diverso da
0 si esegue l'istruzione 30, che salta di nuovo indietro alla riga
29. Se \textit{delreg} vale 0 viene saltata una riga, riportando
quindi l'esecuzione all' indirizzo \textit{loop 2}, cio\`e al loop
esterno.
\end{itemize}

Cerchiamo di valutare il ritardo in termini di numero di cicli
macchina.  Le righe 22-25 sono eseguite in 4 cicli (una per ciclo). Le
righe 29-31 costituiscono il loop interno. L'istruzione
\textit{decfsz} richiede un ciclo se il risultato \`e diverso da 0 ,
altrimenti 2. Le istruzioni \textit{goto} richiedono due cicli, quindi
255 * (1+2) + 2 +2 = 769. Tornando all'istruzione alla riga 26, questa
esegue 0x82 = 130 volte il loop secondario. Quindi 130 * (1 +2 +749) +
2 +2 = 97764. Supponendo un clock con frequenza di 4 MHz, e quindi con
1 MHz di frequenza effettiva di esecuzione dei codici operativi,
questo comporta un ritardo di circa 100 ms, e poiche' lo stesso
ritardo e' applicato per la parte alta e bassa del ciclo, questo
equivale a generare un segnale con frequenza di circa 5 Hz.

Dopo aver compilato il programma con l'assemblatore, si ottiene la
seguente lista di codici operativi, espressi in formato
esadecimale. Questa stessa lista pu\`o poi essere caricata sul
microprocessore. Si noti che l'intero programma occupa solamente 20
locazioni della memoria programma.

Utilizzando la tabella in figura ~\ref{OPCODESTABL} \`e possibile
riconoscere tutte le istruzioni espresse in formato mnemonico nel
listato precedentemente commentato.

\begin{small}
\verbatiminput{codice.asm}
\end{small}


\subsection{Esempio di programmazione in C}

Risulta interessante valutare lo stesso programma scritto per\`o in un
\index{linguaggio}linguaggio di alto livello, quale il C.

\begin{small}
\verbatiminput{flash.c}
\end{small}

%\lstinputlisting[language=C]{flash.c} 




Ovviamente questo programma risulta molto piu' leggibile e intuitivo
del codice \Index{Assembler} prima analizzato, \`e per\'o necessario
notare che il codice, dopo la \Index{compilazione}, richiede 51
locazioni della memoria programma, quindi pi\`u del doppio di quanto
richiesto dalla programmazione diretta in \index{linguaggio}linguaggio
macchina.



