Projet système FPGA : 2010 - Ugo Martin, Louis Rannou et Pierre Schamberger

De Ensiwiki
Aller à : navigation, rechercher


Le projet système sur FPGA est le projet de spécialité que nous avons choisi pour clore notre deuxième année d'études à l'Ensimag. Cette page contient le travail effectué lors de ces 4 semaines par notre équipe, ainsi que les points et les difficultés rencontrées qui nous ont semblé importants.

Présentation

Ce projet a pour but la réalisation d'un noyau de système d'exploitation, non pas sur un ordinateur classique, mais sur un FPGA : une petite carte qui contient entre autres un processeur, de la mémoire, et de quoi communiquer avec le monde extérieur. Il faut distinguer dans ce projet deux parties, que l'on développe en parallèle : une partie matérielle où la carte et ses périphériques doivent être configurés, et une partie système qui consiste à implémenter le noyau du système.

L'implémentation du noyau est très balisée : des spécifications complètes sont fournies, ainsi qu'un plan de route qui divise le travail en sept phases. En revanche, tout le développement matériel, qui relève plutôt des extensions à apporter au projet, est laissé très libre.

La durée accordée à ce projet est de quatre semaines, du jeudi 20 mai au mardi 15 juin 2010. Il s'est entièrement déroulé sur les machines ensipsys de l'Ensimag.

Au terme de ce projet, nous sommes parvenus à l'obtention d'un noyau minimal fonctionnel qui implémente l'ensemble du cahier des charges ; et du côté matériel, l'on dispose d'un écran et d'un clavier reliés à la carte, qui peuvent dialoguer avec elle.

L'équipe

Le groupe avait pour tuteur Sébastien Viardot et était composé des 3 personnes suivantes, toutes dans la filière SLE, en provenance de Phelma :

  • Ugo Martin
  • Louis Rannou
  • Pierre Schamberger

Ce groupe s'est formé dès le départ sur une volonté de mélanger une partie logicielle (conception d'un système d'exploitation) avec une partie matérielle (FPGA, conception de blocs en vhdl, ...). Le but fixé au début du projet était de faire un système d'exploitation correct, avec un affichage graphique VGA et une gestion du clavier par le port PS/2. Nous nous sommes répartis le travail comme suit :

  • Louis et Ugo pour la partie système, avec une préférence pour la communication bas niveau pour Ugo
  • Pierre sur la partie matérielle

L'environnement

Le site de Sébastien Viardot donne bon nombre d'informations nécessaires pour commencer le projet (voir les pages Projet Système FPGA et Projet d'architecture) :

http://sebastien-viardot.imag.fr

Ce site a a été notre point de départ pour prendre en main l'environnement de travail qui allait nous entourer pendant tout ce mois de juin. Ce n'était pas un environnement habituel pour nous : nous ne connaissions pas ou peu les logiciels à utiliser, et nous n'avions pratiquement pas eu d'occasion de travailler sur un support physique autre qu'un ordinateur pour nos programmes jusqu'à présent. Cette section présente donc les principaux éléments avec lesquels nous avons travaillé.

La carte FPGA

La carte est le support physique qui accueille notre système d'exploitation. En voici ci-contre une photo. On peut y voir de nombreux éléments, parmi lesquels :

Carte du projet système FPGA
  • Le FPGA en lui-même : le carré noir à droite du logo Spartan 3. C'est le composant principal. En simplifiant, un FPGA est un ensemble de transistors, malléable à volonté, qui peut donc prendre la forme de n'importe quel circuit logique -- dans la limite des ressources disponibles.
  • Le port série : il est relié au câble gris en bas à gauche. Il sert à communiquer avec l'extérieur, l'extérieur se limitant dans notre cas à un ordinateur, qui sert à afficher le texte que la carte envoie.
  • Le port VGA : le port en haut à gauche, qui semble identique au port série de ce point de vue, mais ne l'est pas. Les informations qui passent par ce port servent à l'affichage graphique.
  • Le câble programmateur : le câble beige. Pas vraiment membre de la carte à part entière, il est néanmoins indispensable pour transférer toutes les informations qui servent à configurer le FPGA : c'est par lui que la carte saura que tel transistor devra être relié à tel autre, par exemple.

Certains de ces éléments sont décrits plus en détail dans la partie matérielle.

MicroBlaze

