ATTENTION : CE QUE JE VAIS VOUS APPRENDRE EST EXCEPTIONNELLEMENT DANGEREUX. TOUS LES EXEMPLES QUE JE PRÉSENTERAI AURONT ÉTÉ PRÉALABLEMENT TESTÉS SUR ÉMULATEUR. TOUT DOMMAGE À VOTRE CALCULATRICE DÛE À UNE FAUTE DE COPIE NE SAURA M'ÊTRE IMPUTÉE.Créer un programme hexadécimalPour créer un programme hexa sur une des calculatrices ci-dessus (les autres fichez le camp
), c'est au moins aussi simple que créer un programme Ti-basic : on va dans [prgm] NOUVEAU et on tape le nom de son programme.
Par contre, si on en reste là la calto va réellement croire que c'est un programme Ti-basic. Donc on va signaler notre identité en ajoutant le token (ou mot-clé)
AsmPrgm (uniquement via le catalogue), comme ça elle est bien mise au courant.
Sinon à part ça, je vous dit tout de suite comment exécuter un programme hexa, c'est pas beaucoup plus compliqué. Pour info, ça se lance
exactement de la même manière qu'un programme ASM :
- Code: Select all
Asm(prgmXXXXXXXX
Avec prgmXXXXXXXX le nom de votre programme hexa.
Enfin non, en réalité y'a deux façons :
- La commande précédemment décrite, ou
- En compilant le programme avant de le lancer
Pour compiler un programme hexa, on a une commande tout prête appelée
AsmComp() (toujours via le catalogue) qui prend en premier argument le programme à compiler et en deuxième argument le nom du fichier de sortie (qui ne doit évidemment pas déjà exister sous peine d'une ERROR:DUPLICATE). Le résultat sera un programme deux fois plus léger et rapide à lancer avec la première méthode. Un exemple pour illustrer le tout et on s'y met :
- Code: Select all
Première méthode :
Asm(prgmHEXA
Deuxième méthode :
AsmComp(prgmHEXA,prgmEXECUTER
Asm(prgmEXECUTER
Le header en hexadécimalSi vous connaissez l'ASM (je vais faire comme si), vous vous rappelerez sûrement du header, à écrire au début de chaque programme ASM. Ce header ressemblait plus ou moins à ça :
- Code: Select all
.org $9D93
.db $BB,$6D
; ici les .equ et autres #define
; programme
Ici rien de tout cela : comme en hexadécimal on n'utilise pas de lettres (ben oui A B C D E F c'est des chiffres je vous rappelle
) on n'a pas à s'embarrasser de conventions, de casse ou de quoi que ce soit.
Ce qui fait que notre beau header pimpant se résume en :
- Code: Select all
:AsmPrgm
:BB6D
C'est tout. Facile non ? Bah profitez-en parce que ça va pas durer :diable:
Retenez
absolument ces deux lignes, et encore plus la deuxième que la première. Si vous oubliez la première, vous aurez juste droit à une petite ERROR:INVALID vous signalant que vous avez oublié quelque chose, mais si vous oubliez la deuxième ... Ben ça change rien en fait, le programme s'exécute quand même
c'est si vous marquez une valeur erronée à la place genre 66BD que là je ne répondrai plus de rien.
Ce BB6D tout le monde s'en rappelle, c'est l'adresse où doit s'exécuter un programme. De ce côté-là, rien ne change.
Structurer son code hexadécimalL'avantage avec le code hexadécimal, c'est que comme justement il est en hexadécimal, il ne comprend pas les sauts de ligne
tant qu'ils ne coupent pas un octet en deux (on va voir ça). Par contre, il comprend les espaces, et il saura bien vous le dire via une ERROR:SYNTAX.
ATTENTION : si votre code hexa comporte une erreur détectée par la calto, appuyer sur Goto ne sert à rien, ça vous renverra à la fin de la commande Asm().Donc je viens de dire que la calto n'est pas gênée par les sauts de ligne tant qu'ils ne coupent pas un octet en deux. Et c'est vrai
Les "commandes" en hexadécimal (on ne peut pas vraiment les appeler comme ça mais bon) s'écriront
toujours tout le temps de la même manière : des groupes de deux chiffres hexadécimaux. Sachant qu'un chiffre hexa traduit 4 bits et forme ce qu'on appelle un quartet, deux chiffres hexa traduisent 8 bits en formant un
octet. C'est la position des bits qui va donner le
token à interpréter.
Donc disais-je, si dans un accès de frustration et de rage contre votre calculatrice vous insérez un saut de ligne entre deux quartets qui correspondent, elle va pas être d'accord et vous le fera savoir via une ERROR:SYNTAX !
Exemple :
- Code: Select all
:936103
:7AC8D5EFBA
Ça ça marche
:19473
:93DEFA8
Ça non
En fait c'est simple, si vous voyez une ligne comprenant un nombre impair de chiffres, c'est pas bon.
Aussi, en ASM les programmes finissent tous par RET. Ben là c'est plus RET c'est C9. Donc si vous ne mettez pas C9 à la fin de chaque programme, ça risque de bousiller votre calto en moins de temps qu'il n'en faut pour le dire. On a donc un code minimal qui ne fait rien :
- Code: Select all
:AsmPrgm
:BB6D
:C9
Ou même
:AsmPrgm
:BB6DC9
Dernière chose, au niveau de la lisibilité (si lisibilité il y a
), essayez au maximum de donner une structure cohérente à votre code. C'est à dire, mettez une instruction par ligne, pas deux, pas trois et encore moins une moitié d'instruction. Parce que oui, on peut mettre des "moitiés" d'instruction. Donc en gros pour mettre $54D1 dans DE et $41E6 dans HL faites ça :
- Code: Select all
:11D154
:21E641
Et pas ça :
- Code: Select all
:11D15421E641
Et encore moins ça :
- Code: Select all
:11D1
:5421
:E641
Vous voyez, ici y'a 2 et pas 3 instructions ! Quand je vous parlais de "moitiés" d'instructions, c'était pas une image.
Bon, ben cette fois on est paré, on peut y aller ! À l'assauuuuut !!!
Les registres et l'assignation en hexadécimalAïe ...
À partir d'ici la vraie galère commence.
Après des heures de dur labeur, j'ai enfin trouvé
toutes les adresses des registres !!!!!
k:
Commençons avec les registres. Ben c'est les mêmes qu'en ASM c'est juste qu'ils s'appellent pas pareil
Par exemple, en hexadécimal, hl s'appelle $21. Et encore, pas tout le temps.
Ah oui non parce qu'en plus de faire la même chose MAIS de s'appeler pas pareil, faut EN PLUS qu'ils jouent les schyzophrènes à changer de nom selon le contexte
par exemple, si vous voulez mettre une valeur dans DE il va s'appeler $11, mais si vous voulez mettre DE dans un autre registre il va s'appeler autrement (je sais pas encore comment désolé) !!! Si c'est pas juste pour faire ch*er les gens ça !
L'assignation classique : valeur hexadécimale vers registreC'est le cas le plus courant, qui correspond à assigner une valeur hexadécimale (on fait de l'hexa je rappelle
) à un registre. En ASM, on fait comme ça :
- Code: Select all
ld a,$07 ; maintenant, le registre a contient $07
En hexadécimal, on a juste à écrire le nom du registre suivi de la valeur à assigner. Même pas une commande, rien. La preuve que les programmeurs sont vraiment des gros flemmards ^^ . Donc, pour le cas d'une assignation dite "classique" :
- A s'appelle $3E
- B s'appelle $06
- C s'appelle $0E
- D s'appelle $16
- E s'appelle $1E
- F s'appelle pas
- H s'appelle $26
- L s'appelle $2E
- AF s'appelle pas non plus
- BC s'appelle $01
- DE s'appelle $11
- HL s'appelle $21
Oui, en fait AF et F n'existent pas, puisque les flags sont gérés directement en hexadécimal (on n'utilise pas F).
On remarque que les adresses de tous les registres 8 bits (sauf A) peuvent être devinés dès qu'on connaît celle de B ($06). En effet, chacun de ces registres étant de 8 bits, par exemple pour trouver C on a juste à faire B + $08, ce qui donne $0E, et ainsi de suite. C'est pareil pour les registres 16 bits à partir de BC ($01) auquel par exemple pour trouver DE on ajoute 16, soit $10. Donc, DE est bien situé à $11.
Alors c'est sûr que niveau optimisation c'est du jamais vu mais je vous dis pas combien j'ai galéré pour comprendre la signification de ces deux octets qui ressemblent à rien !
Donc, pour assigner $42 (donc 66) à E, on fera :
- Code: Select all
1E42
Pas compliqué, si ?
Dans le même esprit, ici on assigne $3D94 à HL :
- Code: Select all
21943D
Et là normalement vous auriez dû noter quelque chose.
Show/Hide spoilerAfficher/Masquer le spoiler
Si on regarde le code, on voit qu'on assigne à HL non pas $3D94 mais $943D ! En effet, on doit inverser les octets de toute valeur 16 bits pour l'utiliser correctement.
Alors je précise que c'est comme ça mais je sais pas pourquoi, hein
je m'en suis juste rendu compte lors de mes tests.
L'assignation registre vers registreAccrochez-vous, là ça devient vraiment compliqué.
Les registres 8 bitsPour assigner un registre à un autre registre, la théorie est très simple et l'application très compliquée : en effet, cette commande en ASM :
- Code: Select all
ld a,b
Se traduit en hexadécimal par
- Code: Select all
78
Quoi !? Un seul octet pour une commande !? me direz-vous. Et c'est là que vous allez vous mettre à détester l'hexadécimal, croyez-moi
Donc disais-je, pour assigner un registre à un autre, on doit spécifier le nom du registre cible avec un premier quartet, et le nom du registre source avec le deuxième quartet.
MAIS si c'était juste ça ça serait trop facile ! Ah ben non mais c'est pas marrant comme ça !
Donc en fait, le nom du registre source varie en fonction du registre cible. En Français compréhensible
, si on veut faire
- Code: Select all
ld a,b
b s'appellera pas de la même façon que si on fait
- Code: Select all
ld d,b
Alors là, alors là non mais c'est du sadisme ça !
Mais le PIRE, c'est qu'il y a des registres
cibles qui s'appellent
pareil ! Et là croyez-moi c'est vraiment le ouaï quand on se met à utiliser beaucoup de registres.
Pour commencer, les registres sources :
- A s'appelle 7. Heureusement, c'est le seul.
- B s'appelle 4
- C s'appelle 4 aussi
- D s'appelle 5
- E s'appelle aussi 5
- H s'appelle 6
- Devinez quoi ? L s'appelle 6
Mais alors vous allez me dire, comment lors d'une assignation différencier B et C ? D et E ? H et L ? Et ben [s]c'est simple[/s] non pas du tout en fait
: en fonction du registre source. Heureusement, vous n'avez que deux registres source à connaître :
- Si le registre cible est B,D ou H, A s'appelle 7. Sinon, si la cible est C,E ou L, A s'appelle F
- Si le registre cible est B (pour les autres registres), D ou H, B s'appelle 0. Sinon, si la cible est A, C, E ou L, B s'appelle 8
À partir de B, vous pouvez calculer C, D, E, H et L simplement en ajoutant $01.
ATTENTION : faites très attention au registre cible ! Je ne sais pas ce que ça va donner si pour assigner C à D vous faites- Code: Select all
59
au lieu de- Code: Select all
51
! Retenez absolument que si le registre cible est B, D ou H, il faut ajouter $01 à partir de $00 pour avoir les registres, mais si la cible est A, C, E ou L, c'est à partir de $08 !Vous êtes toujours vivants ?
Alors faisons un petit exercice pour que ça soit définitivement clair dans votre tête.
En hexadécimal, faites un programme complet (qu'on pourrait lancer sur la calto) qui assigne :
C'est sûr, il faut réfléchir un peu pour ne pas se tromper avec les relations entre registre cible et source, mais rien d'insurmontable.
ATTENTION : on écrit d'abord la cible et ensuite la source, comme pour la commande ld !Correction :
Show/Hide spoilerAfficher/Masquer le spoiler
J'avoue que c'est un peu hard à retenir au début, mais vous verrez, on s'y fait.
- Code: Select all
:AsmPrgm
:BB6D
:62
:79
:45
:6F
:C9
En fait, ce n'est pas par pur sadisme ou par haine contre les programmeurs qu'on utilise ce système. C'est parce qu'on a vu ici les registres
8 bits, et "bizarrement", vous voyez que les registres cibles vont 2 par 2 ... et que les sources s'étendent toujours sur 8 bits ... ah tiens
Et si on y regarde un peu plus près, sur A par exemple : selon la cible, il vaut 7 ou F ...
Mais attends $F - $7 = $8 !!!!Et oui, il y a une véritable raison à ce système. Chaque registre prend 8 bits, mais comme il n'y a aucun espace de mémoire libre, on est obligé de mettre deux registres 8 bits dans un seul emplacement 16 bits.
CQFD.
Les registres 16 bitsAvec les registres 16 bits, c'est très simple :
on fait pas . Ben oui carrément, on ne
peut pas stocker des registres (8 ou 16 bits) dans un registre 16 bits. Que des adresses, on verra ça [s]beaucoup[/s] plus tard.
Les romcallsLà c'est bon, j'ai trouvé tout ce qu'il fallait, ce sera un des rares chapitres complets ^^ Pour appeler une romcall en ASM, vous utilisiez :
- Code: Select all
bcall(xxxx)
Hé ben bonne nouvelle : en hexa c'est pareil ! On a juste à :
- Remplacer "bcall" par EF
- Enlever les parenthèses
- Inverser les octets de la romcall
Aaaaah ! Enfin un truc simple !
Donc récapitulons, sachant qu'en ASM pour effacer l'écran on fait :
- Code: Select all
bcall($4540)
En hexa on fait ..? Allez devinez !
Solution :
Show/Hide spoilerAfficher/Masquer le spoiler
- Code: Select all
:EF4045
Houlà c'est duuuur ! :]
Pour les romcalls qui utilisent des arguments, c'est comme en ASM : on a juste à assigner la bonne valeur au bon registre et appeler la romcall qui va l'utiliser paisiblement. Vous plaignez pas, pour une fois que y'a un truc facile ^^
Par contre il va y avoir un autre gros problème, c'est au niveau des romcalls, pour savoir où elles se situent, parce que je pense pas que ça vous éclate de retenir des adresses comme ça ^^
C'est pourquoi je vous conseille de télécharger le fichier include
ultimate.inc qui contient les adresses de tellement de trucs et de machins que vous allez faire un overflow si vous essayez de tous les compter :]
Et donc grâce à ce fichier, vous aurez toutes les adresses de n'importe quoi sous la main.
Après le C9 ...En ASM, y'a plein de trucs après le RET. Par exemple les .db ou les autres labels.
Ben en hexa c'est plus ou moins la même chose, on a l'instruction C9 puis encore tout plein de trucs.
Alors je ne vous parlerai ici que du cas de la chaîne de caractère parce que je connais que celui-là, donc m'en voulez pas trop hein
En ASM, pour rajouter une chaîne à un label vous mettiez un .db non ? Ben pas en hexa. En hexa pour les chaînes comme ça c'est l'anarchie totale, on écrit C9, on saute une ligne pour faire bô et on balance la chaîne comme ça sans rien. Chaîne bien sûr codée en hexa, à partir de A = 65 = $41 et on ajoute $1 pour monter d'une lettre dans l'alphabet.
- Code: Select all
:AsmPrgm
:BB6D
; programme
:
:C9
:414243444500
Le 00 de la fin est l'équivalent du "blabla"
,0 de l'ASM, donc pareil, ne l'oubliez jamais !
Je ne sais pas encore comment utiliser ces chaînes, mais promis je saurai bientôt !
Mini-TP surprise Parce que je pense vous avoir appris assez de trucs pour pouvoir les mettres en oeuvre, je vous demande maintenant de créer
votre premier programme entièrement hexadécimal ! Alors bien sûr rien de compliqué, je ne vous demanderai rien que je n'aurai expliqué.
ATTENTION : entrez toujours vos programmes sur un émulateur avant de les mettre sur la calto pour vous assurer qu'il n'y ait pas de dangers à les utiliser.
Je vais donc vous demander d'afficher 14 à l'écran (pas $14). Pour voir tout ça, on attendra la pression sur une touche avant de quitter.
Je ne vous demande pas de tout inventer, il y a les romcalls pour ça
Servez-vous d'ultimate.inc pour avoir leur adresse.
Allez hophop au boulot !
Indice :
Show/Hide spoilerAfficher/Masquer le spoiler
Il n'y a pas 36 manières d'afficher des chiffres : utilisez HL et la romcall DispHL ($4507). Cette romcall utilise DE comme coordonnées, mais comme il faut utiliser les adresses (pour curRow) laissez tomber les coordonnées pour l'instant. N'oubliez pas que la valeur de HL est en hexa, alors que celle affichée est en décimal !
Vous avez trouvé j'espère ?
Correction :
Show/Hide spoilerAfficher/Masquer le spoiler
La correction n'est pas réellement difficile :
- Code: Select all
:AsmPrgm
:BB6D
:210E00
:EF0745
:EF7249
:C9
210E00 stocke $000E dans HL (attention à l'inversion des octets).
EF0745 appelle DispHL ($4507) avec les coordonnées 0;0. Il va donc afficher $000E, soit 14.
EF7249 appelle getkey ($4972). Le programme va donc attendre qu'on appuie sur une touche.
C9 termine le programme.
C'est là qu'on voit la vraie puissance de l'hexadécimal : les programmes sont beaucoup plus courts et plus rapides que l'ASM, mais en contrepartie beaucoup moins compréhensibles.
Voilà, le tout tient en 6 lignes. D'accord, c'était un TOUT PETIT TP, mais ça vous aura au moins servi à vous familiariser avec la syntaxe "spéciale" de l'hexadécimal.
Voilà, j'ai dit tout ce que je savais. C'est vrai que c'est super galère à traduire comme à utiliser, l'hexa, mais ça reste rapide et surtout un challenge élevé que de faire un programme potable avec juste des chiffres ! L'hexadécimal est, je vous le rappelle, le voisin direct du binaire !
Sur ce, bonne continuation et à bientôt pour les updates !