# Very High Speed Integrated Circuit Hardware Description Language/Embarquer un PIC 16F84

Nous allons mettre en œuvre dans ce chapitre un processeur softcore compatible avec le PIC® 16F84 de Microchip. Il s'agit d'un processeur RISC sur 8 bits. Après avoir exploré le processeur original, nous nous concentrerons sur le modèle VHDL du système mono-puce. Ce projet, bien que relativement simple, nécessitera une exploration avancée du cœur pour y réaliser certaines modifications : ajout d'un troisième PORT et ajout du signal "strobe" associé. Ce travail ne sera pas présenté dans ce chapitre.
Le contenu de ce paragraphe peut sembler redondant avec les chapitres silicore1657 et ATMega8. Je rappelle que tous ces chapitres sont des projets qui font exactement la même chose, gérer un jeu de pong, d'où cette redondance. Il vous est demandé de choisir votre architecture et de lire le chapitre correspondant. Désolé, mais il en faut pour tous les goûts !

## Choix du cœur

Il existe au moins trois versions de descriptions de cœur PIC® 16F84 sur Internet. La plus à jour me semble être un projet en Verilog, appelé risc16F84 dans la suite, et disponible sur le site d'opencores avec des mises à jour récentes (2006). Mais ayant des étudiants qui ne pratiquent que VHDL, nous avons décidé d’utiliser le projet CQPIC, plus ancien certes, mais à l'origine de ce cœur risc16F84.
Nous avons déjà eu l’occasion d’utiliser un cœur de processeur 16C57 dans un autre chapitre de ce cours. Cet ancien projet, dénommé silicore1657 dans la suite de ce document, nous a permis d'acquérir un peu d'expérience mise à profit pour le choix du cœur. Il existe en effet un autre cœur VHDL PIC16F84, appelé PPX par la suite, de Daniel Wallner qui a été utilisé et débogué par Patrice Nouel, Maître de Conférence à l’ENSEIRB (à la retraite maintenant). Mais mon choix s'est porté sur le CQPIC car il n'utilise pas de PORT bidirectionnel mais décompose les PORTS (comme expliqué plus loin dans ce document). La documentation du Silicore1657 nous a alerté à ce sujet : elle attire l'attention de l’utilisateur sur l’utilisation des PORTs dans un cœur. Un cœur bien réalisé doit proposer tout sauf la ROM la RAM et les PORTS parce que leur implémentation est trop dépendante du fabricant du FPGA ciblé. Il n'y a, en effet, aucune norme pour implanter ceux-ci.
Le CQPIC est un cœur de processeur (ou processeur softcore) compatible avec le PIC® 16F84 de microchip. On pouvait le trouver sur Internet sous la forme d'un fichier "cqpic100d.zip". Comme il devient difficile de le trouver nous avons mis une version (améliorée ?) sur Internet : CQPICStart.zip. Il a été développé par Sumio Morioka (Japon) et publié en décembre 1999 dans "Transistor Gijutsu Magazine" (sa dernière mise à jour datait de 2004 avant la notre en 2010)
* L'hébergement de mon site perso se termine le 5 septembre 2023 ! À ce jour je n'ai pas encore décidé comment je vais gérer ce problème dont je ne suis pas à l'origine. Il en résulte que le lien CQPICStart et l'ensemble des corrections qui utilisent mon site perso seront indisponibles à partir de cette date. SergeMoutou (discuter)
Nous allons commencer par présenter la partie hardware du cœur en nous basant sur la documentation de Microchip. Vous pouvez lire aussi comment démarrer avec un PIC16F84 ainsi qu'un cours complet de la wikiversité dédié à la programmation des 16F et 18F avec un peu d'assembleur et beaucoup de C.

## Architecture du PIC® 16F84