Le MicroBlaze est le processeur pour lequel nous avons écrit notre noyau de système d'exploitation. C'est donc le circuit chargé d'exécuter, instruction par instruction, le code qui se trouve dans la mémoire. On peut remarquer que ce composant capital n'a pas été mentionné dans les éléments constitutifs de la carte. C'est parce que le processeur se trouvera à l'intérieur du FPGA : après tout, c'est un circuit logique comme un autre du point de vue des transistors.

Ce processeur, conçu par Xilinx, met à disposition du programmeur (nous) tout un ensemble d'éléments matériels et logiciels. La documentation complète (environ 140 pages) peut être consultée ici : Fichier:Microblaze.pdf. À l'intention de lecteurs familiers de l'architecture Intel, on peut noter quelques points particuliers :

  • L'architecture de ce processeur est de type RISC, c'est-à-dire que son jeu d'instruction est plutôt réduit, par opposition aux CISC, dont le jeu est plus fourni.
  • Le processeur contient 32 registres généraux, ainsi que quelques registres particuliers supplémentaires, notamment le registre d'état et le compteur ordinal.
  • Parmi les registres généraux, certains se voient attribuer un rôle précis : par exemple R1 sert de pointeur de pile, R3 de valeur de retour des fonctions, etc. Ces conventions sont respectées par le compilateur C lorsqu'il génère de l'assembleur pour le MircoBlaze, et il faut également les respecter lorsqu'on écrit du code directement en assembleur.

Xilinx

Xilinx est le logiciel qui sert à agencer tous les composants matériels que l'on veut disposer sur la carte. Une fois que la disposition est faite, Xilinx génère une plate-forme virtuelle : c'est un simulateur de la carte physique. On peut alors prendre chacun un exemplaire du simulateur, et exécuter nos tests dessus, plutôt que de tout faire sur la carte physique.

mb-gdb

mb-gdb est le débogueur que nous avons utilisé tout au long de ce projet. C'est l'équivalent de #ddd, mais adapté au MicroBlaze. Il permet d'observer ce qu'il se passe lors du déroulement d'un programme : exécution pas à pas, points d'arrêt, état des registres, de la mémoire, etc.

Ce programme est indispensable pour arriver à trouver d'où viennent les erreurs dans le code que l'on écrit. Malheureusement, il est très lent — il faut parfois attendre une trentaine de secondes pour avancer d'une instruction — et plante assez souvent. En général, un redémarrage du logiciel règle le problème, mais lorsque le plantage survient près du but, il est difficile de ne pas être frustré ! Il y a néanmoins un avantage notable à cette lenteur : elle apprend à réfléchir avant de lancer le test à « pour voir ».

Conception matérielle

Comme dit précédemment, la partie matérielle comporte deux gros blocs: l'affichage sur un écran (mode pixel par pixel) et la gestion d'un clavier PS/2. Mais il fallait aussi gérer l'architecture globale du projet, qui comprenait plusieurs éléments indispensables :

Conception du circuit de base

Dans cette première partie, nous avons créé un projet minimal avec le logiciel Xilinx Plateform Studio (XPS), avec les éléments de base pour le circuit, à savoir :

System.jpg
  • Le processeur MicroBlaze : c'est lui qui va exécuter toutes les instructions assembleur du code de l'OS
  • La BRAM qui lui est associée : Cet espace mémoire est une sorte de cache rapproché du processeur, relié à ce dernier par un bus dédié, et qui permet de ne pas toujours aller chercher les informations dans la RAM. C'est dans cet espace que sera stocké le <lien vers plus tard>boot loader</lien> qui permettra de lancer notre OS de façon autonome.
  • Un bus OPB (IBM) : OnChip Peripheral BusC'est le nerf de l'architecture. C'est sur ce bus que vont transiter toutes les infos vers ou depuis la RAM, le processeur, le contrôleur d'interruptions, et les futures extensions. C'est lui qui définit l'horloge du système (OPB_Clk) fixée à une période de 20ns. Ce bus est de conception IBM, mais simplifié dans son implémentation par Xilinx.
  • Une RAM rattachée au Bus OPB : C'est dans cet espace qu'est stocké la majorité des données, tant pour l'écran que le code source.
  • Un arbitre de bus : Rattaché au bus OPB, c'est lui qui décide, par décision statique ou dynamique, quel périphérique maître du bus va avoir l'accès à chaque instant.
  • Un contrôleur d'interruption : Chaque périphérique fonctionnant par interruption matérielle est relié à ce contrôleur, et c'est lui qui avertit le processeur qu'une interruption (IT) matérielle est survenue. C'est au processeur d'aller chercher la source auprès du contrôleur, pour effectuer le traitant correspondant. Durant le traitant d'IT, le processeur masque automatiquement les autres IT pouvant survenir, et c'est au contrôleur de les mémoriser.

