Programmation des FPGA Xilinx.


Le composant est configuré par le téléchargement d'un fichier binaire dans une mémoire interne. Pour celà plusieurs possibilité :
1. Programmation par le cable JTAG. (M2-M1-M0=101)
2. Programmation par lecture d'une PROM (IsP). (M2-M1-M0=000 ou 111)
3. Programmation par bus parrallèle. (M2-M1-M0=110)
4. Programmation par bus USB, série multilinx...

  -------------------------------
  1. Programmation par port JTAG.
  -------------------------------

La configuration par le port JTAG (boundary scan) est possible quelque soit le mode (M0/M1/M2).
Une application autonome sans processeur nécéssite l'emploi d'une PROM IsP (in system programmable.)
La PROM peut alors être programmée in situ en utilisant les 4 signaux JTAG qui suivent :
TCK : JTAG test clock.
TDI : JTAG serial data input (pull up à 1)
TDO : JTAG serial data output (pull up à 1)
TMS : JTAG mode select input (pull up à 1)
VCC : Alimentation positive.
GND : référence.
Les détails de ce mode de fonctionnement sont largement décrit dans les datasheet Xilinx.
Le logiciel fourni par Xilinx est iMPACT et permet la programmation ainsi que le test des circuits grâce aux vecteurs SFV.

Connection du xilinx et de la PROM.

Le lien qui suit présente un schéma permettant le dialogue entre un PC et le port JTAG. Les buffers du convertisseur parrallèle vers JTAG sont alimentés par la carte cible (2.5V selon le Xilinx). Cette tension est renvoyée sur l'entrée d'erreur du port // pour des raisons mystérieuses.
Schéma d'un convertisseur port parallèle PC vers JTAG.
JTAG. (site officiel)
JTAG. (aspect technique)

  --------------------------------
  2. Programmation par bus 8 bits.
  --------------------------------

Le niveau logique des broche est de 3.3V (Le port parallèle fournit du TTL => transistor) La broche PROGRAM\ doit être mise à '1' avant une nouvelle configuration.
La programmation par bus parallèle est la plus rapide, les données sont envoyées octet par octet dans le FPGA qui génère un "BUSY flag" pour controller le flux de données.
Si la ligne BUSY est mise à '1' par le FPGA, la donnée doit être maintenue jusqu'à la mise à zéro de BUSY.
Chaque front montant de CClk permet d'incrémenter le compteur d'adresse interne.(?vérif?)
Il est possible de lire le contenu du FPGA, dans ce cas WRITE\ est positionné à '0'.
Les données sont envoyées avec le MSB de chaque octet sur D0 et le lsb sur D7.
Il est possible de programmer plusieurs composants, CS\ valide celui qui sera la cible.
Quand le circuit est programmé, la broche DONE passe à '1'.

Mécanisme d'écriture (algorithmie):

/*----------------------------------------------------------------*/
WRITE\   = 0       Autorise l'écriture de la mémoire de configuration
CS\      = 0       Valide le circuit

Tant que le fichier n'est pas vide :
|  D[7:0] = Data;  octet à envoyer sur le port parallèle
|  CCLK   = 0      génère un front montant
|  WAIT            attente : c'est une pseudo horloge
|  CCLK   = 1      pour la prise en compte de la donnée
|
|  if (BUSY==0)    la donnée est accépté
|    octet++       continuer le traitement
|  sinon           la donnée sera accepté au premier front montant
|    wait          de CCLK après passage à 0 de BUSY
|  fin si
Fin tant que

si (DONE=1)        programmation correcte

WRITE\   = 1       Fin d'écriture possible
CS\      = 1       Le circuit n'est plus valide
/*----------------------------------------------------------------*/

En fait, si l'horloge CCLK est suffisemment lente, BUSY n'influencera pas la séquence de programation, les problèmes se poseront quand il faudra optimiser la vitesse de programmation. (mais comme t'as le temps, gamin, tu t'fais pas) Donc la boucle d'attente "si BUSY==0" est supperflue ; les données seront programmées à chaque front montant de CCLK.

