![]() ![]() ![]() |
![]() ![]() ![]() ![]() ![]() |
![]() ![]() ![]() |
Surtout ne perdez pas courage si vous pataugez, c'est presque normal étant donné que le langage assembleur est radicalement différent des langages de haut niveau tels que le Turbo Pascal, le C/C++, le Basic...
Je suis disponible pour répondre à vos questions. Plusieurs d'entre vous m'ont déjà demandé de l'aide alors n'hésitez pas, sachez toutefois que je prépare un BTS et les réponses ne seront pas des plus rapides.
Vous devez avoir compris les parties abordées ici pour pouvoir commencer à programmer dans de bonnes conditions.
![]() ![]() ![]() |
Pour vous faire une idée de sa puissance, sachez que les TI peuvent rivaliser avec la console Megadrive de Sega (tout est relatif bien sur), le Motorola 68000 est un processeur possédant un bus (circuit de transfert de données) 16 bits avec des registres (variables internes de données) 32 bits.
![]() ![]() ![]() |
Ceci est équivalent pour nous à OUI et NON, VRAI et FAUX...
Il n'y a pas d'alternatives telles que "peut-être", "oui mais non"...
C'est entre autre pour cela que les nombres aléatoires n'ont d'aléatoire que le nom, car ils sont en fait générés par une fonction de période très longue.
![]() ![]() ![]() |
8 bits forment un Octet | Byte en anglais | d'où .b dans un programme |
schématiquement | xxxxxxxx | où x représente un bit |
nous avons 2^8 possibilitées | = | 256 nombres différents |
16 bits forment un Mot | Word en anglais | d'où .w dans un programme |
schématiquement | xxxxxxxxxxxxxxxx | où x représente un bit |
nous avons 2^16 possibilitées | = | 65536 nombres différents |
32 bits forment un Double mot | Longword en anglais | d'où .l dans un programme |
schématiquement | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | où x représente un bit |
nous avons 2^32 possibilitées | = | 4294967296 nombres différents |
![]() ![]() ![]() |
Reportez-vous à l'annexe B-6 du manuel de votre TI pour avoir le code des différents caractères.
![]() ![]() ![]() |
![]() ![]() ![]() ![]() |
![]() ![]() ![]() |
Pour mieux comprendre ce que je viens de vous dire, pensez que les romains (et les Italiens encore un peu de nos jours) utilisaient les symboles I, V, X... et les combinaient entre eux (d'une façon un peu spéciale toutefois).
Notre pays ainsi qu'une grande partie de la planète utilise le système décimal constitué de dix symboles, ceux-ci sont 1, 2, 3, 4, 5, 6, 7, 8, 9 et 0. Nous les combinons pour arriver au même résultat.
Les systèmes informatiques nous ont obligés à changer notre système maternel car ceux-ci ne comprennent que les états ouverts et fermés (physiquement sous forme de tensions dans des transistors). Les premiers informaticiens ont choisi comme symboles 0 et 1 pour le système binaire (base 2). Désormais il faudra combiner ces 0 et 1.
Le système binaire étant très lourd et fort peu compréhensible par l'homme, les informaticiens ont alors eu l'idée de créer le système hexadécimal (base 16), celui-ci est constitué de nos digits 1, 2, 3, 4, 5, 6, 7, 8, 9 et 0 mais aussi des digits A, B, C, D, E, F.
Le grand avantage de cette représentation, c'est qu'un digit hexadécimal est équivalent à 4 digits binaires.
Le code ASCII fait même office de système de numération (base 256) puisque à chaque caractère correspond une valeur !
Nous ne parlerons pas du système octal (base 8) car celui-ci n'est pas ou très peu utilisé aujourd'hui.
![]() ![]() ![]() |
8 = | 8*1 |
98 = | 9*10 + 8*1 |
998 = | 9*100 + 9*10 + 8*1 |
1998 = | 1*1000 + 9*100 + 9*10 + 8*1 |
Il faut remarquer que ces nombres 1, 10, 100 et 1000 sont des puissances de 10, dans l'ordre 10^0, 10^1, 10^2 et 10^3. Cette représentation est appelé base 10, permet de représenter tous les nombres possibles grâce à une combinaison de digits allant de 0 à 9.
En assembleur Motorola 68000, il faut mettre # avant toute valeur décimale.
PROGRAMMATION
MOVE.w #1999,D0 ; copie le nombre #1998 dans D0
![]() ![]() ![]() |
Prenons quelques nombres simples et voici l'analyse que nous pouvons en faire :
00000001 = 0*128 + 0*64 + 0*32 + 0*16 + 0*8 + 0*4 + 0*2 + 1*1 = | 1 |
00000011 = 0*128 + 0*64 + 0*32 + 0*16 + 0*8 + 0*4 + 1*2 + 1*1 = | 3 |
00101011 = 0*128 + 0*64 + 1*32 + 0*16 + 1*8 + 0*4 + 1*2 + 1*1 = | 43 |
11101011 = 1*128 + 1*64 + 1*32 + 0*16 + 1*8 + 0*4 + 1*2 + 1*1 = | 235 |
Ces nombres 1, 2, 4, 8, 16, 32, 64 et 128 sont des puissances de 2, dans l'ordre 2^0, 2^1, 2^2 et 2^3, 2^4, 2^5, 2^6 et 2^7. Cette représentation est appelé base 2 et permet de représenter tous les nombres possibles grâce à des groupements de 8, 16 ou 32 bits pour former respectivement un octet, mot et double mot.
Nous mettons à gauche des 0 qui paraissent inutiles parce que nous travaillons avec des octets, mots et doubles mots et nous devons représenter à chaque fois les 8, 16 ou 32 bits les composant.
Pour nommer un bit très rapidement nous leur attribuons un numéro qui s'appelle le poids,
![]() ![]() ![]() |
x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | |
poids | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
PROGRAMMATION
MOVE.w #%1100101011000110,D0 ; copie le nombre %1100101011000110 dans D0
![]() ![]() ![]() |
A = 10 |
B = 11 |
C = 12 |
D = 13 |
E = 14 |
F = 15 |
Prenons quelques nombres simples et voici l'analyse que nous pouvons en faire :
7 = | 7*1 |
C7 = | 12*16 + 7*1 |
1C7 = | 1*256 + 12*16 + 7*1 |
51C7 = | 5*4096 + 1*256 + 12*16 + 7*1 |
#%1011001101011000 = #% 1011 0011 0101 1000 = #$ B 3 5 8 = #$B358
car | #%1011 = # 1*2^3 + 0*2^2 + 1*2^1 + 1*2^0 = 8 + 0 + 2 + 1 = #$B |
#%0011 = # 0*2^3 + 0*2^2 + 1*2^1 + 1*2^0 = 0 + 0 + 2 + 1 = #$3 | |
#%0101 = # 0*2^3 + 0*2^2 + 1*2^1 + 1*2^0 = 0 + 0 + 2 + 1 = #$5 | |
#%1000 = # 1*2^3 + 0*2^2 + 0*2^1 + 0*2^0 = 8 + 0 + 0 + 0 = #$8 |
PROGRAMMATION
MOVE.w #$4000,D0 ; copie le nombre $4000 dans le premier mot de D0
Chaque octet en mémoire est repéré par une adresse,
si vous écrivez MOVE.w $4000,D0, vous mettez le mot repéré par l'adresse $4000 de votre TI dans le registre D0 et non la valeur $4000.
Donc si à l'adresse $4000 il y a la valeur #$E534, D0 vaudra #$????E534 à la fin de l'instruction.
En faisant MOVE.w #$4000,D0 vous mettez la valeur #$4000 (= #16384 en décimal) dans D0.
![]() ![]() ![]() |
![]() ![]() ![]() ![]() ![]() |
![]() ![]() ![]() |
Dans cette explication, le rouge indique la partie de poids fort et le bleu celle de poids faible :
![]() |
xxxxxxxx |
nous avons un bit de poids fort et un bit de poids faible | |
![]() |
xxxxxxxxxxxxxxxx |
nous avons un octet de poids fort et un octet de poids faible | |
![]() |
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
nous avons un mot de poids fort et un mot de poids faible |
![]() ![]() ![]() |
Pour cela intéressons-nous au bit de poids fort d'un octet, mot ou double mot.
Etant donné qu'en assembleur il n'y a pas de signes + et -, c'est ce bit qui joue ce rôle :
![]() ![]() |
00011010 | = | 26 | ||
10011010 | = | 154 | = | -102 |
0011011100101110 | = | 14126 | ||
1011011100101110 | = | 46894 | = | -18642 |
00011011110101001111010001010110 | = | 466941014 | ||
10011011110101001111010001010110 | = | 2614424662 | = | -1680542634 |
type | nombres non signés | nombres signés | ||||
octet | 0 | à | 255 | -128 | à | 127 |
mot | 0 | à | 65535 | -32768 | à | 32767 |
double mot | 0 | à | 4294967295 | -2147483648 | à | 2147483647 |
![]() ![]() ![]() |
si le bit de poids fort est armé (=1) il faut appliquer le complément à deux à la valeur non signée, le résultat sera consideré comme un nombre signé négatif.
EXEMPLE 2 :
Prenons le nombre non signé 251, #251 = %11111011
Le bit de poids fort est armé (%10111011) : on appliquera le complément à deux
Complément à deux :
on fait un NON logique : NOT %11111011 = %00000100
puis on ajoute un : %00000100 + #1 = %00000101
Le résultat vaut : %00000101 = #-5
![]() ![]() ![]() |
Il suffit de faire tout d'abord un NON logique sur le nombre que l'on veut opposer (les 0 deviennent 1 et inversement) puis de lui ajouter 1.
EXEMPLE
prenons le nombre 51 | #51 = #%00110011 |
on fait un NON logique | #%00110011 devient #%11001100 |
maintenant #%11001100 + #%00000001 | = #%11001101 = #-51 |
MOVE.w #116,D0 ; copie le nombre #116 dans D0 NOT.w D0 ; effectue un NON logique (complément à un) ADDI.w #1,D0 ; incrémente D0 pour avoir le complément à deuxPROGRAMMATION (2)
MOVE.w #116,D0 ; copie le nombre #116 dans D0 NEG.w D0 ; effectue le complément à deux
![]() ![]() ![]() |
Il suffit de faire tout d'abord un NON logique sur le nombre que l'on veut opposer (les 0 deviennent 1 et inversement) puis de lui ajouter 1.
EXEMPLE
prenons le nombre 51, #51 = %00110011
on fait un NON logique, %00110011 -> %11001100
maintenant %11001100 + %00000001 = %11001101 = #-51
PROGRAMMATION
MOVE.w #116,D0 | ; copie le nombre #116 dans D0 |
NOT D0 | ; effectue un NON logique (complément à un) |
ADD #1,D0 | ; incrémente D0 pour avoir le complément à deux |
![]() ![]() ![]() |
Parmi deux instructions similaires, une terminée par "U" servira à effectuer une action sur un nombre non signé (Unsigned), et une autre terminée par "S" effectuera la même action en considérant que le nombre est signé (Signed).
PROGRAMMATION avec MULS
MOVE.w #116,D0 ; copie le nombre #116=#-140 dans D0 MOVE.w #219,D0 ; copie le nombre #219=#-37 dans D1 MULS.w D0,D1 ; D0*D1 => D1 = -140*-37 = #5180PROGRAMMATION avec MULU
MOVE.w #116,D0 ; copie le nombre #116 dans D0 MOVE.w #219,D0 ; copie le nombre #219 dans D1 MULU.w D0,D1 ; D0*D1 => D1 = 116*219=25404
![]() ![]() ![]() |
MOVE.l D0,D1 | ; copie le contenu de D0 dans D1 |
Tout d'abord MOVE, c'est un des nombreux mnémonique que nous utilisons dans nos programmes, comme vous pouvez le constater c'est soit un mot anglais complet soit l'abréviation de plusieurs mots anglais...
Ensuite .l, c'est la taille des données du premier opérande qui fait office de source, vous avez au choix .b pour byte (octet / 8 bits), .w pour word (mot / 16 bits) ou .l pour longword (double mot / 32 bits).
Puis nous avons un premier opérande appelé opérande source, la plupart des instructions sont formées de deux opérandes, certaines un seul et d'autre aucun. Pour la majorité des instruction c'est lui qui influencera l'opérande de destination. Dans une soustraction par exemple, c'est la source qui est retranchée à la destination et qui reste inchangée.
La plupart du temps nous avons l'opérande de destination déjà citée, pour la majorité des instructions c'est lui qui sera influencé par l'opérande source. Dans une addition par exemple, la source est ajoutée à la destination et le résultat est enregistré dans la destination.
Enfin il y a le commentaire, celui-ci est toujours après l'instruction, commence par ; et prend fin des que vous appuyez sur la touche [ENTREE] (code ASCII 13).
![]() ![]() ![]() |
![]() ![]() |
![]() ![]() ![]() |
Cette mémoire est divisée en deux grandes parties :
Comme nous l'avons vu précédemment 8 bits forment un octet, chaque octet à une adresse pour pouvoir être accédé, elle peut être soit paire soit impaire.
Attention, l'adresse d'un mot ou un double mot est l'adresse du premier octet le composant et doit être toujours paire !
Dans le cas contraire vous provoquerez l'interruption "ADDRESS ERROR"
Pour visualiser la mémoire de votre TI-92 je vous conseille d'utiliser Hexview 2.4 de Benoît Scherrer disponible chez Ticalc.org.
Le microprocesseur peut effectuer deux actions sur la mémoire :
![]() ![]() ![]() |
Un caractère étant codé sur 8 bits (octet), il ne prendra qu'un emplacement à chaque fois.
Une chaîne de caractère étant une suite de plusieurs caractères, celle ci occupe autant d'octets consécutif que de caractères plus un caractère de code ASCII nul pour la délimiter (à ne pas confondre avec l'espace de code ASCII 32)
Une valeur numérique occupera autant d'emplacement consécutifs que nécessaire :
![]() ![]() |
Nous avons huit registres de données 32 bits qui servent à contenir des données, ils ont comme noms D0, D1, D2, D3, D4, D5, D6 et D7. Pour accélérer les choses nous les appellerons Dn quand nous pourrons les utiliser indifféremment pour une tache.
Ensuite huit registres d'adresse 32 bits qui servent à contenir des adresses (pointeurs), ils ont comme noms A0, A1, A2, A3, A4, A5, A6 et A7.
Attention, le registre A7 est le pointeur de pile. Il est donc formellement déconseillé d'utiliser un autre registre d'adresse à la place ou de modifier d'une façon quelconque le registre A7 pendant l'exécution du programme.
La raison est fort simple : le microprocesseur, donc toutes les fonctions en ROM et par conséquent les bibliothèques accompagnant Fargo utilisent le registre A7 comme pointeur de pile.
Les registres d'adresse A0, A1, A2, A3, A4, A5 et A6 seront appelés An pour accélérer les choses, quand nous pourrons les utiliser indifféremment pour une tache.
Puis il y a le compteur ordinal 32 bits nommé PC (program counter), qui pointe en permanence sur la prochaine instruction a exécuter.
Seuls les 24 premiers bits sont utilisés, ce qui est largement suffisant pour accéder à toute la mémoire des TI, c'est pour cela que la plupart des adresses données sont du type $xxxxxx ou lieu de $00xxxxxx.
Enfin le registre de status 16 bits nommé SR, pouvant être décomposé en deux registres 8 bits. L'octet de poids faible est le registre de status utilisateur nommé CCR et l'octet de poids fort et l'octet système. Vous aurez besoins d'en savoir plus sur le registre de status utilisateur pour les instruction. Le registre de status est totalement expliqué par ailleurs.
Zguide © 1998 - 1999 par Florian DREVET. Tous droits réservés