Le schéma ci-contre montre l'architecture globale du projet.

Chargement sur la carte

Ce matériel nous a permis de faire un premier test du noyau fourni. Il y a deux possibilités de faire les tests, en simulation grâce à XPS et sa plateforme virtuelle, ou bien directement sur la carte, avec utilisation du débogueur pour charger le noyau et visualiser ce qui se passe, puisqu'aucune sortie n'est encore définie. Les parties suivantes nous permettront de sortir des données, pour un débogage plus aisé. Le chargement se fait en plusieurs temps :

  • Il faut d'abord que XPS compile le projet matériel en lui même, pour en faire un fichier *.bit.
  • Ce fichier est ensuite transféré sur la carte via un câble JTAG
  • Il faut ensuite compiler le noyau (logiciel) grâce au Makefile fourni, qui génère le fichier binaire.
  • La dernière étape consiste alors à lancer le débogueur et à charger le fichier binaire obtenu en RAM.

Le programme peut alors commencer à s'exécuter. Les étapes de compilation matérielle et de transfert vers la carte sont assez lourdes. Ces temps vont conduire à un débogage assez lent. Pour le rendu final, un petit programme de chargement (le BootLoader) a été crée. Il est à mettre dans la BRAM, et il récupère par le port RS232 le vrai programme qu'il stocke en RAM, avant de commencer à l'exécuter.

Les sources : Source

Dans la suite, les différents bloc utilisés sont détaillés :

Sortie RS232

L' UART (Universal Asynchronous Receiver Transmitter) permet de communiquer entre la carte et l'ordinateur via le port RS232. Le bloc préfabriqué UART existant déjà dans Xilinx, nous n'avons eu qu'à le rajouter au schéma global, et à le connecter directement sur l'OPB (dans un premier temps juste dans le sens TX, pour émettre). Du coté logiciel, il a fallu écrire un driver pour que le printf envoie bien sur l'UART. L'UART est défini par une adresse sur l'OPB (0x40600000 dans notre cas). On regarde d'abord si la file d'attente d'envoi est vide (attente active), puis on y écrit la donnée une fois qu'elle l'est ( adresse d'écriture 0x40600000 + 4). Ci dessous, le code pour l'envoi d'un caractère :

#define UART_BASE_ADDRESS 0x40600000

void tty_send(char c) {
        /* controle si la FIFO TX est vide ! */
        while(!(*((int*)(UART_BASE_ADDRESS+8)) & (4)));
        /* c'est OK */
        *(int*)(UART_BASE_ADDRESS + 4) = c;
}

De l'autre coté du câble (ordinateur), nous utilisions la commande cu pour récuperer ce qui transite par le câble RS232 :

cu --line=/dev/ttyS0 --nostop --speed=115200 --parity=none

Lors des tests avec la platforme virtuelle, un outil similaire est utilisé : vpio

Ainsi, tout ce qui passe sur le câble est inscrit dans la console, ce qui est particulièrement utile pour le debug, tant sur la platforme virtuelle (pour la partie conception système essentielement) que sur la carte.

Sortie écran

Image extraite du test 'balle rebondissante'

Le but de cette partie est d'obtenir un affichage couleur pour notre système. Les tests utilisés tout au long de cette partie sont les suivants :

  • La balle : un balle avance dans sur l'écran et rebondit contre les bords.
  • Le jeu de la vie : vie de cellules. Donne des images assez différentes, et utilise beaucoup le bus.

Les sources : sources C

Description

Image extraite du test 'jeu de la vie'

De manière à obtenir un système complet, nous avons donc décidé d'implémenter un affichage sur écran VGA 640x 480 pixels. Le protocole de communication sur ce port est un peu particulier et comporte 5 signaux principaux :

  • HSync : synchronisation horizontale
  • VSync : synchronisation verticale
  • R : valeur de rouge du pixel concerné
  • G : valeur de vert du pixel concerné
  • B : valeur de bleu du pixel concerné