Chronnogrammes :

        __    __    __    __    __    __    __
 CCLK     |__|  |__|  |__|  |__|  |__|  |__|  |__
        ___                                   ___
 CS\       |_________________________________|
        __                                     __
 WRITE\   |___________________________________|
        ____ ________________ ________________ ___
 D[0:7] ____X________________X________________X___
                               _____
 BUSY   ______________________|     |_______________

 D0 à D7 : Setup de 5 ns(1) Hold de 1.7 ns(2)
 CS\     : Setup de 7 ns(3) Hold de 1.7 ns(4)
 WRITE\  : Setup de 7 ns(5) Hold de 1.7 ns(6)
 BUSY    : 12ns(7)
 CCLK    : 50MHz au maximum

Employons le port parallèle du PC pour programmer le composant.
Prérequis : Le port parallèle :
HOW TO

Adresse de base du port parallèle : 378H-37BH = 11 0111 10XX
Le port LPT1 est situé à l'adresse 378, le port LPT2 à l'adresse 278.
Soit 888 thru 891 decimal, avec 891 non utilisé.
Le port BASE (port de donnée) permet l'envoie d'un octet.
Le port BASE+1 (port d'état) est en lecture seule et retourne l'état des signaux d'entrée suivants :
Bits 0 et 1 sont réservés. Bit 2 état d'IRQ Bit 3 ERROR (1 = état haut) Bit 4 SLCT (1 = état haut) Bit 5 PE (1 = état haut) Bit 6 ACK (1 = état haut) Bit 7 -BUSY (0 = état haut) Le port BASE+2 (port de contrôle) est en écriture seule :
Bit 0 -STROBE (0 = état haut) Bit 1 -AUTO_FD_XT (0 = état haut) Bit 2 INIT (1 = état haut) Bit 3 -SLCT_IN (0 = état haut) Bit 4 active la requête d'interruption (IRQ) du port parallèle Bit 5 contrôle la direction du mode étendu (0 = écriture, 1 = lecture) Bits 6 et 7 sont réservés.

Brochage DB25 (SPP signal):

<= in   DB25    Name of         Reg
=> out  pin     Signal          Bit     Function Notes
------  ----    --------        ---     -----------------------------
=> (e/s) 1      -Strobe         C0-     Set Low pulse >0.5 us to send
=> (e/s) 2      Data 0          D0      Set to least significant data
=> (e/s) 3      Data 1          D1      ...
=> (e/s) 4      Data 2          D2      ...
=> (e/s) 5      Data 3          D3      ...
=> (e/s) 6      Data 4          D4      ...
=> (e/s) 7      Data 5          D5      ...
=> (e/s) 8      Data 6          D6      ...
=> (e/s) 9      Data 7          D7      Set to most significant data
<= (e)   10     -Ack            S6+ IRQ Low Pulse ~ 5 uS, after accept
<= (e)   11     +Busy           S7-     High for Busy/Offline/Error
<= (e)   12     +PaperEnd       S5+     High for out of paper
<= (e)   13     +SelectIn       S4+     High for printer selected
=> (s)   14     -AutoFd         C1-     Set Low to autofeed one line
<= (e)   15     -Error          S3+     Low for Error/Offline/PaperEnd
=> (s)   16     -Init           C2+     Set Low pulse > 50uS to init
=> (s)   17     -Select         C3-     Set Low to select printer
==       18-25   Ground
Routine en c pour écrire sur le port parallèle :
/*
* exemple.c : un exemple très simple d'accès aux ports d'E/S
*
* Ce programme ne fait rien d'utile, juste une écriture sur le port,
* une pause, puis une lecture sur le même port.
* À compiler avec « gcc -O2 -o exemple exemple.c »et à
* exécuter en tant que root avec « ./exemple ».
*/

#include 
#include 
#include 

#define BASEPORT 0x378 /* lp1 */

int main()
{
/* Obtention de l'accès aux ports */
if (ioperm(BASEPORT, 3, 1)) {perror("ioperm"); exit(1);}

/* Initialisation de tous les signaux de données (D0-D7) à l'état bas (0) */
outb(0, BASEPORT);

/* Dormons pendant un moment (100 ms) */
usleep(100000);

/* Lecture sur le port d'état (BASE+1) et affichage du résultat */
printf("status : %d\n", inb(BASEPORT + 1));

/* Nous n'avons plus besoin de l'accès aux ports */
if (ioperm(BASEPORT, 3, 0)) {perror("ioperm"); exit(1);}

exit(0);
}

/* fin d'exemple.c */