Ce tutorial est prévu pour les calculatrices Texas Instrument modèles TI-89/92/V-200. A peu de choses près, ces trois machines sont identiques : leurs différences majeures sont au niveau de la taille de l'écran, et du clavier.
Il existe deux versions matérielles différentes : les HW1, et HW2.
Les HW1 sont les plus anciennes, les HW2 les plus récentes. Les HW2 comportent
quelques fonctionnalités supplémentaires par rapport aux HW1 (par exemple, les
HW1 n'ont pas de support d'horloge). La V-200 est considérée comme une HW2 (Il
n'existe pas de V-200 HW1).
Au cours de notre apprentissage de la programmation en Assembleur, il sera rare
que nous ayons à nous soucier des différences entre les différentes versions
matérielles, mais, quand il le faudra, nous préciserons que c'est le cas.
Il existe aussi plusieurs versions de "cerveaux". Ce "cerveau"
est le logiciel qui vous permet de faire des mathématiques, de programmer en
TI-BASIC, de dessiner, de lancer des programmes en Assembleur, ... ; bref, ce
"cerveau" est ce grâce à quoi votre machine est plus qu'un simple
tas de composants électroniques.
Différentes versions allant de 1.00 sur TI-92+, 1.01 sur TI-89, et 2.07
sur V-200, à, pour le moment, 2.09 (sortie durant le second trimestre
2003) ont été diffusées par Texas Instrument. En règle
générale, plus la version est récente, plus elle comporte
de fonctions intégrées, directement utilisables en Assembleur.
Ce "cerveau" est généralement appelé "AMS" (pour Advanced
Mathematic Software), ou, par abus de langage, "ROM" (Pour Read Only
Memory), puisque l'AMS est stocké dans un mémoire flashable de ce type.
Le plus souvent possible, nous essayerons de rédiger des programmes compatibles
entre les différentes versions de ROM, mais, dans les rares cas où ce ne sera
pas possible (par exemple, parce que nous aurons absolument besoin de fonctions
qui ne sont pas présentes sur certaines anciennes ROM), nous le signalerons.
Nos TIs sont dotées d'un processeur Motorola 68000, cadencé à 10MHz sur HW1,
et à 12MHz sur HW2.
(Ce processeur était utilisé sur les premiers Macintosh, sur certaines consoles
ATARI, et est toujours utilisé sur les rames de TGV atlantiques !)
Ce processeur comporte 8 registres de données, nommés de d0 à d7, et 8 registres
d'adresse, de a0 à a7. (Un registre est un petit emplacement mémoire situé à
l'intérieur même du processeur, et qui est donc très rapide ; c'est le type
de mémoire le plus rapide, mais aussi le plus cher, ce qui explique pourquoi
il n'y en a que si peu). Ces 16 registres ont une taille de 32 bits.
Les registres de données, de même que ceux d'adresse (de a0 à a6 seulement :
a7 est un peu particulier), sont généraux, ce qui signifie que l'on peut mettre
un peu ce qu'on veut dedans (Il n'y a pas, comme sur certains autres processeurs,
un registre réservé pour les boucles, ou autre). Cependant, étant donné le faible
nombre de registres, il vaut mieux les utiliser de façon judicieuse !
Le registre a7 est particulier dans le sens où il joue le rôle de "pointeur
de pile" : c'est lui qui contient l'adresse du sommet de la pile. La pile
("Stack", en anglais), est une zone mémoire un peu particulière, sur
laquelle on "empile" ou "dépile" des données... Nous verrons
plus tard ce que cela signifie exactement.
Le M68k (Abréviation de Motorola 68000) possède également un registre nommé "PC" (Program Counter) qui sert à indiquer en permanence au processeur quelle est la prochaine instruction qu'il devra utiliser. Rassurez-vous, lors de l'exécution normale d'un programme, c'est le processeur lui-même qui se charge de modifier de manière adéquate la valeur du PC. Ce registre est de 24 bits.
Ce processeur dispose aussi d'un registre de statut, nommé "SR" (Status
Register), sur 16 bits. Nous étudierons tout d'abord les 8 bits de poids faible,
puis les 8 bits de poids fort.
Voici le schéma représentatif du SR :
Nom | T | - | S | - | - | I2 | I1 | I0 | - | - | - | X | N | Z | V | C |
N° bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Registre de Flags :
Il s'agit de l'octet de poids faible du SR.
Voici, globalement, la signification des différents bits utilisés le comportant
:
Octet Système :
Il s'agit de l'octet de poids fort du SR.
Voici à présent, de faççon rapde, la signification des différents
bits utiles le composant :
Attention, ceci est assez technique. Si vous n'avez pas déjà de bonnes connaissances
en architecture et fonctionnement des processeurs, il est probable que vous
ne saisirez pas ce qui suit. Ce n'est pas pour l'instant grave : ceci n'est
utilisé qu'à un niveau assez avancé de programmation. Vous comprendrez en temps
voulu.
Ce dont nous allons ici parler tient encore une fois plus au processeur qu'à la TI, puisque nous nous pencherons sur la représentation des nombres en interne (au niveau du processeur et de la mémoire).
Les processeurs Motorola stockent les nombres en Big Endian ; c'est-à-dire
que l'octet de poids fort d'un nombre est rangé "à gauche".
Un petit exemple rendra les choses plus clair : le nombre $12345678 sera représenté
en mémoire par la suite d'octets suivant : $12, $34, $56, $78.
A titre d'information, les processeurs Intel de la famille ix86 (386, 486, et
Pentiums) auraient représenté ce nombre par la suite d'octets suivant : $78,
$56, $34, $12.
Force est de reconnaître que la technique utilisée par Motorola permet au programmeur
de parfois se "simplifier la vie" !
Les entiers, que ce soit négatifs, ou positifs, sont codés selon la technique dite du complément à deux.
Pour les entiers positifs :
Nous avons déjà vu comment passer du décimal au binaire ; c'est exactement ce
qu'il faut faire ici.
Par exemple, en travaillant avec des mots de deux octets, on aura :
16849 = %0100000111010001 (=$41D1)
Pour les entiers, le bit de poids fort est considéré comme un bit de signe.
S'il vaut 0, l'entier est positif, et s'il vaut 1, l'entier est négatif.
Par exemple, %1101111000010001 ne sera pas considéré comme 56849, mais comme
nombre négatif !
Pour les entiers négatifs :
Cette fois-ci, c'est un peu plus difficile ; mais il suffira de retenir la technique
utilisée, qui sera toujours la même. (Il y a d'autres méthodes, mais c'est celle-ci
que j'utilise, car c'est celle que je considère comme la plus simple).
Voici, toujours avec des mots de deux octets, comment encoder la valeur -16849
:
On commence par "traduire" la valeur absolue du nombre ; ici, 16849
:
16849 = %0100000111010001
Puis, on inverse la valeur de tous les bits (les bits à 0 passent à 1, en inversement ; cela revient à faire le complément à un du nombre), on obtient :
%1011111000101110
Enfin, on ajoute 1 au résultat :
%1011111000101110 |
Remarque : Une addition en binaire se fait de la même façon qu'en décimal. La seule chose dont il faut se rappeler, c'est que 1+1 = 10. |
(Précisons que la TI est dotée d'une fonction de conversion qui parvient à
effectuer ceci ! Il suffit de saisir -16849>Bin).
Utiliser la technique du complément à deux permet de mémoriser :
Comme vous avez pu le remarquer, la valeur minimale représentable est égale
à la valeur maximale représentable, plus un. Ceci n'est pas sans inconvénients,
et peut parfois poser problème, si l'on ne fait pas assez attention.
Il arrive que l'on travaille avec des valeurs dites "non-signées"
("unsigned" en anglais). Dans ce cas, les 8, 16, ou 32 bits sont tous
utilisés pour coder une valeur positive, comprise entre 0 et, respectivement,
2^8-1, 2^16-1 et 2^32-1.
Le processeur Motorola 68000 que nous utilisons, pour lequel nous allons programmer, est capable de reconnaître trois types de données entières. A chacun de ces types correspond une lettre, qui sera souvent utilisée comme suffixe pour certaines instructions, afin que le processeur puisse déterminer sur quel type de données elles doivent travailler ; le suffixe sera séparé de l'instruction par un point.
Je n'ai pas l'intention de vous forcer à ingérer plus de théorie tout de suite,
même si je suis d'avis que celle-ci pouvait s'avérer nécessaire, sans vous permettre
enfin de programmer ; dès le prochain chapitre, nous réaliserons notre premier
programme en Assembleur.
J'aurai pu, comme j'en avais l'intention au départ, partir dès
le premier chapitre sur un exemple de programme, et vous fournir les explications
que je vous ai donné dans les chapitres 1 et 2 en même temps que
celles portant sur cet exemple, mais j'ai vite réalisé que cela
ferait beaucoup trop de nouveautés en même temps. J'ai donc préféré
cette solution qui même si elle est moins "ludique" car ne commence
pas par du code, est probablement plus adaptée pour une bonne raison
: lorsque vous parviendrez au premier exemple de code, vous disposerez déjà
de bases qui, bien que assez peu approfondies, devraient vous faciliter la compréhension.
Bonne continuation !