Home Présentation Cours TD et TP Projet Anciens tests Annonces Liens utiles

Rustines

  1. Dans la ligne 154 de Proc_0_Program.asm, au lieu de l'instruction
  2.    SETRI R10 200
    
    il faut mettre
       SETRI R10 201
    
    autrement dit, le début de ce tableau doit être à 201.
  3. Dans Proc_1_Program.asm dans l'instruction de saut qui suit le second CLINT R4 -- celui pour le V() -- , il faut mettre -6 au lieu de -5, donc
    JZROI R6 -6       ; jump back to waitLoop ...
    
Je vous remercie d'avoir signalé ces problèmes. Si vous le souhaitez, vous pouvez retélécharger l'archive, qui a été ainsi corrigée.

Préambule

Le projet, disponible pour téléchargement en entier ici, et avec l'énoncé disponible également ici, comporte deux parties : une à effectuer individuellement et à rendre pour le 18 novembre 2012, 23h59 heure de Paris, et une autre, à faire en équipe, et à rendre pour le 23 décembre 2012, 23h59 heure de Paris.
La partie à faire en équipe est divisée en deux sous-parties -- la compréhension détaillée du code fourni, suivie d'un travail d'extension de code effectif. Lorsque vous commencez à travailler là-dessus, il est fortement conseillé de faire bien entendu d'abord la partie compréhension, qui est indispensable pour mener à bien le travail d'extension de code proprement dit.

Avant-projet

L'avant-projet est à faire individuellement, et un rapport est à rendre par courrier électronique, en format PDF (à l'exclusion de tout autre format, sous peine de non-considération du travail). Le texte de l'avant projet peut tenir sur environ quatre pages, par exemple avec une taille de police de caractères de 11pt (ou 12pt), et des marges raisonnables.

Projet