Bien que l'écran ne fasse que 480 lignes de 640 pixels, il y a des pixels 'invisibles' avant pour la synchronisation. Ces signaux de synchronisations permettent de définir sur quel pixel seront affectées les valeurs de R, G, B. En théorie, il est possible, via un CNA, de faire varier la tension sur chacun des 3 pins de couleurs pour arriver au nombre de couleurs des écrans classiques, mais nous nous contenterons d'y affecter 0 ou 1, soit 8 couleurs au maximum.

Réflexion générale

2 possibilités pour stocker les données :

  • Aller les chercher en RAM, là ou le processeur les mets dès qu'il y a du changement. Cela implique beaucoup de mouvement sur le bus, et donc des latences possibles, et donc des erreurs de synchronisation
  • Faire une mémoire dédiée en vhdl avec 2 accès In et Out dans le bloc VGA en lui même. Beaucoup plus rapide et pratique, utilisé aujourd'hui sous le nom mémoire vidéo. Cependant, les performances en mémoire du FPGA sont très faibles ( 900K hors RAM). Solution donc inexploitable.

En utilisant la RAM, il va donc y avoir 2 maîtres sur le bus (Microblaze et VGA), il faut donc munir ce dernier d'un arbitre, pour décider qui du processeur et du VGA à l'accès à un instant donné. Dans la suite, nous présentons les différentes solutions réalisées. Les tests ont été menés grâce aux logiciels libres ghdl et gtkwave, ainsi que le logiciel Xilinx ISE pour la synthèse et les tests sur carte Une fois le vhdl fonctionnel, il faut l'intégrer au projet Xilinx, en créant un nouveau bloc rataché au bus OPB, et y ajouter les pin de sorties ou d'entrées du FPGA (fichier *.ucf).

Solutions

2 couleurs
Premier essai en 2 couleurs (vert et noir). Le TestBench et une partie du module proviennent du site de Sébastien Viardot. Chaque pixel correspond à 1 bit en RAM, à partir de 0x201F0000 (fin de la RAM).
Les sources (Makefile, Test Bench, Module, config gtkwave) : Sources
8 couleurs (simple)
Ce mode est juste une extension rapide du mode 2 couleurs. Nous avons réquisitionné la fin de la RAM, répartie en 3 blocs (un par couleur).
La machine à état est juste modifiée pour boucler 3 fois avant de re-tomber en IDLE pour récupérer les 3 bits du pixels.
Lors des tests, on obtient dans certains cas un écho dans l'image, comme si le bloc VGA n'avait pas le temps de chercher la nouvelle valeur des 32 pixels suivants, et recopiait donc les 32 derniers enregistrés.
Les sources (Makefile, TestBench, Module, config gtkwave) : Sources
Le mode 8 couleurs avec mémoire interne
L'idée de ce module est de corriger le bug précédent, en cherchant à acquérir toute les données de la ligne en cours (640*3 = 1920 bits) de la RAM avant le début de la ligne, durant les premiers "pixels invisibles" de synchronisation.
il faut stocker le tout dans les BRAM incluses dans le FPGA.
Durant ce projet, nous n'avons pas pu l'implanter sur la carte, néanmoins le module fonctionne sous ISE
Les sources (Makefile, TestBench, Module) Sources

Driver

Il faut encore créer le driver, pour pouvoir utiliser l'écran dans les programmes utilisateurs. Il faut écrire les bonnes valeurs aux bonnes adresses de la RAM.

Deux fonctions essentielles le composent :

  • aff_init qui initialise l'écran à une certaine couleur (arrière-plan)
  • aff_pixel qui met un pixel donné à une certaine couleur.

Le driver (ecran.c) Source

Gestion du clavier

Deuxième extension, le clavier. Nous allons implémenter seulement certaines touches. La démarche est la suivante :

  • compréhension du protocol PS/2
  • implémentation vhdl
  • tests avec ghdl et Gtkwave
  • synthèse sous Xilinx ISE
  • Tests du module seul sur la carte avec Xilinx Impact

L'idée est la suivante : lorsqu'une touche est appuyée ou relâchée, le module envoie une interruption au contrôleur d'IT, et met la valeur dans un registre, en attendant qu'elle soit lue par le processeur.

Protocole PS/2

Le site computer-engineering.org nous a été grandement utile pour la compréhension du protocole PS/2, le schéma suivant montre le protocole basique "device to host".