Il s'agit d'un processeur 8 bits avec des instructions codées avec un opcode sur 14 bits. La version originale de ce PIC avait peu de RAM (68 octets). Une autre de ses limitations est la taille de sa pile : avec une pile de huit niveaux seulement, il doit être difficile de réaliser un compilateur C.
Ce processeur gère un certain nombre d'interruptions.
Nous allons commencer par présenter le plus difficile, l'architecture des registres mémoire (Register File dans la terminologie anglo-saxonne que l’on pourrait traduire par dossier/classeur de registres (j'ai trouvé aussi fichier de registres), mais nous préférons registres mémoire ou mémoire de registres ou banc de registres). Nous parlons de difficultés parce qu’il y a plusieurs banques mémoires ce qui est une caractéristique des architectures 8 bits Microchip (jusqu'aux séries 18FXXX) qui disparaissent seulement avec les architectures 16/32 bits (24FXXX et autres)

### Architecture des registres SFR et de la mémoire

Les registres SFR (Registres internes à Fonctions Spéciales) sont répartis en deux banques. Cette partie de mémoire est suivie par 68 registres d’usage général pouvant être utilisés comme mémoire simple qui sont identiques sur les deux banques. Ensuite vient une série de registres généraux qui eux dépendent de la banque mémoire choisie et qui ne sont pas implémenté dans le 16F84 original.
La mémoire du 16F84 est organisée en banques sélectionnées par le(s) bit(s) RP0 (et RP1) du registre STATUS. Seul RP0 est utilisé pour le 16F84, soit deux banques.

#### RAM et Registres du 16F84

    Adr.Banque0Banque1Adr. 00hIndirect addr.Indirect addr.80h 01hTMR0OPTION_REG 02hPCLPCL82h 03hSTATUSSTATUS 04hFSRFSR84h 05hPORTATRISA 06hPORTBTRISB86h 07h---- 08hEEDATAEECON188h 09hEEADREECON2 0AhPCLATHPCLATH8Ah 0BhINTCONINTCON 0Ch – 4Fh68 cases mémoiresidem banque 08Ch – CFH 50h – 7FhinutiliséinutiliséD0H – FFH
La première partie de cette mémoire (les registres) est parfois appelée banc de registres (ou fichier de registres). La partie marquée inutilisée est naturellement inutilisée dans le PIC16F84 original mais sera en fait utilisée par notre cœur CQPIC. Remarquez aussi l'adresse 07h et 87h inutilisée dans le PIC16F84 mais utilisée par notre cœur comme PORTC.
Vous pouvez lire aussi comment démarrer avec un PIC16F84 et/ou Utiliser les PIC 16F et 18F.

### Les instructions

Cette section est difficile à comprendre. Même si elle ne fait intervenir que des notions du niveau indiqué, il est conseillé d'avoir du recul sur les notions présentées pour bien assimiler ce qui suit. Cependant, ce contenu n'est pas fondamental et peut être sauté en première lecture.
Il est temps de présenter maintenant l’ensemble des 35 instructions du PIC® 16F84 codées sur 14 bits. Vous trouverez en colonne de gauche le code binaire de l'instruction se trouvant au centre puis une courte explication de ce que fait l'instruction.
Les opérandes peuvent être de plusieurs types:
* f : adresse mémoire de registres (register file address) de 00 à 7F
* W : registre de travail
* d : sélection de destination : d=0 vers W, d=1 vers f
* pp : numéro de PORT entre 1 et 3 sur deux bits
* bbb : adresse de bit dans un registre 8 bits (sur 3 bits)
* k : champ littéral (8, ou 11 bits)
* PC compteur programme
Jeu d'instructions 14-bit pour PIC 16F84 :
| Opcode (binary) | Mnemonic | Description |
| 00 0000 0xx0 0000 | NOP | Pas d'opération |
| 00 0000 0110 0011 | SLEEP | arrête le processeur |
| 00 0000 0110 0100 | CLRWDT | Reset du timer watchdog |
| 00 1000 dfff ffff | MOVF f,d | Recopie de W dans f (adressage direct) |
| 00 0000 1fff ffff | MOVWF | déplacement de W vers f |
| 00 0001 0xxx xxxx | CLRW | Positionne W à 0 (idem à CLR x, W) |
| 00 0001 1fff ffff | CLRF f | Positionne f à 0 (idem à CLR f, F) |
| 00 0010 dfff ffff | SUBWF f, d | Soustrait W de (d = f − W) |
| 00 0011 dfff ffff | DECF f, d | Décrément f (d = f − 1) |
| 00 0100 dfff ffff | IORWF f, d | OU Inclusif W avec F (d = f OR W) |
| 00 0101 dfff ffff | ANDWF f, d | ET entre W et F (d = f AND W) |
| 00 0110 dfff ffff | XORWF f, d | OU Exclusif W avec F (d = f XOR W) |
| 00 0111 dfff ffff | ADDWF f, d | Additionne W avec F (d = f + W) |
| 00 1000 dfff ffff | MOVF f, d | recopie F (d = f) |
| 00 1001 dfff ffff | COMF f, d | Complement f (d = NOT f) |
| 00 1010 dfff ffff | INCF f, d | Incrément f (d = f + 1) |
| 00 1011 dfff ffff | DECFSZ f, d | Decrément f (d = f − 1) et saut si zero |
| 00 1100 dfff ffff | RRF f, d | Rotation droite F (rotation droite avec la retenue) |
| 00 1101 dfff ffff | RLF f, d | Rotation gauche F (rotation gauche avec la retenue) |
| 00 1110 dfff ffff | SWAPF f, d | échange de groupes 4-bit de f (d = lsb:f msb:f) |
| 00 1111 dfff ffff | INCFSZ f, d | Incrément f (d = f + 1) et saut si zero |
| 01 00bb bfff ffff | BCF f, b | RaZ d'un bit de f (Clear bit b of f) |
| 01 01bb bfff ffff | BSF f, b | Mise à 1 d'un bit de f (Set bit b of f) |
| 01 10bb bfff ffff | BTFSC f, b | test de bit de f, saute si zéro (Test bit b of f) |
| 01 11bb bfff ffff | BTFSS f, b | test de bit de f, saute si un (Test bit b of f) |
| 11 01xx kkkk kkkk | RETLW k | Positionne W à k et retour |
| 10 0kkk kkkk kkkk | CALL k | Sauve l'adresse de retour, charge PC avec k |
| 00 0000 0000 1001 | RETFIE | retour d'interruption |
| 00 0000 0000 1000 | RETURN | retour de sous-programme |
| 10 1kkk kkkk kkkk | GOTO k | saut à l'adresse k (9 bits!) |
| 11 111x kkkk kkkk | ADDLW k | Addition de W et k |
| 11 110x kkkk kkkk | SUBLW k | Soustraction de W et k |
| 11 00xx kkkk kkkk | MOVLW k | Chargement littéral de W (W = k) |
| 11 1000 kkkk kkkk | IORLW k | OU Inclusif littéral avec W (W = k OR W) |
| 11 1001 kkkk kkkk | ANDLW k | ET littéral avec W (W = k AND W) |
| 11 1010 kkkk kkkk | XORLW k | OU exclusif or littéral avec W (W = k XOR W) |
Dans la terminologie Microchip, littéral signifie en adressage immédiat.
Vous pouvez lire aussi comment démarrer avec un PIC16F84 et/ou Utiliser les PIC 16F et 18F.

### Architecture matérielle du PIC 16F84

L'architecture matérielle du PIC 16F84 est relativement simple : elle peut être présentée sous forme de schéma.
Évidemment, une description matérielle de cette architecture en VHDL laisse de côté un certain nombre de fonctions comme la réalisation d'une horloge, la gestion analogique des ports avec la possibilité de résistances de tirages par exemple …

## Notre cœur ou processeur softcore

Le cœur original CQPIC a été réalisé de manière à être le plus proche du composant PIC® 16F84 original. Voici maintenant une description du cœur sous forme de programme VHDL.
À noter que contrairement au PIC® 16F84, le composant CQPIC utilise une entrée spécifique "t0cki" pour le timer0 (pour le PIC® c’est le bit b4 T0CKl du PORTA). Il y a encore bien d'autres différences : comparez au brochage original du PIC® 16F84 décrit dans un autre projet qui fait apparaître 18 broches seulement.
En général un processeur softcore comprend toujours beaucoup plus d'entrées sorties que le processeur original. Une des raisons est que le cœur donné ci-dessus ne comprend pas sa RAM et sa ROM contrairement au composant original.
Avant de passer aux périphériques nécessaires au bon fonctionnement, il nous faut aborder le problème très spécifique des ports.

### Les deux ports du CQPIC

Nous avons fait des modifications sur la gestion des PORTS dans le cœur original qui seront présentées plus loin. Nous nous contenterons dans cette section de généralités.
Les ports sont des entités très spécifiques dans un micro-contrôleur car ils sont bidirectionnels. Ce côté bidirectionnel est difficile à implanter de manière générale dans un FPGA puisqu’il dépend du fabricant (du FPGA) et donc de l'environnement d'utilisation. Ainsi, la description VHDL des ports est laissée à l'utilisateur du cœur CQPIC.
Un coup d'œil sur le cœur nous montre que chaque port est décomposé en trois ports distincts. Par exemple, pour le PORTA on trouve porta_dir, porta_in et porta_out. Cette façon de faire est assez courante dans les "soft core" et j’ai déjà eu l’occasion de la rencontrer lors d'un projet précédent, le silicore1657. La bidirectionnalité des PORTs est gérée par un registre spécial TRIS associé à chacun des ports. Ces registres spécifiques existent dans le cœur, ils s'appellent porta_dir et portb_dir. Ils sont tous les deux sur 8 bits contrairement au PIC® 16F84 pour lequel le PORTA ne possède que 5 bits et peuvent être utilisés soit comme ports généraux en sortie, soit pour la gestion bidirectionnelle. Les ports proprement dit se décomposent alors en port d'entrée porta_in et portb_in ainsi qu'en ports de sortie porta_out et portb_out.
Pour des raisons de compatibilité le port porta_dir n’est pas accessible de manière normale. L'écriture dans porta_dir se fait par l'instruction :
tandis qu'en assembleur on écrira :
Comme deuxième remarque, nous dirons qu’à l'origine le PORTA ne disposait que de 5 bits et que nous avons modifié le cœur et le fichier CQPIC.VHD pour que l’on puisse l’utiliser sur 8 bits. Tous les fichiers correspondants se trouvent dans le répertoire "\CQPICStart\PORTA8" du fichier CQPICStart.zip.
Notre dernière remarque sera pour compléter notre description. Si l’on écrit dans un programme C :
ceci aura comme signification : porta_out <= porta_in. Physiquement, ce qui est à gauche du signe égal, n’est pas la même chose que ce qui est à droite.
La description des PORTs dans cette section n’est pas complète et sera reprise quand nous aurons besoin de les relier à une logique externe.
Abordons maintenant les deux autres périphériques nécessaires, la RAM et la ROM. Ces deux composants ne font pas partie du cœur tout simplement parce que les implantations de ceux-ci sont spécifiques aux FPGA cibles.

### La RAM

Il existe peu de modèles de mémoire standard dans le monde des FPGA et ASIC. En fait le type le plus commun de mémoire que l’on peut trouver est ce que la norme WISHBONE appelle 'FASM', ou FPGA and ASIC Subset Model. Pour la RAM, sa spécificité est qu’il s'agit d'une mémoire à écriture et lecture synchrone. Il est facile de trouver des exemples d'une telle mémoire en VHDL. Nous avons choisi :
La gestion de la RAM dans un système mono-puce n’est pas un problème aussi simple qu’il n'y parait. Examinons de plus près ce problème et ce qui fait sa difficulté.
Un coup d'œil sur le programme ci-dessus nous indique immédiatement que les adresses mémoires sont sur 9 bits alors que la documentation du PIC16F84 donne des plages inutilisées à partir de FFh soit sur 8 bits. En VHDL, donner plus de mémoire à un cœur se fait très facilement s'il y a de la place dans le FPGA pour cela. Comme nous avons décidé d’utiliser un compilateur C, notre problème est de savoir comment faire comprendre au compilateur C que l’on dispose de plus de mémoire que prévu ?
Normalement les compilateurs ont une directive de compilation pour cela qu’il n’est pas difficile de trouver en page 60 de la documentation du compilateur HiTech C.
Aller dans :
Project → Build Options → project →onglet "global" et remplir "RAM Range".
Sans directive on obtient :
Data space used 7h ( 7) of 44h bytes ( 10.3%)
Avec "default,+50-7f" on obtient :
Data space used 7h ( 7) of 74h bytes ( 6.0%)
Avec "default,+50-7f,+d0-ff" on obtient :
Data space used 7h ( 7) of A4h bytes ( 4.3%)
ce qui montre que l’on peut effectivement augmenter l'espace géré par le compilateur. Nous avons réussi à gérer toutes les adresses sur 8 bits. Il nous reste un 9e bit à gérer. Mais cela nécessite forcément d'aller regarder dans le cœur comment tout cela est géré, ce que nous n'avons pas fait pour le moment. Nous pensons de toute façon qu’il faut changer de PIC pour prendre un PIC16F87X dans notre projet C, mais ceci n’est pas sans risque puisqu’il y a alors quatre banques et que certain des registres ont été déplacés.

### La ROM

C'est là que se situe le programme à exécuter. Puisque tout compilateur ou assembleur génère un fichier hex, il nous est nécessaire de transformer ce fichier hex en fichier VHDL. Ceci est laissé à un programme C décrit un peu plus loin. Commençons à présenter un exemple de ROM.
Cet exemple montre un contenu mais chaque programme donnera une ROM différente. Il est à noter que ce que l’on présente est du VHDL alors que chaque compilateur ou assembleur ne délivre qu'un fichier au format HEX. Il faudra donc un utilitaire pour transformer le fichier HEX en fichier VHDL car il s'agit d'une opération qui peut se se faire automatiquement. Nous utiliserons un programme en C++ que nous donnons en annexe 1 et qui se trouve dans le répertoire "\CQPICStart\ROM" du fichier CQPICStart.zip.

## Nos premiers programmes en C

Nous n'allons pas présenter le langage C maintenant puisque d'autres projets le font :
* Le langage C chez Wikipédia
* La programmation C et ses exercices chez WikiBook
* Introduction au langage C et les PIC 16F et 18F en assembleur et C chez Wikiversité
La programmation du cœur se fait à l'aide de l'environnement MPLAB. Ce n’est pas le seul environnement de développement pour les PICs, mais c’est probablement un des plus utilisés et pour ne rien gâcher, il est gratuit. Le téléchargement de MPLAB nous permet d’utiliser l'assembleur ainsi que le compilateur C HiTech. Puisque nous avons décidé pour ce projet de n'utiliser que des outils gratuits, le compilateur C n’est pas optimisé, pour cela il faut payer.
MPLAB fonctionne sous wine donc sous Linux contrairement à winAVR.
MPLABX fonctionne directement sous Linux (sans wine) et naturellement sous Windows.
Notre premier programme en C a été réalisé pour tester le fonctionnement du cœur CQPIC sur notre carte d'application Digilent.
Notre architecture CQPIC étant une architecture 8 bits avec peu de mémoire RAM, il peut sembler intéressant de commencer par présenter un programme en C mais qui ne contient que de l'assembleur.

### Le premier programme simple en C avec assembleur

Le programme présenté montre comment inclure de l'assembleur dans un programme C.
Ne prenez pas ce programme à la lettre. Il est donné pour exemple mais fonctionne de manière surprenante.
* Pour avoir d'autres exemples en assembleur, consultez le WIKIBOOK Comment démarrer avec un PIC 16F84.

### Le premier programme simple en C pur

Un programme tout simple de test est présenté maintenant : il s'agit tout simplement de recopier le PORTA sur le PORTB. Remarquons aussi que ce programme fonctionne complètement si l’on a pris soin de prendre la version que j’ai réalisée.
Contrairement au Silicore1657 déjà évoqué (projet de l'année précédente), le cœur CQPIC dispose du mécanisme d'interruption que nous allons détailler maintenant avec un exemple simple.

### Interruption

Pour tester plus en avant notre cœur CQPIC, je décide d’utiliser une interruption. La plus simple des interruptions à mettre en œuvre étant celle du timer0, nous allons examiner maintenant la documentation correspondante.

#### La documentation du timer0

Nous présentons maintenant le schéma complet correspondant à ce timer0.
Comme on peut le voir dans la documentation schématique, la gestion du timer0 est essentiellement réalisée par le registre OPTION. Seuls les trois bits de poids faibles de ce registre sont à positionner à 1 pour avoir une division par 256. Comme on le verra dans le programme, cette division ne suffit pas il faudra encore lui ajouter une division par 16 dans l'interruption même, pour que notre chenillard soit visible.
Mettre en route le timer0 est une chose, mais déclencher une interruption en est une autre. Il nous faut maintenant documenter ce mécanisme.
Pour réaliser l'interruption, il faut réaliser un front montant dans l'ellipse rouge : on en déduit immédiatement les bits à mettre à 1 dans INTCON, à savoir T0IE et GIE.
Vous trouverez un peu plus de détails dans un autre projet sur le timer 0 et son interruption. Les schémas internes utilisés sont les mêmes, mais avec un peu plus de commentaires.

#### Le programme

Le programme correspondant est donné maintenant.
Remarquez le "if (!(nb % 16))" qui réalise la division par 16 dans l'interruption. C'est absolument nécessaire pour notre cœur qui fonctionne à 50 Mhz pour voir les LEDs allumées se déplacer.
Le lecteur, fin programmeur, nous fera remarquer, à juste titre, que la division est par 16. Il s'agit donc d'une division par une puissance de 2. Le calcul du reste peut alors se faire avec un masque. C'est certainement plus optimisé que l'opérateur modulo mais le projet de pong ne nécessite pas ce genre d'optimisation : notre programme passe son temps à attendre !
Il est maintenant grand temps de revenir sur notre problème original, à savoir interfacer un écran VGA.

## Assemblage du cœur, des mémoires et du module VGA

À la fin de ce précédent chapitre Interfaces VGA, nous avons présenté un module capable de dessiner une balle et deux raquettes, ces trois objets étant mobiles.
Utile aussi de lire ou de relire l'article sur le VGA.

### Le problème des PORTs

Nous avons besoin de deux fois 10 bits pour piloter nos coordonnées de balles. Une autre façon de dire les choses est qu’il nous faut 4 ports de 8 bits en sortie. Or, nous ne disposons que de deux PORTs de 8 bits en sortie (et encore parce que j’ai étendu le PORTA originel. C'est insuffisant. Il nous faut donc réfléchir sur la façon dont on va pouvoir connecter toutes ces données en sortie.
Pourquoi seulement deux PORTs en sortie ? L'entité du piccore présentée en section précédente ne montre-t-elle pas porta_dir et portb_dir en sortie ?
La modification du cœur CQPIC pour augmenter le nombre de bits du PORTA, m'a amené à lire son code VHDL et je suis tombé sur :
Ce code montre que TRISA est pris en compte en interne dans le cœur CQPIC. Ceci peut sembler normal, mais n’est pas conforme à la seule expérience que nous avions avec le Silicore1657 : puisque TRISA était sorti à l'extérieur il pouvait servir de PORT supplémentaire. Si vous avez l’idée d’utiliser TRISA comme PORT supplémentaire ici, vous aurez un fonctionnement étrange d'un programme C :
Physiquement, on relie PORTA (ra_out) à des interrupteurs et TRISA (ra_dir) à des LEDs. Si PORTA est à OxFF (par les interrupteurs extérieurs), tout interrupteur mis à 0 éteindra correctement la LED correspondante (reliée à TRISA). Mais l'inverse ne marche plus : si ce même interrupteur est remis à 1 on n'allume plus la LED correspondante.
Les deux PORTs TRIS (physiquement porta_dir et portb_dir) du cœur CQPIC ne peuvent en aucun cas être utilisés comme PORTs supplémentaires de sortie. Ils sortent physiquement du cœur mais ne peuvent être utilisés sans précautions.
Après plusieurs années d'expérience avec les processeurs embarqués depuis que ce chapitre a été écrit, nous décidons de compléter cette conclusion. Nous ne comprenons absolument pas ce qui pousse les auteurs de cœurs récents à recopier la bidirectionnalité des PORTs (CQPIC n’est pas récent 1999-2002). Un FPGA comporte aujourd’hui bien plus de broches qu'un micro-contrôleur vendu dans le commerce. Ainsi tous les cœurs récents ne devraient pas utiliser la haute impédance en séparant les entrées et sorties. TRISA, TRISB et TRISC deviendraient alors tout naturellement des registres (ou des PORTs) !
Comment contourner cet obstacle ?

### Ajouter un PORTC dans le CQPIC

(Le cœur correspondant se trouve dans le répertoire "\CQPICStart\PORTC" du fichier CQPICStart.zip).
Après avoir passé plusieurs heures à étendre à 8 bits le PORTA (au lieu des 5 initiaux), nous avons repéré à peu près tous les endroits à modifier pour ajouter un PORTC au CQPIC. Le jeu en vaut-il la chandelle ? Cela ne peut pas suffire à résoudre nos problèmes, puisqu'on aura alors en sortie que trois PORTs sur les huit qu’il nous faut. Nous avons finalement réalisé ce changement dans le cœur et en avons profité pour ajouter un signal "strobe" qui accompagne ce port supplémentaire (voir section suivante). C'est ce signal strobe qui va nous permettre de résoudre notre problème d'extension du nombre de PORTs assez facilement.
Notez que cette solution impose de déclarer PORTC et TRISC dans les programmes C. Je déconseille une modification du fichier pic1684.h Faites plutôt comme ceci :
C'est simple, mais cela ne permet pas un accès à des bits individuels (mais nous n'avons pas besoin de cela dans notre projet).
Approfondissons cette solution.

### Ajouter un "strobe" au PORTC et augmenter le nombre de ports

Un signal "strobe" est une sortie qui indique une écriture dans le PORTC. Ajouter ce signal strobe a été en fait le plus délicat du travail. L'intérêt d'un tel signal est de permettre facilement la démultiplication des PORTs (jusqu'à 256). Nous présentons ci-dessous un exemple qui montre comment étendre à huit le nombre de PORTs. On met la valeur du port véritable de destination dans PORTA puis on met dans PORTC la valeur à écrire : le "strobe" lui sera alors envoyé et il recopiera ce qu’il y a dans PORTC.
Il est peut être plus facile de raisonner à partir de ce schéma. Le PORTC (a gauche) est relié à tous les ports ajoutés (à droite) et la logique de décodage envoie le strobe dans le port qui doit recopier ce qu’il y a dans PORTC.
Le fait que le cœur original ne gère pas de signal "strobe" est un grand handicap si l’on veut ajouter de la logique externe. C'est une des raisons qui nous ont fait nous décider à ajouter un PORTC et son strobe associé. Nous ne pensons pas que ce travail puisse être réalisé par un étudiant du niveau 14.
Le programme VHDL correspondant au schéma de la page précédente est présenté maintenant. Il comporte deux entrées PORTA et PORTC pour réaliser quatre ports de sorties pA, pB, pC, pD.
Remarquez qu'on a utilisé des "process" au lieu de "components" pour simplifier le programme.

#### Exercice

Le programme VHDL ci-dessus permet de gérer 4 ports à partir de deux initiaux : le PORTA et le PORTC. Modifier ce programme VHDL pour qu’il gère les 6 ports en sortie conformément à la figure ci-dessus.
Arrivé à ce point, il nous faut certainement donner une image simple de ce que l’on cherche à faire.
La gestion de l'écran VGA peut se présenter comme une boite, certes complexe, mais qui sait dessiner :
* une balle
* deux raquettes
La seule chose qui sera demandé au processeur sera de gérer toutes les coordonnées de ces éléments.
Nous allons traiter ce problème en commençant à gérer la balle seulement puis en ajoutant les raquettes.

## Programmation du nouveau cœur avec écran VGA

(L'ensemble se trouve dans le répertoire "\CQPICStart\VGA_Pong" du fichier CQPICStart.zip). Nous avons déjà présenté quelques programmes en C, mais nous allons examiner ce qu’il faut changer dans ces programmes pour gérer les nouveaux PORTs.

### Programmation en C

Nous commençons par présenter un sous-programme qui écrit une valeur 16 bits dans deux des nouveaux PORTs.

### Le sous-programme "setX"

Une version en C pur est montrée ci-dessous :
Le contenu de ce programme est complètement déterminé par la partie matérielle.

### Déplacement horizontal en continu de notre balle/rectangle

Nous allons présenter maintenant un programme fonctionnel qui déplace sans arrêt le rectangle sur une horizontale.
Remarquez l’utilisation du timer0 sans interruption pour faire la temporisation.

### Programme complet de gestion simple de la balle

Nous présentons maintenant un programme simple de gestion de la balle avec des rebonds :
L'inconvénient de ce programme est le petit nombre des trajectoires gérées, ce qui peut devenir lassant pour un jeu.

### Ajouter les bords, et les raquettes

Comme nous voulons deux raquettes, il nous faut deux coordonnées verticales sur 9 bits (soit 4 ports 8 bits). Nous voulons aussi deux coordonnées de balles soit encore 4 ports de 8 bits. Cela fait en tout 8 ports. Nous avons déjà eu l’occasion de montrer comment on pouvait augmenter le nombre de PORTs.

#### Solution simple sans bord

Nous avons l'intention dans cette section de mettre en œuvre le programme VHDL de la section Ajouter un "strobe" au PORTC et augmenter le nombre de ports. Puisque ce programme VHDL ne proposait que quatre PORTs de sortie nous allons présenter un ensemble fonctionnant mais avec des positions de raquette fixes. Si l’on numérote les quatre ports de sortie de 0 à 3 on choisit

##### choix technologiques

    E/S module VGAE/S CQPIC x_rect<9:8>PORT1<1:0> x_rect<7:0>PORT0<7:0> y_rect<9:8>PORT3<1:0> y_rect<7:0>PORT2<7:0>
Pour pouvoir gérer des rectangles de tailles différentes et de couleur différentes, on complique un peu la partie destinée à dessiner un rectangle en lui donnant une couleur de rectangle une largeur et une hauteur. Voici donc notre nouveau composant :
L'intanciation des rectangles pour la balle et les raquettes se fera alors de la manière suivante :
Les déclarations des signaux dans ce morceau de programme sont omises. Voici maintenant le programme C permettant le rebond sur les raquettes. Vous pouvez remarquer que les coordonnées des raquettes sont calculées en fonction des interrupteurs sur le PORTB, mais ne sont pas mises à jour dans le matériel puisque le matériel ne peut pas le faire.
Comme on peut le voir nous avons choisi le PORTB connecté aux interrupteurs sw0,sw1,sw6 et sw7 de la carte, pour faire descendre et monter les raquettes et sw2 (RB2) pour le départ.

## Travail à réaliser
### Analyse

Comprendre la partie matérielle. Vous devez être capable de dessiner les composants et leurs liaisons à partir des fichiers VHDL donnés dans le répertoire "\CQPICStart\VGA_Pong" du fichier CQPICStart.zip.

### Synthèse

Étendre la partie matérielle pour gérer le déplacement des deux raquettes. On choisira une coordonnée Y de chacune des raquettes, au choix, sur 8 bits (comme dans le projet silicore1657 de l'année dernière) ou sur 9/10 bits. Pour un choix sur 8 bits on pourra prendre :

#### choix technologiques

    E/S module VGAE/S CQPIC x_rect<9:8>PORT1<1:0> x_rect<7:0>PORT0<7:0> y_rect<9:8>PORT3<1:0> y_rect<7:0>PORT2<7:0> y_raqG<7:0>PORT4<7:0> y_raqD<7:0>PORT5<7:0>
Le contenu de la gestion des ports est donné dans l'exercice plus haut. Voici le complément :

### Programmation

Explorer s'il n’est pas possible d’utiliser l'algorithme de tracé de segment de droite Bresenham pour les trajectoires de balles. Cet algorithme est expliqué dans le WIKI : Algorithme de tracé de segment de Bresenham. Il est possible de trouver directement une version en C : tapez Bresenham en C dans google.
Premièrement : modifier le programme pour utiliser setXY au lieu et place de setX et setY :
Pour l’algorithme de tracé de segment de Bresenham, le programme le plus compact trouvé sur internet est :
La première chose que fait l'algorithme est de calculer dx et dy. En ce qui nous concerne, nous ne ferons pas ce calcul puisque nous gérerons directement ce dx et ce dy. Entre parenthèse, cela nous évite de calculer des points d'intersections de notre trajectoire avec les bords de l'écran.
En remarquant que x0 est notre posX, y0 est notre posY, sx est notre deltaX et donc sy notre delatY, il vient :
Il ne reste plus qu’à faire varier deltaY entre 15 et 5 par exemple à l'aide des rebonds sur les raquettes.
Certains se demandent peut-être ce qu’il y a de Bresenham là-dedans. Je vous rappelle que l'algorithme original permet de calculer les points d'une droite sans multiplication et sans division, c’est ce que l’on fait ici. Ce qui caractérise cet algorithme c’est que la pente de la droite tracée est dy/dx, c'est-à-dire un nombre rationnel, c’est ce que l’on a encore une fois. Changez la ligne
en
ou encore en
pour voir les différentes pentes du déplacement de la balle.
Ne pas oublier que dès que dy ou dx varie il faut mettre à jour la variable err pour bien faire ! Seule cette opération nécessite une division par 2.
Voici un exemple qui change la pente de la balle en fonction du mouvement de la raquette au moment du rebond. Pour bien faire, il faudrait que si le déplacement de la raquette et de la balle sont dans le même sens la pente augmente, s'ils sont dans la direction opposée la pente diminue et si les raquettes sont immobiles la pente reste constante. Cela revient à gérer les rebonds sur les raquettes, par exemple, de la manière suivante :
* dx est fixé à 10 et ne change jamais
* si les raquettes sont immobiles au moment du rebond dy ne change pas
* si le déplacement de la balle (suivant y) et de la raquette ont même signe on augmente dy en ne dépassant jamais 15
* si le déplacement de la raquette et de la balle (suivant y) sont en sens contraires on diminue dy en ne dépassant jamais 5
Pour information l’ensemble des resources mémoire de ce programme est donné maintenant :
Ce qui montre qu’il ne nous reste plus grand chose au niveau de la mémoire de code !!! Bon une bonne nouvelle quand même :
* Dans l'environnement MPLAB, aller dans : Project → Build Options → project →onglet "global" et remplir "ROM" avec : default,+400-7FF.
Ceci double la ROM disponible dans notre cœur... et toute cette mémoire est disponible sans problème dans notre FPGA.

### Synthèse matérielle et programmation

Gérer un affichage des scores dans la partie basse de l'écran, soit avec une mémoire de caractères, soit avec des afficheurs sept segments à construire.
Voila ce que cela donne avec un affichage sept segments simulé.

## Annexe 1

Le programme C++ pour transformer le fichier HEX en fichier VHDL n’est pas donné car un petit peu trop long. Il se trouve dans le répertoire "\CQPICStart\ROM" du fichier CQPICStart.zip
* Ce n’est pas le fichier original hex2vhd.c proposé avec le cœur CQPIC qui est utilisé. C'est le fichier hex2rom.cpp présent dans un cœur concurrent, à savoir le cœur PPX. Ce fichier a été légèrement modifié pour que le programme généré puisse aller directement dans notre projet VHDL.
Un fois compilé mon utilitaire s’appelle hex2rom.exe (sous windows) ou hex2rom sous Linux. L'utilisation est faite par la ligne de commande :
si le fichier à convertir s’appelle demo16F84.hex.
Le fichier généré s’appelle progrom.vhd et a "progrom" comme nom d'entité. 13 est le nombre de bit d'adresses, l désigne le fait que l’on utilise la convention little indian (b désignerait big indian) et 14 est le nombre de bits de données dans la ROM.
Si l’on utilise le fichier VHDL directement sans modifier les options de synthèse, nous nous trouvons avec de la ROM distribuée. C'est à vous de décider si c’est grave ou pas.
L'ensemble des blocs utilisés se trouve en blanc et cet exemple montre bien pourquoi on appelle cela de la RAM distribuée (points blancs répartis dans le FPGA). Les blocs RAM (rectangles rouges) sont donc inutilisés (en fait ils sont partiellement utilisés par la RAM du 16F84). Vous pourrez noter que cette façon de faire est très consommatrice de ressources.
La différence entre RAM distribuée et bloc RAM (BRAM) est expliquée dans un autre projet.
Un essai avec une ROM minimale me montre une synthèse qui prend seulement 5% du Spartan3 200 contre 80% avec un programme conséquent. Ces chiffres nous ont conduit à considérer sérieusement la possibilité d’utiliser des BRAM dans ce projet. Ce travail bien fait pourrait nous autoriser à utiliser data2mem comme expliqué dans un autre chapitre donc gagner énormément en taille et en souplesse. Consulter la section Utiliser data2mem avec CQPIC pour voir l'état d'avancement de ce futur travail.

## Annexe II : le fichier ucf

Le fichier ucf dépend à la fois du FPGA utilisé et de la carte de développement.
Ce fichier ucf fonctionne correctement avec la version 9.2 de l'IDE mais la version 11.1 nécessite le rajout de :
en tout début de fichier.