Pour le projet, vous allez donc travailler en équipes qui auront une personne désignée comme chef d'équipe -- elle sera censé coordonner le travail et s'assurer de la bonne marche.
Le rapport du projet doit également être rendu par courrier électronique, en format PDF (à l'exclusion de tout autre format, sous peine de non-considération du travail).
Je vous prie de bien vouloir nommer vos fichiers (que vous m'envoyez en pièce jointe par courrier électronique) seulement avec vos noms et prénoms tout en majuscule, avec le souligné (underscore) (et sans accents, cédille, etc.).
Dans le rapport il faut mettre

  . des explications pour le code initialement fourni, a savoir

      l'ordonnanceur
      le diagramme des etats (donc *initial*)
      les descriptions des transitions dans ce diagramme


  . des explications pour votre code (rajoute, modifie, etc.)

      le nouveau diagramme des etats
      les nouvelles descriptions des transitions dans ce diagramme
      comment vous avez implemente vos idees
      quels ont ete vos choix, pourquoi
      bien commenter votre code
      comment vous avez procede pour tester votre code

  . le cahier des charges individuel (donc pour chaque membre du groupe)

      le plan initial, avec les durees initialement prevues 
      ce que vous avez reellement reussi a faire, en combien de temps
      ce que vous n'avez pas pu faire, et pourquoi
      ce que vous avez rajoute par rapport au plan initial, pourquoi, combien de temps 

Vous devez vous constituer des équipes de cinq ou de quatre membres, choisissant une personne comme chef d'équipe dans les deux listes qui seront affichées ci-après. Une fois constituée, chaque équipe m'envoie un seul mail avec la composition, et après approbation, je l'annonce sur cette page.

Foire aux questions

  1. Regardez en haut de cette page pour la "rustine" -- il faut mettre 201 et non pas 200 à la ligne 154 de Proc_0_Program.asm (il s'agit bien de la numérotation explicite -- ";154") et également -6 (et non pas -5) pour le JZROI R6 de Proc_1_Program.asm .
  2. Pour la question 2.d de l'énoncé, la ligne 168 est-elle dans le fichier dirprojet/Proc_0_Program.asm ou bien dans le fichier dirprojet/ini/Proc_0_Program.asm et le numéro 168 est-il celui de la numérotation explicite dans dirprojet/Proc_0_Program.asm ou bien celui indiqué par un éditeur de texte?

  3. Le fichier est bien dirprojet/Proc_0_Program.asm et le numéro 168 est bien celui donné explicitement dedans (et non pas par un éditeur de texte) et donc la ligne en question est
       SETRI R20 0        ;168 the V() semop value (and V state value)
    
  4. Pour la question 3.c, est-ce ce schéma-ci :
  5. boucle
      P();
      on lit / écrit en mémoire partagée UN nombre;
      V();
      ++index sémaphore;
      ++adresses sémaphores;
    fin boucle; // pour chaque boucle on crée des nouveaux id de sémaphore
    
    ou plutôt celui-là
    boucle
     P();
     on lit / écrit en mémoire partagée UN nombre;
     V();
    fin boucle; // on garde toujours le même index et la même adresse pour les sémaphores
    
    ?
    Ni l'un ni l'autre de manière idéale. Le premier utilise "trop" de sémaphores -- on n'en pas un nombre "grand" dans les systèmes (et on ne peut pas garantir que le producteur passe en premier). Le second est assez proche, mais bon, sans plus de "choses", il n'est pas complet (même chose pour qui passe en premier) -- et le consommateur pourrait lire plusieurs fois le même nombre avant que le producteur puisse en "produire" un autre (en général tout processus peut être interrompu n'importe où lors de son exécution, et il peut reprendre arbitrairement "plus tard", donc un autre processus peut exécuter "beaucoup" de ses propres instructions pendant ce temps-là : ici on peut avoir le cas où le consommateur, après avoir lu et passé par son V(), garde la main et revient dans sa boucle en haut, arrivant donc à poser son P() tout de suite). On peut utiliser judicieusement deux sémaphores. Si cela ne vous semble pas suffisant, on peut également utiliser des valeurs en mémoire partagée (en tant que drapeaux -- flags en anglais). Dans les vrais systèmes Unix on dispose de plus d'outils pour contraindre un tel ensemble producteur-consommateur à commencer dans le bon état, tandis qu'ici on n'a pas un contrôle aussi fin.
  6. Pouvez vous m'expliquer quels sont les liaisons entre une variable de type Memory (comme mem[i], élément de la donnée-membre BaseCPU::mem) et le descripteur de fichier associé ?
  7. En regardant le code qui se trouve dans Board.h, Board.cxx, CPU.h et CPU.cxx (surtout la méthode Memory::setUp() et le constructeur CPU::CPU()), on s'aperçoit qu'on ouvre un seul fichier, dont le descripteur est passé à chaque appel de Memory::setUp() pour chaque "tranche" de mémoire (donc élément de MemoryTable, qui n'est qu'un vector de Memory). Par contre, on passe également une valeur de décalage, afin que chaque tranche soit logée dans le fichier à un endroit qui lui est propre. Donc le descripteur sert à faire effectivement les opérations avec la mémoire, comme on peut le voir en lisant le code des méthodes comme Memory::loadFrom() ou Memory::storeAt() (toujours dans Board.cxx). Enfin, pour aller jusqu'au bout, on peut trouver dans CPU.cxx un exemple d'utilisation de ces méthodes, dans l'implémentation des instructions comme LDMEM et STMEM.
  8. L'adresse 200 dans la mémoire du noyau est-elle correctement utilisé dans Proc_0_Program.asm pour un processus donné de pid N ?
    En effet, comme dit plus haut au sujet de "rustines", il faut mettre 201 et non pas 200 à la ligne 154 Proc_0_Program.asm, autrement il y a un décalage entre ce qui est initialisé et ce qui est utilisé.
  9. Pourrions-nous avoir plus de précisions pour la question 3.d ?
  10. Est-ce bien vrai que pour les instructions de saut comme JMTOI, JZROI, etc. il faut bien compter la ligne de l'instruction elle-même lors du calcul de la valeur du saut?
    Oui, tout à fait, et Proc_1_Program.asm doit être corrigé à cet effet, comme dit plus au sujet des "rustines".
  11. Pour la question 2.c, la structure de mémoire à détailler est-elle pour tous les processus en général ou également pour chaque processus (ses spécificités, stockées en mémoire) ?
    On ne demande que la structure en général, sans exemple particulier d'exécution. Bien entendu, le fait d'analyser le fil d'exécution des programmes fournis peut également vous être utile -- mais ceci n'est pas demandé dans le rapport.
  12. Pour la question 2.d, la question est-elle "à quoi sert la ligne 168 tout simplement?" ou bien "à quoi sert la ligne 168 par rapport au reste du code?" ?
    La question porte bien sur son rôle ensemble avec le reste du code.
  13. Toujours pour la question 2.d, je voudrais aussi savoir dans quel cas on exécute cette ligne 168, car elle se trouve à un endroit qui ne semble pas accessible, puisqu'elle se trouve après un "shutdown" et juste avant le début de semoptest.
    En général on peut arriver sur une ligne pour l'exécuter aussi en suivant un saut, donc cette analyse, qui est très bien partie, devrait simplement être achevée proprement. Il n'y a rien de contradictoire jusqu'ici.
  14. Pour la question 3a, a-t-on le droit de modifier les paramètres donnés à int5 ou bien devons-nous les recopier pour pouvoir les modifier?
    Les interruptions prennent en général comme paramètres deux types d'information : des valeurs de registres, et des valeurs en mémoire (dont on donne l'adresse dans des registres). Grâce au mécanisme de commutation de contexte, les valeurs des registres vues au moment du CLINT par le processus P qui fait appel à une interruption I seront bien restaurés lors du retour de I (code noyau) vers P (code utilisateur).
    Par contre, les valeurs qui se trouvent dans la mémoire vive du processus sont bien accessibles en lecture-écriture au noyau (qui exécute donc le code de I), et il n'y en a pas de sauvegarde/restauration "automatique". C'est donc au code de I de bien "prendre soin" de ces valeurs-là. Si le processus "s'attend" à ce que le contenu de certaines de ses zones mémoire soit modifié (et le "sait pourquoi"), tout va bien. Sinon, il ne faut pas "y toucher".
    Donc ceci est une affaire de convention, ou de protocole. Dans le cas d'une interruption censée obtenir des valeurs d'un processus (donc les lire) et faire quelque chose avec, mais sans les modifier, il faut donc bien respecter cela de cette manière-ci.
  15. Est-il grave si on finit par exécuter plus de 10000 instructions ? (Dans le code C++ il y a une telle limite dans BaseCPU::run()).
    Cette limite est entièrement arbitraire ; elle est mise là simplement pour aider surtout au déboguage (empêchant ainsi des boucles infinies).
  16. Qu'est-ce qu'un diagramme des états ? Que mettre dedans en général ?
    Un diagramme des états est une description des états (de quelque chose -- et ici, dans notre cas, des processus de notre système virtuel sur lequel on travaille dans ce projet), sous la forme de "bouboules" et de flêches entre elles -- donc un dessin. Dans les bouboules on met le nom de chaque état, et sur les flêches on écrit (succintement) dans quelle situation (dans quelles conditions, etc.) on passe d'un état à un autre. Un processus est en général dans un état d'attente (de plusieurs types) ou bien d'exécution, etc. C'est le noyau qui, en "étudiant" un processus donné, décide de le faire changer d'état. Ici on demande un tel diagramme qui décrit ce qui se passe donc dans notre système virtuel tel qu'il vous est initialement fourni, et aussi un diagramme qui décrit ce qui se passe dans le système tel qu'il a été modifié par vous dans le cadre du travail lié à ce projet.
  17. Pour la question 3.b, pouvons nous avoir de plus amples informations sur la notion "lire depuis le clavier" et sur la nature exacte du travail demandé?
    La notion "lire depuis le clavier" vous est bien connue : c'est par exemple faire en C++
      int a;
      cin >> a;
    
    (avec éventuellement du
      cout << "Entrez un nombre entier "
    
    avant le cin). Il s'agit donc ici de faire en sorte que la même opération soit bien possible. Vous disposez bien entendu d'une base de code déjà écrite, qui ne doit qu'être complétée. Nous devons donc comprendre à quel niveau la compléter.
    L'énoncé du projet vous dit que l'int6 est complémentaire à int5. Commençons par regarder brièvement ce que fait donc l'int5. Une fois qu'on se met à examiner le code fourni, on observe tout d'abord que l'int5 en effet ne semble faire rien d'autre qu'écrire dans la mémoire. Par contre, en regardant de plus près, on s'aperçoit qu'elle n'écrit pas n'importe où, mais dans un endroit "magique". L'écriture dans cet endroit déclenche l'exécution d'un bout de code C++ appartenant à la classe ConsoleInOut (dont le code se trouve dans Board.cxx). Dans CPU.cxx on voit comment se déroule la partie "magique" surtout dans l'implémentation de l'instruction STMEM -- le commentaire dans le code parlant de "memory-mapped I/O address and request". Ceci est l'élément clé nécessaire à la compréhension du travail à faire.
    Donc, en regardant davantage dans Board.cxx, on s'aperçoit qu'en fait une bonne partie du travail est déjà faite, puisque on trouve bien le code de la méthode input() de la classe ConsoleInOut, qui fait ainsi la liaison entre "les doigts de l'utilisateur sur le clavier" et le coeur du programme. Ce qui est à faire est donc, comme le précise l'énoncé, la partie int6 analogue à int5, qui utilise donc la "magie" déjà mise à votre disposition pour faire en sorte qu'un programme écrit dans notre mini-language assembleur de ce projet puisse lire depuis le clavier des valeurs (et faire quelque chose avec).