Clavier.jpg

Il est aussi possible d'envoyer des signaux vers le clavier (diodes CAPS LOCK, NUM LOC, paramètres divers), ce qui complique un peu le protocole.Dans le cadre de ce projet, nous nous limiterons à la réception des données du clavier.

Bloc vhdl

Le bloc construit à du coup deux interfaces :

  • une interface esclave avec interruption du coté du bus OPB
  • une interface avec les signaux du clavier (PS2_Clk, PS2_Data)

Pour la conception de ce bloc, nous nous sommes inspiré du travail du site http://www.xess.com. Nous avons en effet utilisé leur Testbench pour tester notre bloc VHDL. Nous avons tout d'abord validé un modèle simple du module, seul sur la carte et sans l'interface OPB, directement synthétisé par ISE et mis sur la carte avec Impact, puis ajouté l'interface pour le rajouter au système complet. Nous avons au passage rajouté des blocs de stabilisation des données entrantes par les pins PS/2, car le signal physique pouvait précipiter potentiellement la FSM sur son compte d'horloge.

Les sources : Sources vhdl

Driver

Comme pour l'écran, il faut pouvoir communiquer avec le matériel depuis le système. Deux fonctions ont été implémentées :

  • PS2_Traduction() : transforme un scancode de clavier en ASCII ou suite d'ASCII.
  • PS2_get() : c'est le traitant d'interruption appelé à chaque fois. Il appelle PS2_Traduction pour récupérer un ASCII, puis fait un appel à keyboard_data, qui le stocke dans une FIFO, et l'affiche éventuellement.

Les sources : Driver clavier

Problèmes rencontrés

Si vous souhaitez vous lancer dans un projet similaire, soyez avertis des points suivants :

  • Bugs réguliers de ISE et Impact (Crash sans préavis)
  • ChipScope est l'unique moyen de voir ce qu'il se passe sur le bus. Chez nous, il ne fonctionnait pas, le débogage est plus complexe dans ce cas.
  • le passage de ISE à EDK avec des blocs pré-construits (IP) n'est pas direct
  • La documentation Xilinx (bus, contrôleur, UART, ...) demande beaucoup de temps et d'attention
  • Chaque débogage sur carte demande un très long chargement. Il faut bien réfléchir avant de lancer le chargement.

Conception du noyau

Comme précisé en introduction, la totalité des spécifications que le noyau devait supporter nous a été fournie au début du projet. Cette partie de conception du noyau a donc principalement consisté en la recherche de solutions pour implémenter les fonctionnalités requises.

L'utilisation d'un outil de simulation plutôt qu'un travail sur le matériel ralentit considérablement l'avancée. Afin de minimiser le temps passé à corriger les codes, une lecture attentionnée de la documentation et des spécifications du cahier des charges est importante. Nous décrirons donc le travail effectué en suivant l'ordre chronologique du cahier des charges.

Changement de contexte et ordonnancement

La carte ne comporte qu'un seul processeur ; cela signifie qu'on ne peut exécuter qu'un seul processus (qu'un seul programme, qu'une seule application) à la fois. Pour donner l'impression que plusieurs tâches s'exécutent en même temps, il faut un mécanisme capable de faire alterner leur exécution : on parle d' ordonnancement des processus.

Le passage d'un processus à un autre est appelé changement de contexte. Lorsque le système décide d'interrompre le processus en cours d'exécution pour aller donner la main à un autre, il sauvegarde le contexte du processus qu'il coupe, et restaure le contexte de celui qu'il relance.

L'ordonnancement se fait selon plusieurs règles. La principale concerne la priorité : chaque processus est déclaré plus ou moins important aux yeux du système d'exploitation. Plus sa priorité est élevée, plus il est important, et plus il sera favorisé par le système : il s'exécutera plus souvent que les autres. Pour plus de détails, voir les spécifications : Projet_système_:_spécification#Ordonnancement_-_Scheduling.

Gestion de processus

Nous pouvons maintenant nous intéresser à la filiation et à la gestion des processus. Si un processus A crée un processus B, A est appelé le père de B -- et B le fils de A. La création d'un processus demande une réservation de mémoire : c'est la pile. Dans cette pile seront stockées toutes les variables locales au processus.

