SOMMAIRE EDITO COURRIER L'EQUIPE ACTUALITE NEWS CONCOURS EXTERNAL ASM-INIT ASM-PRATIK INTERRUPTION HARD DUNE EDEN HPMARRIO INTERVIEW BOOK HP92
HPGrâal Numero 1

INITIATION A L'ASSEMBLEUR

Premier numéro d'HPGrâal, et première leçon d'ASM... C'est le début d'une longue série ! L'objectif final étant que vous soyez aussi bon que moi (si c'est possible :) )...
Bon on va peut-être commencer ? Alors sortez vos cahiers, respirez à fond, et nous voila partis dans les profondeurs du Saturn (que la Force soit avec vous !).
  1. L'assembleur c'est quoi ?

    L'assembleur est un langage de programmation, comme le RPL ou l'External (beurk !), qui permet d'accéder directement au coeur de votre HP pour lui faire faire ce que vous voulez, et en plus à une vitesse folle (près de 1000 fois plus rapide que le RPL)...
    Mais comment est-ce possible ? eh bien tout simplement en contrôlant directement le processeur... Vous savez, ce truc électronique qu'on compare souvent au "cerveau" des ordinateurs ou des calculatrices, qui contrôle tous leurs périphériques (mémoire, écran, clavier, etc...), et qui fait marcher la machine... C'est à lui qu'on va s'attaquer dans ce numéro.

    1. Un peu d'électronique.

      Les flèches indiquent le sens des relations entre les différents constituants de la HP.


      Comme dans toutes les machines de Van Neuwman, la mémoire contient des données et des programmes. Le processeur contient deux circuits électroniques : l'unité de contrôle lit en mémoire les programmes, et reconnaît les différentes instructions du processeur. L'unité de traitement exécute ces instructions dans le but de traiter les informations. Elle peut lire et écrire des données en mémoire. Pour travailler, elle utilise des registres, sortes de mini-mémoires qui servent à stocker des informations temporaires.

    2. Le binaire et les bits.

      L'informatique utilise beaucoup l'électronique, ce qui explique l'utilisation du binaire : un interrupteur peut être dans deux états : ouvert ou fermé, ce qu'on traduit mathématiquement par 0 ou 1. Ainsi, on code tout en binaire (textes, images, chiffres, programmes, sons...). C'est très pratique pour les nombres : on utilise la base 2 ce qui permet de faire faire des opérations mathématiques au processeur (sur HP : additions et soustractions).
      On appelle alors "bit" la plus petite quantité d'information (pour BInary digiT). Un bit vaut 0 ou 1.
      Le processeur de la HP est un Saturn, qui rentre dans la classe des processeurs 4 bits, ce qui signifie qu'il analyse les informations par blocs de 4 bits, appelés "quartets". En informatique, pour mesurer les capacités de mémoire, on utilise plutôt l'octet : un octet = 8 bits = 2 quartets.

      A noter : 1 Ko (Kilo-octet) = 1024 octets = 210 octets
      1 Mo (Mega-octet) = 1024 Kilo-octets = 220 octets
      On parle aussi de Go (Giga-octets) mais pas sur HP.

    3. Compter en base binaire.

      Je vous renvoie à vos cours de maths de CM2 pour savoir ce qu'est une base. [ndJCL : Cela fait longtemps que les bases ont été virées des programmes de primaire... Et d'ailleurs, cela était plus ou moins fait selon le niveau en math des instits...]. Comme je suis gentil et que je sais que vous êtes aussi fainéants que moi, voici un exemple :

      
        base		|  décimale	|  binaire 	| hexadécimale (base 16)
      
        nombres	|	 0	|       0	|	 0
      
        		|	 1	|       1	|	 1
      
        		|	 2	|      10	|	 2
      
        		|	 3	|      11	|	 3
      
        		|	 4	|     100	|	 4
      
        		|	 5	|     101	|	 5
      
        		|	 6	|     110	|	 6
      
        		|	 7	|     111	|	 7
      
        		|	 8	|    1000	|	 8
      
        		|	 9	|    1001	|	 9
      
        		|	10	|    1010	|	 A
      
        		|	11	|    1011	|	 B
      
        		|	12	|    1100	|	 C
      
        		|	13	|    1101	|	 D
      
        		|	14	|    1110	|	 E
      
        		|	15	|    1111	|	 F
      
        		|	16	|   10000	|	10
      
        
      Bon allez, je suis sympa alors j'explique : 11 = 1*23 + 0*22 + 1*21 + 1*20 => 1011.
      [ndJCL: Vous pourrez remarquer que c'est exactement pareil qu'en base décimale, la base usuelle. En effet, 1798 = 1*103 + 7*102 + 9*101+ 8*100 ]
      Vous remarquez tout de suite que pour multiplier par deux un nombre en binaire, il suffit de rajouter un 0 à la fin !
      Sur HP, on utilise surtout l'hexadécimal, très pratique puisque sur un quartet on peut coder 16 chiffres...
      [ndJCL: Un peu faible l'argument! On utilise surtout l'hexadécimal car la traduction hexa <----> binaire est très simple; en effet, il suffit de regrouper par 4 les chiffres binaires, de les traduire en hexa par groupe de 4 et de mettre le tout bout à bout pour obtenir de l'hexa; et de traduire chaque chiffre hexa en binaire et de mettre bout à bout pour obtenir du binaire. Ainsi:
      
        C  <----> 1100
      
        8  <----> 1000
      
        C8 <----> 11001000
      
        
      Tout cela est du au fait que 16 est une puissance de 2]

    4. Les différents langages.

      On a vu tout à l'heure que le processeur reconnaissait les instructions qu'il lit en mémoire par l'intermédiaire de l'unité de contrôle. En fait à chaque instruction réalisable par le Saturn est associé au moins un code binaire (ou hexadécimal, c'est pareil). Par exemple, la séquence 101010100110 (AA6 en hexadécimal) est interprétée par l'unité de contrôle du Saturn comme "multiplie par deux le contenu de telle partie de tel registre".
      On appelle Langage Machine l'ensemble des codes binaires connus par le processeur.
      Mais nous le binaire (et même l'hexadécimal) on aime pas trop parce que c'est pas très parlant. Alors au lieu de se prendre la tête à programmer avec des 0 et des 1, on utilise l'assembleur : à chaque instruction du langage machine, on associe un mnémonique plus agréable à utiliser. Pour reprendre l'exemple de tout à l'heure, au lieu de "101010100110" on utilise plutôt "C=C+C A". C'est quand même plus pratique, non ? Bon OK il faut aussi savoir ce que ça veut dire, mais ça, ça viendra tout seul plus tard.
      Maintenant on a un problème : le langage machine est par définition le seul que comprenne la machine, donc le Saturn ne pige rien aux mnémoniques de l'assembleur, alors quand on a fait un programme en assembleur (qu'on abrégera en ASM), il faut traduire les mnémoniques pour obtenir du langage machine. Pour ça on utilise un programme (on va pas faire ça à la main, oh ! Pas fou non ?). Ce programme porte le même nom que le langage : on parle donc d'UN assembleur pour le programme et de L'assembleur pour le langage.
      Et le RPL et l'External dans tout ça ? bah le RPL fait en fait appel à des sous programmes en Externals, eux-mêmes faisant appel à des programmes en langage machine. La lenteur de ces langages par rapport à l'assembleur est due à une plus grande complexité et aussi, il faut bien le reconnaître, à la mauvaise qualité des programmes internes de la HP.

  2. Comment on fait ?

    Dans ce numéro (et dans les suivants aussi) vous aller trouver un programme en assembleur (asm-pratik). Même si vous ne pouvez pas encore le comprendre vous pouvez quand même vous y intéresser, ça vous donnera une bonne idée de ce qu'est l'assembleur plus précisément... Je vais donc maintenant vous expliquer comment le rentrer dans votre HP (valable pour tous les progs en ASM) :
    Procurez-vous tout d'abord un assembleur : sur S(x) je vous conseille Asm-flash dont j'utiliserai la syntaxe, comme tout le monde, car tous les assembleurs de la G(x) (ou presque) l'ont adoptée... donc prenez le premier qui vous tombe sous la main. Si toutefois vous voulez le Top du Top, ruez-vous sur le MASD du MétaKernel (Hpmâd) ou sur JASM (Jylog) (cf. news).
    Ensuite recopiez le programme dans une chaîne de caractères en respectant les sauts de lignes après chaque instruction et sans oublier le caractère @ (alpha, shift-droit et ENTER) à la fin. Par contre vous n'êtes pas obligés de mettre les commentaires (signalés par un %), mais vous pouvez, ils ne seront pas assemblés. On appelle cette chaîne "source" du programme, sauvez-la pour pouvoir la modifier après...
    Puis rappelez-la au niveau 1 de la pile, et lancez votre assembleur. S'il n'y a pas d'erreurs dans la source (personne n'est parfait), vous devriez obtenir un objet "code" : c'est votre programme, faites en ce que vous vous voulez...
    Petit (gros) conseil : lorsque vous ferrez vos programmes vous mêmes, sauvegardez toujours ce que vous avez de précieux sur ordinateur ou carte protégée en écriture, car un programme marche rarement du premier coups, et en assembleur, la moindre erreur (dites bug) provoque souvent un plantage de la HP. En général, on s'en sort en appuyant sur ON et C en même temps, mais pas toujours. Dans ce cas il faut toujours avoir un trombone sur soi : insérez-le dans le trou sous le patin haut/droit au dos de la HP, ça la relancera, mais vous risquez de perdre le contenu de la mémoire (rassurez-vous ça n'arrive pas si souvent). Dernier détail : nos programmes sont (normalement) sans bugs...

  3. La structure de la machine

    Après tant de théorie, on va enfin s'attaquer à quelque chose de plus concret, en regardant de plus près la structure de la machine.
    On ne va pas tout de suite parler du Saturn, parce qu'il y a des choses que vous devez savoir avant. (ne soyez pas effrayés par la quantité d'informations que vous recevez...). On va donc voir maintenant la mémoire et les Entrées/Sorties.

    1. La mémoire.

      Il y en a de deux sortes : la mémoire RAM et la ROM. ROM signifie en anglais "Read Only Memory" c'est-à-dire qu'on ne peut que lire cette mémoire et surtout pas y écrire. Ce type de mémoire sert à stocker les programmes qui font fonctionner votre machine : ceux qui ont étés écrits par Hewlett Packard. Cette mémoire ne peut pas bouger, ce qui assure la sécurité du système...
      La RAM quant à elle, permet de stocker vos programmes ou vos données puisqu'on peut y écrire et y lire.
      Sur HP, la ROM fait 512Ko et la RAM destinée aux utilisateurs fait 32 Ko pour les G et 128 Ko pour les GX.
      Mais dans la HP, il y a aussi deux autres mémoires RAM, qui elles ne servent pas directement pour l'utilisateur, mais qui sont très pratiques pour les programmeurs : la RAM I/O et le Bank-Switcher.

    2. La RAM I/O.

      Ou RAM des Entrées/Sorties. Cette mémoire sert d'intermédiaire entre le processeur et les périphériques (contrôleur d'écran, IR et câble, horloge), mais aussi avec d'autres composants de la machine, comme les piles ou le bus. En fait ce n'est pas une vraie mémoire RAM au sens ou certaines parties n'en sont pas lisibles et ne servent qu'en écriture à transmettre des informations aux périphériques. Certaines parties même ne servent pas à la même chose suivant qu'on y lise ou qu'on y écrive. On verra dans un autre numéro le détail de toutes ces parties et leurs rôles.

    3. Le Bank-Switcher.

      Ou Sélecteur de bancs. Cette mémoire sert à sélectionner le banc de la carte en port 2 des HP48GX. Vous savez sûrement que sur GX on peut mettre des cartes de capacité supérieure à 128Ko en port 2. Pour gérer ces cartes, la HP les considère en fait comme plusieurs "bancs" de 128Ko chacun. En gros c'est comme si vous aviez plusieurs cartes de 128 Ko dans une seule. La HP ne peut travailler que sur un seul banc à la fois, il faut donc qu'elle puisse sélectionner le banc sur lequel elle va travailler : le Bank-Switcher sert à ça...
      Pour choisir un banc il suffit de lire quelque chose dans la partie du Bank-Switcher correspondante. Ce n'est donc pas une vrai mémoire, on parle plutôt de Module.
      A noter : ce module est présent sur les HP48G, bien qu'elles ne puissent pas recevoir de cartes.

    4. Les entrées et sorties contrôlées par le processeur.

      Les entrées : seul le clavier est contrôlé par le processeur, on y reviendra.
      Les sorties : il n'y a que le beeper. Il est d'ailleurs contrôlé par les mêmes instructions que le clavier.

    5. Le bus.

      Ce bus là n'a rien à voir avec la RATP. Il s'agit de l'organe de la HP qui permet aux différents éléments de communiquer avec le Saturn. Petit schéma :
      Lorsque le Saturn veut communiquer avec un des chips (modules) de la HP, il envoie sur le bus une adresse (vous remarquerez qu'il y a 4 fils sur le bus : c'est un bus 4 bits), et en même temps un signal électrique dans la daisy-chain.
      Chaque module a un gestionnaire relié à la daisy-chain. Ainsi lorsqu'un gestionnaire reçoit un signal sur la daisy-chain il sait qu'il y a une adresse qui se balade sur le bus. Là il regarde si cette adresse le concerne ; si oui, il agit en conséquence, sinon il fait passer le message au gestionnaire suivant par la daisy-chain. La conséquence de ce système est une priorité des différents modules. Par exemple, la RAM est prioritaire sur la ROM, car si une information concerne la RAM elle n'atteindra pas la ROM.

    6. Le système d'adressage.

      Vous avez peut être remarqué que la ROM n'a pas de gestionnaire... C'est du au fait que pour le Saturn une adresse tient sur 5 quartets, en hexadécimal, ce qui fait FFFFF, soit 1048575 adresses possible. Et chaque adresse correspond à un quartet. Le Saturn peut donc adresser 1 048 575 quartets, soit 512 Ko... Or c'est justement la taille de la ROM !!! Il en résulte que si un message arrive jusqu'à la ROM, il la concerne forcément, donc pas besoin de gestionnaire.
      Une autre conséquence du fait que la ROM occupe tout le domaine des adresses possibles pour le Saturn est que certaines parties de la ROM sont masquées par les autres modules (qui eux aussi doivent avoir une adresse).
      Pour savoir si une information qui circule sur le bus concerne son module, un gestionnaire doit être configuré, c'est-à-dire qu'il doit connaître l'adresse de début de son module et sa taille (à l'exception de la RAM I/O qui à une taille fixe de 32 octets et dont seule l'adresse est configurable).
      Pour avoir accès aux parties cachées par d'autres modules, le Saturn doit déconfigurer ces modules ou les reconfigurer à une autre adresse ou à une autre taille. Lorsqu'un module est déconfiguré c'est comme s'il n'existait plus...
      Remarques :
        • Même si un module n'est pas présent, son gestionnaire existe toujours et doit être configuré (généralement à une adresse inutilisée et à sa taille minimale).
        • A part pour la RAM I/O dont la taille est fixe, la taille d'un module doit être un multiple de 2Ko.
        • En plus, l'adresse du début d'un module doit être un multiple de sa taille.
        • Si on configure un module à une taille plus petite que sa taille réelle, on n'aura accès qu'à son début.
        • Si on configure un module à une taille plus grande que sa taille réelle, tout se passe comme si on avait plusieurs copies du modules à la suite.

  4. Le Saturn.

    Je vous ai déjà parlé des registres, mais je vais y revenir : les registres sont de toutes petites mémoires (comparées à la taille de la RAM) qui servent à stocker des informations utilisées par le Saturn de manière temporaire, pour éviter d'avoir à utiliser la RAM, car le processeur met environ 1000 fois moins de temps pour récupérer des informations dans les registres que dans la RAM. Ces registres sont de deux types : les registres "normaux" et les flags (ou drapeaux en français). Ces derniers ont le même rôle que les drapeaux utilisateurs : ce sont des indicateurs d'état contenant un bit. Par exemple un flag peut servir à indiquer que le son est allumé (à 1) ou éteint (à 0).
    Dans le Saturn, on trouve des registres pour plusieurs usages différents. Il y a :
      • Les registres de calcul
      • Les registres de sauvegarde.
      • Les pointeurs
      • Les registres - drapeaux
      • Les registres d'Entrée/Sortie

    1. Les registres de calcul.

      Il y en a quatre en tout et on les nomme respectivement A, B, C, et D. Ce sont des registres de 64 bits, ce qui fait 16 quartets pour chaque registre. Ils servent à faire tous les calculs et même d'autre choses c'est pourquoi ce sont les registres les plus utilisés.
      Je vous ai dit que ces registres avaient une taille de 16 quartets (numérotes de #0 à #F), mais ils ont une structure plus compliquée, car ils sont divisées en champs. Un champ est une partie du registre sur laquelle on peut travailler séparément sans toucher au reste du registre. Mais ne croyez pas pour autant que l'on puisse considérer qu'un champ fonctionne comme un registre isolé, car les différents champs d'un même registre peuvent se recouper. Vous comprendrez sûrement mieux avec un petit schéma :
      
        \/  numéro du quartet en hexadécimal
      
          F    E    D    C    B    A    9    8    7    6    5    4    3    2    1    0
      
        |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|
      
        /\ représentation des bits (par des points)
      
        
      Ca, c'est l'ensemble d'un registre. Voyons maintenant les différents champs (ce sont les mêmes pour tous les registres de calcul et aussi pour les registres de sauvegarde).
      • Champ A : le plus utilisé. On l'appelle A pour Adresse (je vous rappelle que le Saturn code les adresses sur 5 quartets et c'est justement la taille de ce champ):
        
                                               4    3    2    1    0
        
                                             |....|....|....|....|....|
        
            
      • Champ B : très utilisé aussi. B signifie Byte, c'est à dire un octet. Il fait donc 2 quartets.
        
                                                       1    0
        
                                                     |....|....|
        
            
      Les champs qui suivent sont liés à la représentation des réels dans la HP : ils sont codés sur 16 quartets dont un pour le signe, 12 pour la mantisse et 3 pour la valeur de l'exposant. On a donc :
      
          F    E    D    C    B    A    9    8    7    6    5    4    3    2    1    0
      
        |....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|....|
      
        | S  |                          M                                |        X     |<-- champs
      
        |    |                                                           | XS |   B     |<-- autres
      
                                                                                             champs
      
        
      Les noms : S pour Signe, M pour Mantisse, X pour eXponant (exposant en anglais), et XS pour eXponant Sign. Vous connaissez déjà B.
      Vous remarquerez que les champs A et M se chevauchent, donc si vous travaillez sur M vous allez modifier la fin du champ A du même registre, mais pas le champ X. Mais il y a encore d'autres champs :
      • Champ W (pour Wide) qui est la totalité du registre (bah oui c'est bien beau de travailler au champs quand il y a du soleil mais faudrait peut être pas oublier qu'on a des registres de 16 quartets...).
      • Le champ P . C'est un champ très particulier d'un seul quartet, mais qu'on peut choisir en mettant son numéro dans un registre appelé P (aussi). Par exemple si j'ai besoin de ne travailler que sur le quartet E, je vais mettre E dans le registre P et après je vais travailler sur mon champ P. On y reviendra dans le paragraphe sur les pointeurs.
      • Le champ WP fait encore plus fort car il permet de travailler sur tous les quartets de 0 à celui dont la valeur est dans le registre P (WP signifie Wide-P). Ce qui nous donne par exemple pour P=7:
        
                                 7    6    5    4    3    2    1    0
        
                               |....|....|....|....|....|....|....|....|
        
                               | P  |                                  |
        
                               |                  WP                   |
        
          
      C'était le dernier ! En Général on utilise une notation pour ne pas avoir à répéter "le champ A du registre C" ou encore "C champ A" : on écrit "Ca" ou "C.A" au choix. [ndJCL: On trouve aussi "C[A]", et prononcez de toutes façon C champ A].
      Petit détail sur les registres de calcul : ils ne sont pas du tout équivalents : on ne peut pas effectuer les mêmes opérations sur tous les registres. Entre autre, Le registre C est le registre roi : on peut faire toutes les opérations sur lui. Ensuite vient le registre A qui peut aussi faire beaucoup de chose mais moins. Quand aux registres B et D ils servent la plupart du temps à stocker des valeurs pendant qu'on bosse sur C et A. De plus, si une instruction nécessite deux registres (par exemple une addition), on est obligé d'en prendre deux consécutifs (dans l'ordre alphabétique), sauf pour C qui marche aussi avec A. Il en résulte que l'on ne peut pas additionner A et D.

    2. Les registres de sauvegarde.

      Il y en à 6 en tout, ils ont pour noms R0, R1, R2, R3, R4 et RSTK. Commençons par la série des R0 à R4. Ce sont des registres du même type que les registres de calcul (entre autres ils sont également coupés en champs) et dont le seul rôle est de sauvegarder le contenu des registres A et C (et donc des registres B et D par leur intermédiaire), car 4 registres de calculs, même séparés en champs, c'est parfois un peu juste pour stocker tout ce dont on a besoin, alors plutôt que d'aller écrire en mémoire RAM ce qui est très lent, on met les valeurs dont on se sert peu dans les registres de sauvegarde et on les récupère quand on en a besoin...
      Le dernier, RSTK est totalement différent : il s'agit de la pile des retours (Return StaCK) du Saturn: Ce processeur est capable d'exécuter ce que l'on appelle des sous-programmes, c'est-à-dire des programmes en langage machine normaux mais qui se finissent par l'instruction RTN (ReTurN). Le principe est que le processeur, qui est en train d'exécuter un programme stocké à l'adresse A peut aller exécuter un programme à l'adresse B et revenir à l'adresse A après. Ca sert par exemple quand on a besoin d'effectuer plusieurs fois un même programme à des moments différents et qu'on a pas envie de le répéter.
      L'instruction qui permet de sauter vers un sous-programme est GOSUB adresse-du-sous-programme. Ainsi si on a :
      
        adresses		instruction
      
        A			GOSUB B
      
        C			suite du programme
      
        ...			...
      
        B			instruction du sous-programme
      
        D			RTN
      
        
      Le Saturn va voir "GOSUB B" alors il va aller à l'adresse B et il va exécuter les instructions du sous-programme, jusqu'à ce qu'il tombe sur l'instruction "RTN". A ce moment là, il retourne à l'adresse C et continue la suite du programme. On peut se demander où le Saturn écrit l'adresse C pour savoir que c'est là qu'il faut retourner après le RTN ? Bah.. à votre avis ? Oui bien joué, dans le registre RSTK ! Celui-ci fait 160 bits soit plutôt 8 groupes de 5 quartets (puisque les adresses sont stockées sur 5 quartets). On peut donc stocker 8 adresses dans cette pile ce qui permet d'emboîter jusqu'à 8 sous-programmes. En fait il est fortement déconseillé d'en emboîter plus de 6... Cette pile fonctionne comme celle de la HP : la dernière adresse rentrée est la première accessible (et la seule !). Quand on y rentre une nouvelle adresse (ce qui est fait automatiquement par l'instruction GOSUB), toutes les autres sont décalées, ce qui fait que la dernière est perdue (Eh oui contrairement à la pile dans laquelle vous faites vos calculs celle ci à une taille limitée, et lorsqu'elle est vide, elle ne comporte que des 0...).
      Cette utilisation explique qu'on se serve rarement de cette pile pour sauvegarder des données.
Il est tard maintenant et vous avez déjà bien travaillé alors on verra la suite des registres dans le prochains numéro, ainsi que les instructions dont on dispose pour programmer en ASM...

HpFool


Des questions:hpgraal@hotmail.com
Un mot au WEBMASTER?:gissehel@mygale.org
Passez donc sur pulsar:Le site pulsar