\subsection{Cahier des charges}

Voici les contraintes du bloc d'entrées / sorties :

\begin{itemize}
\item{Bloc de 8 entrées / sorties}
\item{Chaque fil est configurable soit en entrée, soit en sortie}
\item{Chaque fil est configurable pour générer une interruption sur front
montant et / ou front descendant}
\item{Un signal de RAZ}
\end{itemize}


% en gros c'est comment est vu le module côté userland.
\subsection{Vue comportementale}

Les blocs d'entrées / sorties ont plusieurs utilités. La première est de
pouvoir brancher des capteurs renvoyant une entrée binaire, par exemple la
sortie d'un comparateur. La deuxième est de permettre de commander, des
sorties comme par exemple l'allumage de LEDs. 

Finalement la troisième fonction de ce bloc sera de simuler un bus parallèle.
En effet, l'année dernière, nous utilisions un bus parallèle pour lequel nous
avons développé un certain nombre de cartes. A partir de blocs d'entrées /
sorties, on peut donc réutiliser les modules précédements développés.

On pourra voir la figure \ref{entity_gpio} page \pageref{entity_gpio} pour
avoir une vue globale du module.

\begin{figure}[htbp]
\caption{Entity du bloc d'entrées / sorties}
\begin{center}
\scalebox{0.6}{
\includegraphics {./gpio/images/entity.pdf}
%\includegraphics[width=\textwidth]{./interrupt/images/entity.pdf}
}
\end{center}
\label{entity_gpio}
\end{figure}

Du point de vue comportemental son fonctionnement est le suivant. Au début, le
PC configure le bloc après avoir envoyé un signal de remise à zéro. Il
commence par configurer les différentes pins du bloc soit en entrées, soit en
sorties. Ensuite le PC configure quelles pins pourront générer une
interruption. Ces interruptions peuvent être déclenchées soit sur front
montant, soit sur front descendant.

Une fois cela fait, il peut lire et écrire des données sur les
entrées et sorties. La configuration du bloc gpio est réalisée en écrivant
dans des registres. 

On remarque que ce module possède cinq signaux "chip select" : cs\_reg\_data,
cs\_reg\_direction, cs\_reg\_it\_up\_mask, cs\_reg\_it\_down\_mask et
cs\_read\_output. Le signal cs\_read\_output permet de lire les états des 8
broches d'entrées / sorties. Les autres signaux permettent d'accéder aux
registres contenant respectivement, le masque des directions, les masques
d'interruptions (font montant et descendant) et les données à mettre sur les
lignes en sorties. 

Ces quatres registres ont la particularité de pouvoir être écrit mais aussi lu.
En effet, pour la phase de teste il nous semble utile que les registres
puissent être relus. Ainsi on pourra s'assurer que la configuration est bien
celle désirée. 

Voici comment se déroule les procédures d'écriture et de lecture dans les
registres. La procédure d'écriture est la suivante. Tout d'abord, le module
dirigeant le bloc écrit sur le bus de donnés l'octet lui permettant de
configurer tel ou tel registre.

Simultanément, il positionne le signal $R\bar{W}$ en mode écriture (Write).
Finalement, il sélectionne à l'aide d'un des signal CS (Chip select) le
registre dans lequel il veut écrire.

La procédure de lecture s'effectue en positionnant le signal $R\bar{W}$ en
lecture (Read), puis en sélectionnant le chip select du registre auquel on
désire accéder. 

On notera que pour interfacer ce bloc et le bus ISA, il faut un module dont le
rôle sera de convertir les signaux du bus ISA (AEN, IOR, IOW) en les signaux
$R\bar{W}$ et les signaux de "chip select" (CS).

Pour résumer, voici quelques informations utiles :
\begin{itemize}
\item{La lecture (signal $R\bar{W}$) : active pour un état haut}
\item{L'écriture (signal $R\bar{W}$) : active pour un état bas}
\item{Les masques d'interruptions : interruption active pour un état haut,
	inactive pour un état bas}
\item{Le masque de directions : en sortie pour un état haut, en entrée pour un
	état bas}
\end{itemize}

\subsection{Exemple d'utilisation du module}

Voici un exemple pour illustrer les discours précédents. On pourra se reporter
au chronogramme figure \ref{gpio_behav_sim1} page \pageref{gpio_behav_sim1} Ce
chronogramme représente la simulation comportementale du bloc d'entrées
sorties.


%% TODO : Se débrouiller pour inclure les DEUX images

% Commande sympas : convert -rotate -90 fichier.tiff fichier.pdf
\begin{figure}[htbp]
\begin{center}
%\includegraphics[height=\textheight,angle=90]{./gpio/sim/gpio_behav_sim_test.pdf}
\includegraphics[height=0.8\textheight,angle=90]{./gpio/sim/gpio_behav_sim_dim.pdf}
%\includegraphics[width=0.7\textwidth,angle=90]{./gpio/sim/gpio_behav_sim1.pdf}
\end{center}
\label{gpio_behav_sim1}
\end{figure}


Dans cet exemple, nous allons configurer puis utiliser le bloc d'entrées /
sorties. La première action à effectuer est une remise-à-zéro du bloc à l'aide
de son signal reset. C'est ce que l'on remarque lorsque le signal rst est à 1.
Ce signal doit garder un état haut durant au moins une prériode d'horloge du
bus (clk\_b).

On remarque que sur les entrées /sorties, on simule le fait d'avoir branché
des capteurs sur les cinq lignes de poids fort. On voit donc apparaître sur 
la sortie les valeurs $00001ZZZ$. Cela signifie que l'on laisse les trois pins
de poid faible dans un état de haute impédance.

Une fois cela fait, on configure alors le bloc. Pour ce faire, l'ordinateur
place tout d'abord sur le bus de données le masque de direction. Dans
l'exemple, le masque est $00000111$, ce qui signifie que l'on désire
positionner les 3 pins de poid faible en sorties. On peut alors constater que
les trois pins du bloc qui sont en sortie, prennent la valeur $0$. Cela vient
du fait que lors du reset, on a remis le bloc à zéro, et par défaut, les
sorties sont à zéro d'ou les signaux obtenus.

On remarquera aussi que la ligne $R\bar{W}$ est en écriture. Ainsi, dès que
la ligne de validation du registre de configuration des directions (ligne chip
select : cs\_reg\_direction ) est à un état haut et qu'il y a un front montant
de l'horloge (clk\_b) du bus, on configure le bloc avec les signaux sur le bus
de données.

De la même manière, on configure ensuite les masques d'interruptions. On
positionne la valeur $11100000$ dans le registre reg\_it\_up et la valeur
$00011000$ dans le registre reg\_it\_down. Dans cette configuration, on vient
d'autoriser les interruptions sur les pins en entrée du bloc. Les registres
ainsi positionnés vont donc autoriser le déclenchement des interruptions des 3
bits de poid fort sur front montant, et des bits 4 et 5 sur front descendant.

Ensuite, on transmet au bloc les signaux que l'on désire voir sur les lignes
en sortie du bloc. Dans notre cas on transmet $00000001$. Comme seules les
trois pins de poid faible sont en sortie, on recopie en sortie $ZZZZZ001$ sans
tenir compte des bits de poid fort. Comme les "capteurs simulés" sur les cinq
bits de poid fort génèrent les valeurs $00001ZZZ$, on retrouve sur la sortie
un mélange de ces signaux, d'où la valeur de $00001001$.

Dans la suite, on se propose de relire les valeurs affectées aux différents
registres. C'est ce que l'on fait. On vérifie successivement les masques
d'interruptions, le registre de direction puis le registre de données.
Finalement le PC lit les valeurs situées sur les entrées sorties, ce qui
est réalisé grâce au signal cs\_read\_output.

On remarquera aussi le signal d'interruption. Celui-ci passe à l'état haut
lorsque l'état des "capteurs" change. Ici, on remarquera que c'est un front
descendant qui génère cette interruption. Le bloc d'entrées /sorties attend
alors que le PC demande à lire les entrées / sorties pour achever
l'interruption.

\subsection{Architecture physique}

Nous allons dans cette partie étudier plus en détails le fonctionnement
interne du module d'entrées /sorties. On pourra consulter l'architecture
physique sur la figure \ref{archi_gpio} page \pageref{archi_gpio}. 

\begin{figure}[htbp]
\caption{Architecture physique du bloc d'entrées / sorties}
\begin{center}
%\scalebox{0.7}{\includegraphics {./interrupt/images/archi_phy.pdf}}
\includegraphics[width=\textwidth]{./gpio/images/archi_phy.pdf}
\end{center}
\label{archi_gpio}
\end{figure}

Comme on peut le constater, ce module est relativement simple. On peut le
décomposer en deux parties : la configuration et la lecture / écriture des
entrées et sorties. Nous commencerons par nous pencher sur la configuration du
bloc.

Nous avons vu précédement que pour la configuration d'un bloc d'entrées /
sorties, il y avait trois registres de configuration. Un registre contenant un
masque déterminant la direction de chaque pin et deux registres contenant des
masques d'interruptions. On retrouve bien ces trois registres sur le schéma
directement connectés au bus de données.

On trouve un troisième registre nommé registre de données. Celui-ci est chargé
de mémoriser les valeurs à mettre sur les pins du bloc qui sont configurées en
sortie.

Pour revenir aux registres de configuration, ils sont alors connectés sur
d'autres blocs. Le premier, est le gestionnaire de direction et a pour but de
recopier les valeurs du registre de données uniquement sur les pins qui sont
configurées en sorties. Les deuxièmes et troisièmes sont les gestionnaires
d'interruptions qui sont chargés de générer les interruptions. On voit que
pour cela ils s'aident des masques d'interruptions "haut" et "bas".

Finalement, pour la lecture des entrées / sorties on connecte directement sur
les pins un bloc à trois états (état bas, état haut et haute impédance). Ce
bloc dès qu'on le sélectionne à l'aide du signal cs\_read\_output recopie les
entrées sorties sur le bus de données. On notera que ce module, de même que les trois registres, sont synchronisés sur l'horloge du bus ISA.


\subsection{Décomposition RTL}

\subsubsection{Les registres : reg\_rw}

Commençons par décrire le fonctionnement du registre synchrone nommé
\textit{reg\_rw}. Ce registre est un registre 8 bits pas tout à fait standard.
Comme les registres standards, il possède une horloge, un signal de
remise-à-zéro, un signal enable, des entrées au nombre de 8 et des sorties au
nombre de 8 également. Par contre, celui-ci a un signal supplémentaire : le
signal Read / Write ($R\bar{W}$). Son entity est donc la suivante :

\begin{itemize}
\item{1 signal d'horloge}
\item{1 signal de remise-à-zéro}
\item{8 signaux d'entrée}
\item{8 signaux de sortie}
\item{1 signal enable}
\item{1 signal read / write}
\end{itemize}

L'intérêt de ce registre par rapport à un registre "normal" est de pouvoir
relire son contenu. Cela est utile dans notre cas puisque durant le
développement de la carte, nous aurons besoin de pouvoir nous assurer du bon
fonctionnement des différents modules de la carte. L'implémentation de ce
registre est particulièrement adaptée à notre carte qui communique par bus.

On se rappelera que c'est un registre synchrone. Les opérations seront donc
effectuée à la suite d'un front montant. Pour résumer son fonctionnement,
voici comment ce registre se comporte :

\begin{itemize}
\item{Si $write$ ($R\overline{W}$ = '0') et $enable$, alors sauvegarde de
l'entrée et recopie de celle-ci en sortie.}
\item{Si $read$ ($R\overline{W}$ = '1') et $enable$ alors recopie de la
dernière valeure sauvegardée sur l'entrée.}
\item{Si $\overline{enable}$, alors recopie la dernière valeur sauvegardée sur
la sortie et positionne l'entrée en haute impédance.}
\end{itemize}

Le code correspondant au registre décrit précédement se trouve en
annexe~\ref{sec:reg_rw} page~\pageref{sec:reg_rw}.

\subsubsection{Le bloc trois-états : tristate}

Pour la lecture des valeurs sur les entrées / sorties, un composant nommé
\textit{tristate} est utilisé. L'entity de ce module est la suivante :

\begin{itemize}
\item{8 signaux d'entrée}
\item{8 signaux de sortie}
\item{1 signal enable}
\end{itemize}

Ce composant est en fait un module asynchrone composé de huits composants
trois états. Son comportement est donc le suivant :

\begin{itemize}
\item{Si enable (représenté par cs\_read\_output sur le schéma) est à un état
bas, les sorties sont dans un état haute impédance (noté 'Z')}
\item{Si enable est à l'état bas on recopie les entrées / sorties sur le bus
de données}
\end{itemize}

Le code correspondant au bloc décrit précédement se trouve en
annexe~\ref{sec:tristate} page~\pageref{sec:tristate}.


\subsubsection{Le gestionnaire de direction : gpio\_direction}

Lors de la conception du cahier des charges du bloc du module GPIO, nous
avions bien spécifié le fait que chaque pins devait être configurable soit en
entrée, soit en sortie. C'est le rôle de ce bloc. Son entity est la suivante :

\begin{itemize}
\item{8 signaux d'entrée}
\item{8 signaux de constituant un masque}
\item{8 signaux de sortie}
\end{itemize}

Celui ci fonctionne donc de la manière suivante. Pour ce faire, celui-ci
possède deux "bus" de 8 entrées chacun. Le premier de ces bus est destiné au
masque de direction. Le deuxièmes bus est destiné aux données.

Le masque est une série de "flags". Si un bit est dans un état haut, alors, ce
bit est considéré être en sortie. Ainsi, pour ce flag à l'état haut, on
recopiera sur la sortie le bit du bus de données.

Les pins autre n'étant pas définies comme des sorties par le masque sont
positionnés dans un état haute-impédance 'Z'. Le code correspondant au
bloc décrit précédement se trouve en annexe~\ref{sec:gpio_direction}
page~\pageref{sec:gpio_direction}.


\subsubsection{La détection d'interruptions : gpio\_it\_detect\_up et down}

Le but de ces deux modules est de générer les interruptions. Le premier est
chargé de générer une interruptions si il y a un front motant. Le deuxième
fait la même chose, mais pour les fronts descendants. Les entity de ces deux
blocs sont identiques et sont :

\begin{itemize}
\item{1 signal d'horloge}
\item{1 signal de remise-à-zéro}
\item{8 signaux d'entrée}
\item{8 signaux de constituant un masque}
\item{1 signal de sortie (interrupt detected)}
\end{itemize}

Chacune des 8 pins devant être configurable pour déclencher une interruption
ou non, nous avons recours à des masques. Chaque gestionnaire à son propre
masque. De cette manière, on peut définir les masques de telle manière qu'une
pin puisse générer une interruption, sur front montant, descendant ou sur les
deux.

Le code associé au gestionnaire d'interruption sur front montant se trouve en
annexe~\ref{sec:gpio_it_detect_up} page~\pageref{sec:gpio_it_detect_up}. Le
code associé au gestionnaire d'interruption sur front descendant est donné
annexe~\ref{sec:gpio_it_detect_down} page~\pageref{sec:gpio_it_detect_down}.


\subsubsection{Le module gpio}

Ce bloc est celui dont le comportement aura été décrit précédement dans les
sections en rapport avec l'architecture physique. On pourra d'ailleurs se
rapporter aux différents schémas précédement vus. Voici l'entity de ce bloc :

\begin{itemize}
\item{1 signal d'horloge}
\item{1 signal d'horloge de bus}
\item{1 signal de remise-à-zéro}
\item{1 signal read / write}
\item{1 signal d'interruption}
\item{8 signaux associés au bus de données}
\item{4 signaux pour accéder aux différents registres}
\item{1 signal pour lire les valeurs sur les entrées / sorties}
\end{itemize}

Ce bloc est donc l'assemblage des différents modules qui viennent d'être
décrits. Le listing correspondant à ce module est donné annexe~\ref{sec:gpio}
page~\pageref{sec:gpio}.


\subsection{Résultats de synthèse logique}

Ci dessous sont présentées un résumé des informations fournies suite à la
synthèse logique du module.

\lstinputlisting{./gpio/res_gpio.syr}

On peut donc constater que les ressources qui seront utilisées par un module
gpio adaptées au FPGA que nous avons choisi, à savoir, un Spartan2 xc2s200
avec un boitier pq208.

En effet, nous avons décidé d'avoir 5 modules gpio sur la carte, ce qui
représente 40 pins utilisées et 5\% des ressources en slices. Ces
caractéristiques nous conviennent parfaitement.


\subsection{Simulation du bloc et test sur carte}

Voici les résultats de la simulation RTL de notre bloc d'entrées / sorties.

%% TODO : Se débrouiller pour inclure l'images

On pourra vérifier que celle-ci est bien conforme aux résultats escomptés en
se reportant à la simulation comportementale.

Après cette synthèse, nous avons programmé une carte de test pour vérifier
qu'il n'y ai pas d'anomalie et nous avons pu constater que tout se déroule
comme prévu !