L'implémentation de la terminaison d'un processus demande plus de réflexion. Un processus peut se conclure de deux façons : soit il se termine de lui-même (par un exit), soit il se fait « assassiner » par un autre. Un processus père pouvant attendre la fin de l'un de ses fils, un fils doit pouvoir communiquer avec son père, même après sa mort. Dans ce cas, on dit que le processus est un zombie.

La terminaison d'un processus doit provoquer la libération de la mémoire allouée (la pile). Dans le cas d'un processus qui se termine de lui même, il faut faire attention à la supprimer après que le système a procédé au changement de contexte.

Cela fait, un processus doit pouvoir se terminer normalement, où en envoyant une valeur de retour (instruction return). Pour gérer cela, on peut par exemple créer les processus au travers d'une fonction qui exécute la commande désirée, puis qui récupère son éventuelle valeur de retour, et se termine par un appel à exit.

Gestion du temps et interruptions

Les processus doivent se partager le processeur. Pour que le partage soit équitable, le système a besoin d'avoir une idée du temps qui s'écoule, pour interrompre un processus qui aurait terminé son quota d'exécution. Il existe pour cela un composant sur la carte, le timer, qui interpelle régulièrement le processeur. Ce mécanisme s'appelle une interruption. Dès qu'elle survient, le processeur exécute une petite fonction, le traitant d'interruption, qui décidera ou non d'interrompre le processus courant.

À l'opposé, un processus peut décider de lui-même qu'il n'a plus rien à faire pour un moment, et dire au système qu'il souhaite s'endormir jusqu'à une date donnée. C'est alors au système de réveiller le processus au moment où il l'a demandé.

La mise en place des interruptions n'est pas très difficile, mais assez technique : cela nécessite d'étudier le fonctionnement du contrôleur d'interruptions, son initialisation.

Les files de messages

L'utilisation de files de messages permet de synchroniser des processus afin de travailler en programmation concurrente, tout en mettant en place un système de communication entre les processus.

De la même façon que dans la gestion des processus, la difficulté réside dans la communication des processus entre l'émission et la réception et provient essentiellement de la quantité de cas à disjoncter. Dès lors que la correction se montre longue, le risque est que les idées s'embrouillent, il sera alors sans doute judicieux de recommencer toute l'implémentation de l'émission et de la réception.

Les files de messages implémentées, l'utilisateur peut implémenter des sémaphores, qui permettent de résoudre le fameux problème des philosophes.

Du noyau à l'utilisateur

Pendant toutes les premières phases de développement du noyau, les processus que l'on exécutait se trouvaient dans le noyau lui-même. Pour être plus réaliste, on met en place une séparation entre le code du noyau et le code des applications. Cela soulève tout un ensemble de problèmes, décrits dans la phase 5 du plan de route.

Pour les résoudre, il a fallu étudier la façon de faire du compilateur : que fait-il lors d'un appel de fonction, lors d'un retour de fonction ? Comment la pile est-elle gérée ? En effet, pour appeler les fonctions du noyau depuis l'application utilisateur (on parle d' appel système), on doit passer par des appels écrits en assembleur. Pour que le mélange de code C et d'assembleur fusionne bien, il faut donc faire attention à respecter les conventions du compilateur.

Une fois ce système correctement mis en place, il est alors facile d'ajouter d'autres appels système ; quelques minutes suffisent.

La console

Entre matériel et système, la console est l'occasion de réunir nos deux parties. Elle permet de lier le clavier et l'écran à la gestion de processus.

Il faut d'abord transformer la suite de caractères tapés en une chaîne lisible par le système. Pour cela, nous possédons un tampon de taille définie. Chaque caractère tapé est enregistré dans le tampon jusqu'à ce que la touche entrée soit pressée. Alors un processus en attente d'entrée clavier sera libéré et lira la ligne dans le tampon.

Au moment de l'écriture dans le tampon, les caractères seront immédiatement affichés à l'écran : c'est l'écho. Il pourra être désactivé, selon le désir de l'utilisateur (par exemple, pour écrire un mot de passe). Tout autre effet du clavier sur l'écran sera implémenté de la même façon. Nous modifions de cette façon la trajectoire de notre balle en appuyant sur une touche.

Il reste à implémenter une compréhension des lignes, et une implémentation de toutes les commandes qu'un utilisateur peut désirer. Le système d'exploitation sera alors complet !

Articles connexes

Projet système FPGA : 2010 - Hugues Evrard et Gaëtan Harter

Documentation